diff --git a/src/arm/Move.go b/src/arm/Move.go index 2399d92..5cbc4c9 100644 --- a/src/arm/Move.go +++ b/src/arm/Move.go @@ -15,9 +15,18 @@ func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 // MoveRegisterNumber moves an integer into the given register. func MoveRegisterNumber(destination cpu.Register, number int) uint32 { + if number < 0 { + return MoveInvertedWideImmediate(destination, ^number) + } + return MoveZero(destination, 0, uint16(number)) } +// MoveInvertedWideImmediate moves an inverted 16-bit immediate value to a register. +func MoveInvertedWideImmediate(destination cpu.Register, number int) uint32 { + return 0b100100101<<23 | regImm(destination, number) +} + // MoveKeep moves a 16-bit integer into the given register and keeps all other bits. func MoveKeep(destination cpu.Register, halfword int, number uint16) uint32 { return mov(0b11, halfword, number, destination) diff --git a/src/arm/Move_test.go b/src/arm/Move_test.go index 69f524e..ba8e5cc 100644 --- a/src/arm/Move_test.go +++ b/src/arm/Move_test.go @@ -27,6 +27,24 @@ func TestMoveRegisterRegister(t *testing.T) { } } +func TestMoveRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code uint32 + }{ + {arm.X0, 0, 0xD2800000}, + {arm.X0, 1, 0xD2800020}, + {arm.X0, -1, 0x92800000}, + } + + for _, pattern := range usagePatterns { + t.Logf("mov %s, %d", pattern.Register, pattern.Number) + code := arm.MoveRegisterNumber(pattern.Register, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} + func TestMoveKeep(t *testing.T) { usagePatterns := []struct { Register cpu.Register @@ -38,7 +56,7 @@ func TestMoveKeep(t *testing.T) { } for _, pattern := range usagePatterns { - t.Logf("movk %s, %x", pattern.Register, pattern.Number) + t.Logf("movk %s, %d", pattern.Register, pattern.Number) code := arm.MoveKeep(pattern.Register, 0, pattern.Number) assert.DeepEqual(t, code, pattern.Code) } @@ -55,7 +73,7 @@ func TestMoveZero(t *testing.T) { } for _, pattern := range usagePatterns { - t.Logf("movz %s, %x", pattern.Register, pattern.Number) + t.Logf("movz %s, %d", pattern.Register, pattern.Number) code := arm.MoveZero(pattern.Register, 0, pattern.Number) assert.DeepEqual(t, code, pattern.Code) } diff --git a/src/arm/encode.go b/src/arm/encode.go index 38f968d..bab6330 100644 --- a/src/arm/encode.go +++ b/src/arm/encode.go @@ -2,19 +2,32 @@ package arm import "git.urbach.dev/cli/q/src/cpu" +const ( + mask6 = 0b111111 + mask7 = 0b1111111 + mask9 = 0b1_11111111 + mask12 = 0b1111_11111111 + mask16 = 0b11111111_11111111 +) + // memory encodes an instruction with a register, a base register and an offset. func memory(destination cpu.Register, base cpu.Register, imm9 int) uint32 { - return uint32(imm9&0b1_1111_1111)<<12 | uint32(base)<<5 | uint32(destination) + return uint32(imm9&mask9)<<12 | uint32(base)<<5 | uint32(destination) } // pair encodes an instruction using a register pair with memory. func pair(reg1 cpu.Register, reg2 cpu.Register, base cpu.Register, imm7 int) uint32 { - return uint32(imm7&0b111_1111)<<15 | uint32(reg2)<<10 | uint32(base)<<5 | uint32(reg1) + return uint32(imm7&mask7)<<15 | uint32(reg2)<<10 | uint32(base)<<5 | uint32(reg1) +} + +// regImm encodes an instruction with a register and an immediate. +func regImm(d cpu.Register, imm16 int) uint32 { + return uint32(imm16&mask16)<<5 | uint32(d) } // reg2imm encodes an instruction with 2 registers and an immediate. func reg2imm(d cpu.Register, n cpu.Register, imm12 int) uint32 { - return uint32(imm12&0b1111_1111_1111)<<10 | uint32(n)<<5 | uint32(d) + return uint32(imm12&mask12)<<10 | uint32(n)<<5 | uint32(d) } // reg3 encodes an instruction with 3 registers.