From df725a2b238a70b585884268a82d2c7ee93583e7 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 16 Apr 2025 17:38:48 +0200 Subject: [PATCH] Refactored arm package --- src/arm/Add_test.go | 4 ++-- src/arm/And_test.go | 4 ++-- src/arm/Call.go | 4 ++-- src/arm/Call_test.go | 25 +++++++++++++++++++++++++ src/arm/Compare_test.go | 4 ++-- src/arm/Div_test.go | 2 +- src/arm/Jump.go | 20 +++++++++----------- src/arm/Jump_test.go | 2 +- src/arm/LoadAddress_test.go | 2 +- src/arm/LoadPair_test.go | 2 +- src/arm/Load_test.go | 2 +- src/arm/Move_test.go | 8 ++++---- src/arm/Mul_test.go | 4 ++-- src/arm/Negate_test.go | 2 +- src/arm/Or_test.go | 4 ++-- src/arm/Shift_test.go | 4 ++-- src/arm/StorePair_test.go | 2 +- src/arm/Store_test.go | 2 +- src/arm/Sub_test.go | 4 ++-- src/arm/Xor_test.go | 4 ++-- src/arm/arm_test.go | 3 +-- src/arm/bitmask.go | 2 +- src/arm/condition.go | 22 ++++++++++++++++++++++ src/arm/encode.go | 8 -------- src/arm/mask.go | 11 +++++++++++ src/asmc/armCompiler.go | 4 +++- 26 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 src/arm/Call_test.go create mode 100644 src/arm/condition.go create mode 100644 src/arm/mask.go diff --git a/src/arm/Add_test.go b/src/arm/Add_test.go index d00d9f6..723580e 100644 --- a/src/arm/Add_test.go +++ b/src/arm/Add_test.go @@ -23,7 +23,7 @@ func TestAddRegisterNumber(t *testing.T) { t.Logf("add %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) code, encodable := arm.AddRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -40,6 +40,6 @@ func TestAddRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("add %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.AddRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/And_test.go b/src/arm/And_test.go index c8e6317..f5bb123 100644 --- a/src/arm/And_test.go +++ b/src/arm/And_test.go @@ -27,7 +27,7 @@ func TestAndRegisterNumber(t *testing.T) { t.Logf("and %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) code, encodable := arm.AndRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -44,6 +44,6 @@ func TestAndRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("and %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.AndRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Call.go b/src/arm/Call.go index 8c1901f..7e18522 100644 --- a/src/arm/Call.go +++ b/src/arm/Call.go @@ -3,6 +3,6 @@ package arm // Call branches to a PC-relative offset, setting the register X30 to PC+4. // The offset starts from the address of this instruction and is encoded as "imm26" times 4. // This instruction is also known as BL (branch with link). -func Call(offset uint32) uint32 { - return uint32(0b100101<<26) | offset +func Call(offset int) uint32 { + return uint32(0b100101<<26) | uint32(offset&mask26) } diff --git a/src/arm/Call_test.go b/src/arm/Call_test.go new file mode 100644 index 0000000..7000e8f --- /dev/null +++ b/src/arm/Call_test.go @@ -0,0 +1,25 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/go/assert" +) + +func TestCall(t *testing.T) { + usagePatterns := []struct { + Offset int + Code uint32 + }{ + {0, 0x94000000}, + {1, 0x94000001}, + {-1, 0x97FFFFFF}, + } + + for _, pattern := range usagePatterns { + t.Logf("bl %d", pattern.Offset) + code := arm.Call(pattern.Offset) + assert.Equal(t, code, pattern.Code) + } +} diff --git a/src/arm/Compare_test.go b/src/arm/Compare_test.go index 4ed047c..ab4abdb 100644 --- a/src/arm/Compare_test.go +++ b/src/arm/Compare_test.go @@ -24,7 +24,7 @@ func TestCompareRegisterNumber(t *testing.T) { t.Logf("cmp %s, %d", pattern.Source, pattern.Number) code, encodable := arm.CompareRegisterNumber(pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -40,6 +40,6 @@ func TestCompareRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("cmp %s, %s", pattern.Left, pattern.Right) code := arm.CompareRegisterRegister(pattern.Left, pattern.Right) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Div_test.go b/src/arm/Div_test.go index 81c3f03..5d3f281 100644 --- a/src/arm/Div_test.go +++ b/src/arm/Div_test.go @@ -21,6 +21,6 @@ func TestDivSigned(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("sdiv %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.DivSigned(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Jump.go b/src/arm/Jump.go index 8f3f807..a51eea9 100644 --- a/src/arm/Jump.go +++ b/src/arm/Jump.go @@ -2,42 +2,40 @@ package arm // Jump continues program flow at the new offset. func Jump(offset int) uint32 { - offset &= 0b11_1111_1111_1111_1111_1111_1111 - return 0b000101<<26 | uint32(offset) + return 0b000101<<26 | uint32(offset&mask26) } // JumpIfEqual jumps if the result was equal. func JumpIfEqual(offset int) uint32 { - return branchCond(0b0000, offset) + return branchCond(EQ, offset) } // JumpIfNotEqual jumps if the result was not equal. func JumpIfNotEqual(offset int) uint32 { - return branchCond(0b0001, offset) + return branchCond(NE, offset) } // JumpIfGreater jumps if the result was greater. func JumpIfGreater(offset int) uint32 { - return branchCond(0b1100, offset) + return branchCond(GT, offset) } // JumpIfGreaterOrEqual jumps if the result was greater or equal. func JumpIfGreaterOrEqual(offset int) uint32 { - return branchCond(0b1010, offset) + return branchCond(GE, offset) } // JumpIfLess jumps if the result was less. func JumpIfLess(offset int) uint32 { - return branchCond(0b1001, offset) + return branchCond(LS, offset) } // JumpIfLessOrEqual jumps if the result was less or equal. func JumpIfLessOrEqual(offset int) uint32 { - return branchCond(0b1101, offset) + return branchCond(LE, offset) } // branchCond performs a conditional branch to a PC-relative offset. -func branchCond(cond uint32, offset int) uint32 { - offset &= 0b111_1111_1111_1111_1111 - return 0b01010100<<24 | uint32(offset)<<5 | cond +func branchCond(cond condition, imm19 int) uint32 { + return 0b01010100<<24 | uint32(imm19&mask19)<<5 | uint32(cond) } diff --git a/src/arm/Jump_test.go b/src/arm/Jump_test.go index 423c568..651cdb0 100644 --- a/src/arm/Jump_test.go +++ b/src/arm/Jump_test.go @@ -63,6 +63,6 @@ func TestJump(t *testing.T) { code = arm.JumpIfLessOrEqual(pattern.Offset) } - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/LoadAddress_test.go b/src/arm/LoadAddress_test.go index 3b3c05f..332b842 100644 --- a/src/arm/LoadAddress_test.go +++ b/src/arm/LoadAddress_test.go @@ -21,6 +21,6 @@ func TestLoadAddress(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("adr %s, %d", pattern.Destination, pattern.Number) code := arm.LoadAddress(pattern.Destination, pattern.Number) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/LoadPair_test.go b/src/arm/LoadPair_test.go index 97edbdb..0cd0448 100644 --- a/src/arm/LoadPair_test.go +++ b/src/arm/LoadPair_test.go @@ -23,6 +23,6 @@ func TestLoadPair(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("ldp %s, %s, [%s], #%d", pattern.Reg1, pattern.Reg2, pattern.Base, pattern.Offset) code := arm.LoadPair(pattern.Reg1, pattern.Reg2, pattern.Base, pattern.Offset) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Load_test.go b/src/arm/Load_test.go index 43eaf28..b8294f2 100644 --- a/src/arm/Load_test.go +++ b/src/arm/Load_test.go @@ -34,6 +34,6 @@ func TestLoadRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("ldur %s, [%s, %d] %db", pattern.Destination, pattern.Base, pattern.Offset, pattern.Length) code := arm.LoadRegister(pattern.Destination, pattern.Base, pattern.Offset, pattern.Length) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Move_test.go b/src/arm/Move_test.go index acfb1a3..968cd1e 100644 --- a/src/arm/Move_test.go +++ b/src/arm/Move_test.go @@ -23,7 +23,7 @@ func TestMoveRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("mov %s, %s", pattern.Destination, pattern.Source) code := arm.MoveRegisterRegister(pattern.Destination, pattern.Source) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -79,7 +79,7 @@ func TestMoveRegisterNumberSI(t *testing.T) { if pattern.Code != 0 { assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } else { assert.False(t, encodable) } @@ -99,7 +99,7 @@ func TestMoveKeep(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("movk %s, %d", pattern.Register, pattern.Number) code := arm.MoveKeep(pattern.Register, 0, pattern.Number) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -116,6 +116,6 @@ func TestMoveZero(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("movz %s, %d", pattern.Register, pattern.Number) code := arm.MoveZero(pattern.Register, 0, pattern.Number) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Mul_test.go b/src/arm/Mul_test.go index c59325e..3d9f5ca 100644 --- a/src/arm/Mul_test.go +++ b/src/arm/Mul_test.go @@ -21,7 +21,7 @@ func TestMulRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("mul %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.MulRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -40,6 +40,6 @@ func TestMultiplySubtract(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("msub %s, %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand, pattern.Extra) code := arm.MultiplySubtract(pattern.Destination, pattern.Source, pattern.Operand, pattern.Extra) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Negate_test.go b/src/arm/Negate_test.go index 65f3809..b5f385c 100644 --- a/src/arm/Negate_test.go +++ b/src/arm/Negate_test.go @@ -21,6 +21,6 @@ func TestNegateRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("neg %s, %s", pattern.Destination, pattern.Source) code := arm.NegateRegister(pattern.Destination, pattern.Source) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Or_test.go b/src/arm/Or_test.go index 0d7aee9..98e6e8a 100644 --- a/src/arm/Or_test.go +++ b/src/arm/Or_test.go @@ -27,7 +27,7 @@ func TestOrRegisterNumber(t *testing.T) { t.Logf("orr %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) code, encodable := arm.OrRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -44,6 +44,6 @@ func TestOrRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("orr %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.OrRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Shift_test.go b/src/arm/Shift_test.go index 8aa96d2..556e349 100644 --- a/src/arm/Shift_test.go +++ b/src/arm/Shift_test.go @@ -26,7 +26,7 @@ func TestShiftLeftNumber(t *testing.T) { t.Logf("%b", pattern.Code) t.Logf("lsl %s, %s, %x", pattern.Destination, pattern.Source, pattern.Bits) code := arm.ShiftLeftNumber(pattern.Destination, pattern.Source, pattern.Bits) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -47,6 +47,6 @@ func TestShiftRightSignedNumber(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("asr %s, %s, %x", pattern.Destination, pattern.Source, pattern.Bits) code := arm.ShiftRightSignedNumber(pattern.Destination, pattern.Source, pattern.Bits) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/StorePair_test.go b/src/arm/StorePair_test.go index eefdfbd..beca1bb 100644 --- a/src/arm/StorePair_test.go +++ b/src/arm/StorePair_test.go @@ -23,6 +23,6 @@ func TestStorePair(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("stp %s, %s, [%s, #%d]!", pattern.Reg1, pattern.Reg2, pattern.Base, pattern.Offset) code := arm.StorePair(pattern.Reg1, pattern.Reg2, pattern.Base, pattern.Offset) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Store_test.go b/src/arm/Store_test.go index 9f4150d..b83ebc6 100644 --- a/src/arm/Store_test.go +++ b/src/arm/Store_test.go @@ -29,6 +29,6 @@ func TestStoreRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("stur %s, [%s, #%d] %db", pattern.Source, pattern.Base, pattern.Offset, pattern.Length) code := arm.StoreRegister(pattern.Source, pattern.Base, pattern.Offset, pattern.Length) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Sub_test.go b/src/arm/Sub_test.go index 2256704..0770b6a 100644 --- a/src/arm/Sub_test.go +++ b/src/arm/Sub_test.go @@ -24,7 +24,7 @@ func TestSubRegisterNumber(t *testing.T) { t.Logf("sub %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) code, encodable := arm.SubRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -41,6 +41,6 @@ func TestSubRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("sub %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.SubRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/Xor_test.go b/src/arm/Xor_test.go index c8f3dc5..aec2b42 100644 --- a/src/arm/Xor_test.go +++ b/src/arm/Xor_test.go @@ -27,7 +27,7 @@ func TestXorRegisterNumber(t *testing.T) { t.Logf("eor %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) code, encodable := arm.XorRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) assert.True(t, encodable) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } @@ -44,6 +44,6 @@ func TestXorRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("eor %s, %s, %s", pattern.Destination, pattern.Source, pattern.Operand) code := arm.XorRegisterRegister(pattern.Destination, pattern.Source, pattern.Operand) - assert.DeepEqual(t, code, pattern.Code) + assert.Equal(t, code, pattern.Code) } } diff --git a/src/arm/arm_test.go b/src/arm/arm_test.go index 9a6693f..12c6a4c 100644 --- a/src/arm/arm_test.go +++ b/src/arm/arm_test.go @@ -7,8 +7,7 @@ import ( "git.urbach.dev/go/assert" ) -func TestGeneral(t *testing.T) { - assert.DeepEqual(t, arm.Call(0), 0x94000000) +func TestConstants(t *testing.T) { assert.DeepEqual(t, arm.Nop(), 0xD503201F) assert.DeepEqual(t, arm.Return(), 0xD65F03C0) assert.DeepEqual(t, arm.Syscall(), 0xD4000001) diff --git a/src/arm/bitmask.go b/src/arm/bitmask.go index 19a65f8..ecf487d 100644 --- a/src/arm/bitmask.go +++ b/src/arm/bitmask.go @@ -24,7 +24,7 @@ func encodeLogicalImmediate(val uint) (N int, immr int, imms int, encodable bool return 0, 0, 0, false } - return N, immr, (imms & 0x3f), true + return N, immr, (imms & 0x3F), true } // clearTrailingOnes clears trailing one bits. diff --git a/src/arm/condition.go b/src/arm/condition.go new file mode 100644 index 0000000..a959c1a --- /dev/null +++ b/src/arm/condition.go @@ -0,0 +1,22 @@ +package arm + +type condition uint8 + +const ( + EQ condition = iota + NE + CS + CC + MI + PL + VS + VC + HI + LS + GE + LT + GT + LE + AL + NV +) diff --git a/src/arm/encode.go b/src/arm/encode.go index 0b9d45c..89ec099 100644 --- a/src/arm/encode.go +++ b/src/arm/encode.go @@ -4,14 +4,6 @@ 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&mask9)<<12 | uint32(base)<<5 | uint32(destination) diff --git a/src/arm/mask.go b/src/arm/mask.go new file mode 100644 index 0000000..b1bb519 --- /dev/null +++ b/src/arm/mask.go @@ -0,0 +1,11 @@ +package arm + +const ( + mask6 = 0b111111 + mask7 = 0b1111111 + mask9 = 0b1_11111111 + mask12 = 0b1111_11111111 + mask16 = 0b11111111_11111111 + mask19 = 0b111_11111111_11111111 + mask26 = 0b11_11111111_11111111_11111111 +) diff --git a/src/asmc/armCompiler.go b/src/asmc/armCompiler.go index 6c11240..0ce0434 100644 --- a/src/asmc/armCompiler.go +++ b/src/asmc/armCompiler.go @@ -100,10 +100,12 @@ func (c *armCompiler) handleCallInstruction(instruction asm.Instruction) { pointer.Resolve = func() Address { destination, exists := c.codeLabels[label.Name] + if !exists { panic(fmt.Sprintf("unknown jump label %s", label.Name)) } - distance := (destination - position) / 4 + + distance := int(destination-position) / 4 return arm.Call(distance) }