diff --git a/internal/commands/shiftl.go b/internal/commands/shiftl.go index 85c6a21..5ed6ca5 100644 --- a/internal/commands/shiftl.go +++ b/internal/commands/shiftl.go @@ -251,15 +251,36 @@ func (c *ShiftLCommand) generateByteCopy() []string { func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string { var asm []string - // Copy source to destination if needed - copyAsm := c.generateByteCopy() - asm = append(asm, copyAsm...) - - // Apply shift - for i := uint16(0); i < amount; i++ { - asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName)) + // Check if same variable + if c.sourceIsVar && c.sourceVarName == c.destVarName { + // Same variable: load to accumulator, shift, store back (faster) + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + // Shift in accumulator (faster: 2 cycles vs 5 for memory) + for i := uint16(0); i < amount; i++ { + asm = append(asm, "\tasl") + } + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + return asm } + // Different variables or literal source: shift in accumulator + if c.sourceIsVar { + // Variable source + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + } else { + // Literal source + val := uint8(c.sourceValue & 0xFF) + asm = append(asm, fmt.Sprintf("\tlda #$%02x", val)) + } + + // Shift in accumulator (faster: 2 cycles vs 5 for memory) + for i := uint16(0); i < amount; i++ { + asm = append(asm, "\tasl") + } + + // Store result + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + return asm } @@ -267,24 +288,61 @@ func (c *ShiftLCommand) generateByteShiftConst(amount uint16) []string { func (c *ShiftLCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) { var asm []string - // Copy source to destination if needed - copyAsm := c.generateByteCopy() - asm = append(asm, copyAsm...) + // Check if same variable + if c.sourceIsVar && c.sourceVarName == c.destVarName { + // Same variable: load to accumulator, shift loop, store back (faster) + // Generate labels + loopLabel := ctx.GeneralStack.Push() + ctx.GeneralStack.Pop() + doneLabel := ctx.GeneralStack.Push() + ctx.GeneralStack.Pop() + + // Load value to accumulator + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + + // Variable shift loop (in accumulator, 2 cycles vs 5 for memory) + asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName)) + asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel)) + asm = append(asm, loopLabel) + asm = append(asm, "\tasl") + asm = append(asm, "\tdex") + asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel)) + asm = append(asm, doneLabel) + + // Store result back + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + + return asm, nil + } + // Different variables or literal: shift in accumulator (faster) // Generate labels loopLabel := ctx.GeneralStack.Push() ctx.GeneralStack.Pop() doneLabel := ctx.GeneralStack.Push() ctx.GeneralStack.Pop() - // Variable shift loop + // Load source to accumulator + if c.sourceIsVar { + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + } else { + val := uint8(c.sourceValue & 0xFF) + asm = append(asm, fmt.Sprintf("\tlda #$%02x", val)) + } + + // Load shift amount to X asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName)) asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel)) + + // Shift loop (in accumulator, 2 cycles vs 5 for memory) asm = append(asm, loopLabel) - asm = append(asm, fmt.Sprintf("\tasl %s", c.destVarName)) + asm = append(asm, "\tasl") asm = append(asm, "\tdex") asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel)) + + // Store result asm = append(asm, doneLabel) + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) return asm, nil } diff --git a/internal/commands/shiftl_test.go b/internal/commands/shiftl_test.go index 8248069..7704036 100644 --- a/internal/commands/shiftl_test.go +++ b/internal/commands/shiftl_test.go @@ -366,10 +366,10 @@ func TestShiftLCommand_Generate(t *testing.T) { }, wantLines: []string{ "\tlda #$01", + "\tasl", + "\tasl", + "\tasl", "\tsta result", - "\tasl result", - "\tasl result", - "\tasl result", }, }, { @@ -450,14 +450,14 @@ func TestShiftLCommand_Generate(t *testing.T) { }, wantLines: []string{ "\tlda value", - "\tsta result", "\tldx shift", "\tbeq _L2", "_L1", - "\tasl result", + "\tasl", "\tdex", "\tbne _L1", "_L2", + "\tsta result", }, }, { @@ -509,13 +509,15 @@ func TestShiftLCommand_Generate(t *testing.T) { } }, wantLines: []string{ + "\tlda value", "\tldx shift", "\tbeq _L2", "_L1", - "\tasl value", + "\tasl", "\tdex", "\tbne _L1", "_L2", + "\tsta value", }, }, { @@ -609,11 +611,11 @@ func TestShiftLCommand_Generate(t *testing.T) { }, wantLines: []string{ "\tlda wordval", + "\tasl", + "\tasl", + "\tasl", + "\tasl", "\tsta result", - "\tasl result", - "\tasl result", - "\tasl result", - "\tasl result", }, }, { diff --git a/internal/commands/shiftr.go b/internal/commands/shiftr.go index f366fc9..f62770c 100644 --- a/internal/commands/shiftr.go +++ b/internal/commands/shiftr.go @@ -263,15 +263,36 @@ func (c *ShiftRCommand) generateByteCopy() []string { func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string { var asm []string - // Copy source to destination if needed - copyAsm := c.generateByteCopy() - asm = append(asm, copyAsm...) - - // Apply shift (right shift uses LSR) - for i := uint16(0); i < amount; i++ { - asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName)) + // Check if same variable + if c.sourceIsVar && c.sourceVarName == c.destVarName { + // Same variable: load to accumulator, shift, store back (faster) + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + // Shift in accumulator (faster: 2 cycles vs 5 for memory) + for i := uint16(0); i < amount; i++ { + asm = append(asm, "\tlsr") + } + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + return asm } + // Different variables or literal source: shift in accumulator + if c.sourceIsVar { + // Variable source + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + } else { + // Literal source + val := uint8(c.sourceValue & 0xFF) + asm = append(asm, fmt.Sprintf("\tlda #$%02x", val)) + } + + // Shift in accumulator (faster: 2 cycles vs 5 for memory) + for i := uint16(0); i < amount; i++ { + asm = append(asm, "\tlsr") + } + + // Store result + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + return asm } @@ -279,24 +300,61 @@ func (c *ShiftRCommand) generateByteShiftConst(amount uint16) []string { func (c *ShiftRCommand) generateByteShiftVar(ctx *compiler.CompilerContext) ([]string, error) { var asm []string - // Copy source to destination if needed - copyAsm := c.generateByteCopy() - asm = append(asm, copyAsm...) + // Check if same variable + if c.sourceIsVar && c.sourceVarName == c.destVarName { + // Same variable: load to accumulator, shift loop, store back (faster) + // Generate labels + loopLabel := ctx.GeneralStack.Push() + ctx.GeneralStack.Pop() + doneLabel := ctx.GeneralStack.Push() + ctx.GeneralStack.Pop() + + // Load value to accumulator + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + + // Variable shift loop (in accumulator, 2 cycles vs 5 for memory) + asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName)) + asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel)) + asm = append(asm, loopLabel) + asm = append(asm, "\tlsr") + asm = append(asm, "\tdex") + asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel)) + asm = append(asm, doneLabel) + + // Store result back + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) + + return asm, nil + } + // Different variables or literal: shift in accumulator (faster) // Generate labels loopLabel := ctx.GeneralStack.Push() ctx.GeneralStack.Pop() doneLabel := ctx.GeneralStack.Push() ctx.GeneralStack.Pop() - // Variable shift loop (right shift uses LSR) + // Load source to accumulator + if c.sourceIsVar { + asm = append(asm, fmt.Sprintf("\tlda %s", c.sourceVarName)) + } else { + val := uint8(c.sourceValue & 0xFF) + asm = append(asm, fmt.Sprintf("\tlda #$%02x", val)) + } + + // Load shift amount to X asm = append(asm, fmt.Sprintf("\tldx %s", c.amountVarName)) asm = append(asm, fmt.Sprintf("\tbeq %s", doneLabel)) + + // Shift loop (in accumulator, 2 cycles vs 5 for memory) asm = append(asm, loopLabel) - asm = append(asm, fmt.Sprintf("\tlsr %s", c.destVarName)) + asm = append(asm, "\tlsr") asm = append(asm, "\tdex") asm = append(asm, fmt.Sprintf("\tbne %s", loopLabel)) + + // Store result asm = append(asm, doneLabel) + asm = append(asm, fmt.Sprintf("\tsta %s", c.destVarName)) return asm, nil } diff --git a/internal/commands/shiftr_test.go b/internal/commands/shiftr_test.go index 15a59d0..9e3bb44 100644 --- a/internal/commands/shiftr_test.go +++ b/internal/commands/shiftr_test.go @@ -366,10 +366,10 @@ func TestShiftRCommand_Generate(t *testing.T) { }, wantLines: []string{ "\tlda #$08", + "\tlsr", + "\tlsr", + "\tlsr", "\tsta result", - "\tlsr result", - "\tlsr result", - "\tlsr result", }, }, { @@ -450,14 +450,14 @@ func TestShiftRCommand_Generate(t *testing.T) { }, wantLines: []string{ "\tlda value", - "\tsta result", "\tldx shift", "\tbeq _L2", "_L1", - "\tlsr result", + "\tlsr", "\tdex", "\tbne _L1", "_L2", + "\tsta result", }, }, { @@ -509,13 +509,15 @@ func TestShiftRCommand_Generate(t *testing.T) { } }, wantLines: []string{ + "\tlda value", "\tldx shift", "\tbeq _L2", "_L1", - "\tlsr value", + "\tlsr", "\tdex", "\tbne _L1", "_L2", + "\tsta value", }, }, {