diff --git a/src/arm/Add.go b/src/arm/Add.go index 3ae49e3..ba641a0 100644 --- a/src/arm/Add.go +++ b/src/arm/Add.go @@ -14,7 +14,22 @@ func AddRegisterRegister(destination cpu.Register, source cpu.Register, operand // addRegisterNumber adds the register and optionally updates the condition flags based on the result. func addRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) uint32 { - return flags<<29 | 0b100100010<<23 | reg2Imm(destination, source, number) + shift := uint32(0) + + if number > mask12 { + if number&mask12 != 0 { + panic("number can't be encoded") + } + + shift = 1 + number >>= 12 + + if number > mask12 { + panic("number can't be encoded") + } + } + + return flags<<29 | 0b100100010<<23 | shift<<22 | reg2Imm(destination, source, number) } // addRegisterRegister adds the registers and optionally updates the condition flags based on the result. diff --git a/src/arm/Add_test.go b/src/arm/Add_test.go index 1051b06..3c75ecc 100644 --- a/src/arm/Add_test.go +++ b/src/arm/Add_test.go @@ -16,6 +16,7 @@ func TestAddRegisterNumber(t *testing.T) { Code uint32 }{ {arm.X0, arm.X0, 1, 0x91000400}, + {arm.X0, arm.X0, 0x1000, 0x91400400}, } for _, pattern := range usagePatterns { diff --git a/src/arm/Compare_test.go b/src/arm/Compare_test.go index 8224614..4580aea 100644 --- a/src/arm/Compare_test.go +++ b/src/arm/Compare_test.go @@ -14,8 +14,10 @@ func TestCompareRegisterNumber(t *testing.T) { Number int Code uint32 }{ + {arm.X0, 0, 0xF100001F}, {arm.X0, 1, 0xF100041F}, {arm.X0, -1, 0xB100041F}, + {arm.X0, 0x1000, 0xF140041F}, } for _, pattern := range usagePatterns { diff --git a/src/arm/Move.go b/src/arm/Move.go index a0fc070..d5851ec 100644 --- a/src/arm/Move.go +++ b/src/arm/Move.go @@ -41,28 +41,28 @@ func MoveRegisterNumberMI(code []byte, destination cpu.Register, number int) []b func MoveRegisterNumberSI(destination cpu.Register, number int) (uint32, bool) { if sizeof.Signed(number) <= 2 { if number < 0 { - return MoveInvertedWideImmediate(destination, uint16(^number), 0), true + return MoveInvertedNumber(destination, uint16(^number), 0), true } return MoveZero(destination, 0, uint16(number)), true } if (number&0xFFFFFFFFFFFF == 0xFFFFFFFFFFFF) && sizeof.Signed(number>>48) <= 2 { - return MoveInvertedWideImmediate(destination, uint16((^number)>>48), 3), true + return MoveInvertedNumber(destination, uint16((^number)>>48), 3), true } - code, encodable := MoveBitmaskImmediate(destination, number) + code, encodable := MoveBitmaskNumber(destination, number) if encodable { return code, true } if (number&0xFFFFFFFF == 0xFFFFFFFF) && sizeof.Signed(number>>32) <= 2 { - return MoveInvertedWideImmediate(destination, uint16((^number)>>32), 2), true + return MoveInvertedNumber(destination, uint16((^number)>>32), 2), true } if (number&0xFFFF == 0xFFFF) && sizeof.Signed(number>>16) <= 2 { - return MoveInvertedWideImmediate(destination, uint16((^number)>>16), 1), true + return MoveInvertedNumber(destination, uint16((^number)>>16), 1), true } return 0, false @@ -77,13 +77,13 @@ func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 return OrRegisterRegister(destination, ZR, source) } -// MoveBitmaskImmediate moves a bitmask immediate value to a register. -func MoveBitmaskImmediate(destination cpu.Register, number int) (uint32, bool) { +// MoveBitmaskNumber moves a bitmask immediate value to a register. +func MoveBitmaskNumber(destination cpu.Register, number int) (uint32, bool) { return OrRegisterNumber(destination, ZR, number) } -// MoveInvertedWideImmediate moves an inverted 16-bit immediate value to a register. -func MoveInvertedWideImmediate(destination cpu.Register, number uint16, shift uint32) uint32 { +// MoveInvertedNumber moves an inverted 16-bit immediate value to a register. +func MoveInvertedNumber(destination cpu.Register, number uint16, shift uint32) uint32 { return 0b100100101<<23 | shift<<21 | regImm(destination, number) } diff --git a/src/arm/Move_test.go b/src/arm/Move_test.go index af4c58e..acfb1a3 100644 --- a/src/arm/Move_test.go +++ b/src/arm/Move_test.go @@ -33,6 +33,7 @@ func TestMoveRegisterNumber(t *testing.T) { Number uint64 Code []byte }{ + {arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xD2}}, {arm.X0, 0xCAFEBABE, []byte{0xC0, 0x57, 0x97, 0xD2, 0xC0, 0x5F, 0xB9, 0xF2}}, {arm.X0, 0xDEADC0DE, []byte{0xC0, 0x1B, 0x98, 0xD2, 0xA0, 0xD5, 0xBB, 0xF2}}, } @@ -51,8 +52,9 @@ func TestMoveRegisterNumberSI(t *testing.T) { Code uint32 }{ // MOVZ - {arm.X0, 0, 0xD2800000}, - {arm.X0, 1, 0xD2800020}, + {arm.X0, 0x0, 0xD2800000}, + {arm.X0, 0x1, 0xD2800020}, + {arm.X0, 0x1000, 0xD2820000}, // MOV (bitmask immediate) {arm.X0, 0x1FFFF, 0xB24043E0}, diff --git a/src/arm/Sub.go b/src/arm/Sub.go index ef2377f..37d0a9e 100644 --- a/src/arm/Sub.go +++ b/src/arm/Sub.go @@ -14,7 +14,22 @@ func SubRegisterRegister(destination cpu.Register, source cpu.Register, operand // subRegisterNumber subtracts the register and optionally updates the condition flags based on the result. func subRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) uint32 { - return flags<<29 | 0b110100010<<23 | reg2Imm(destination, source, number) + shift := uint32(0) + + if number > mask12 { + if number&mask12 != 0 { + panic("number can't be encoded") + } + + shift = 1 + number >>= 12 + + if number > mask12 { + panic("number can't be encoded") + } + } + + return flags<<29 | 0b110100010<<23 | shift<<22 | reg2Imm(destination, source, number) } // subRegisterRegister subtracts the registers and optionally updates the condition flags based on the result. diff --git a/src/arm/Sub_test.go b/src/arm/Sub_test.go index dc42615..e508c75 100644 --- a/src/arm/Sub_test.go +++ b/src/arm/Sub_test.go @@ -16,6 +16,7 @@ func TestSubRegisterNumber(t *testing.T) { Code uint32 }{ {arm.X0, arm.X0, 1, 0xD1000400}, + {arm.X0, arm.X0, 0x1000, 0xD1400400}, {arm.SP, arm.SP, 16, 0xD10043FF}, }