From d96c351b4b81a09e68dd5a39e341bb48d12471d5 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 13 Mar 2025 16:02:09 +0100 Subject: [PATCH] Added more tests --- src/arm/Add.go | 3 +- src/arm/Add_test.go | 26 ++++++++++++++++ src/arm/Compare.go | 8 +++++ src/arm/Compare_test.go | 25 +++++++++++++++ src/arm/Jump.go | 40 ++++++++++++------------ src/arm/Jump_test.go | 68 +++++++++++++++++++++++++++++++++++++++++ src/arm/Sub.go | 3 +- src/arm/Sub_test.go | 26 ++++++++++++++++ src/arm/encode.go | 16 ++++++++++ src/asmc/compileARM.go | 2 +- src/asmc/jumpARM.go | 3 +- src/x86/Jump.go | 24 +++++++-------- 12 files changed, 205 insertions(+), 39 deletions(-) create mode 100644 src/arm/Add_test.go create mode 100644 src/arm/Compare.go create mode 100644 src/arm/Compare_test.go create mode 100644 src/arm/Jump_test.go create mode 100644 src/arm/Sub_test.go create mode 100644 src/arm/encode.go diff --git a/src/arm/Add.go b/src/arm/Add.go index c05e16e..dd868e9 100644 --- a/src/arm/Add.go +++ b/src/arm/Add.go @@ -4,6 +4,5 @@ import "git.urbach.dev/cli/q/src/cpu" // AddRegisterNumber adds a number to a register. func AddRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 { - number &= 0b1111_1111_1111 - return 0b100100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination) + return encodeRegisterNumberFlags(0b10, destination, source, number, false) } diff --git a/src/arm/Add_test.go b/src/arm/Add_test.go new file mode 100644 index 0000000..9b403b3 --- /dev/null +++ b/src/arm/Add_test.go @@ -0,0 +1,26 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/go/assert" +) + +func TestAddRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Source cpu.Register + Number int + Code uint32 + }{ + {arm.X0, arm.X0, 1, 0x91000400}, + } + + for _, pattern := range usagePatterns { + t.Logf("add %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) + code := arm.AddRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/Compare.go b/src/arm/Compare.go new file mode 100644 index 0000000..5fc07ec --- /dev/null +++ b/src/arm/Compare.go @@ -0,0 +1,8 @@ +package arm + +import "git.urbach.dev/cli/q/src/cpu" + +// CompareRegisterNumber is an alias for a subtraction that updates the conditional flags and discards the result. +func CompareRegisterNumber(register cpu.Register, number int) uint32 { + return encodeRegisterNumberFlags(0b11, 0b11111, register, number, true) +} diff --git a/src/arm/Compare_test.go b/src/arm/Compare_test.go new file mode 100644 index 0000000..7a3eca1 --- /dev/null +++ b/src/arm/Compare_test.go @@ -0,0 +1,25 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/go/assert" +) + +func TestCompareRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Source cpu.Register + Number int + Code uint32 + }{ + {arm.X0, 1, 0xF100041F}, + } + + for _, pattern := range usagePatterns { + t.Logf("cmp %s, %d", pattern.Source, pattern.Number) + code := arm.CompareRegisterNumber(pattern.Source, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/Jump.go b/src/arm/Jump.go index 78a75db..8f3f807 100644 --- a/src/arm/Jump.go +++ b/src/arm/Jump.go @@ -6,26 +6,6 @@ func Jump(offset int) uint32 { return 0b000101<<26 | uint32(offset) } -// JumpIfLess jumps if the result was less. -func JumpIfLess(offset int) uint32 { - return branchCond(0b1001, offset) -} - -// JumpIfLessOrEqual jumps if the result was less or equal. -func JumpIfLessOrEqual(offset int) uint32 { - return branchCond(0b1101, offset) -} - -// JumpIfGreater jumps if the result was greater. -func JumpIfGreater(offset int) uint32 { - return branchCond(0b1100, offset) -} - -// JumpIfGreaterOrEqual jumps if the result was greater or equal. -func JumpIfGreaterOrEqual(offset int) uint32 { - return branchCond(0b1010, offset) -} - // JumpIfEqual jumps if the result was equal. func JumpIfEqual(offset int) uint32 { return branchCond(0b0000, offset) @@ -36,6 +16,26 @@ func JumpIfNotEqual(offset int) uint32 { return branchCond(0b0001, offset) } +// JumpIfGreater jumps if the result was greater. +func JumpIfGreater(offset int) uint32 { + return branchCond(0b1100, offset) +} + +// JumpIfGreaterOrEqual jumps if the result was greater or equal. +func JumpIfGreaterOrEqual(offset int) uint32 { + return branchCond(0b1010, offset) +} + +// JumpIfLess jumps if the result was less. +func JumpIfLess(offset int) uint32 { + return branchCond(0b1001, offset) +} + +// JumpIfLessOrEqual jumps if the result was less or equal. +func JumpIfLessOrEqual(offset int) uint32 { + return branchCond(0b1101, offset) +} + // branchCond performs a conditional branch to a PC-relative offset. func branchCond(cond uint32, offset int) uint32 { offset &= 0b111_1111_1111_1111_1111 diff --git a/src/arm/Jump_test.go b/src/arm/Jump_test.go new file mode 100644 index 0000000..423c568 --- /dev/null +++ b/src/arm/Jump_test.go @@ -0,0 +1,68 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/go/assert" +) + +func TestJump(t *testing.T) { + usagePatterns := []struct { + Type byte + Offset int + Code uint32 + }{ + {0, 0, 0x14000000}, + {0, 1, 0x14000001}, + {0, -1, 0x17FFFFFF}, + + {1, 0, 0x54000000}, + {1, 1, 0x54000020}, + {1, -1, 0x54FFFFE0}, + + {2, 0, 0x54000001}, + {2, 1, 0x54000021}, + {2, -1, 0x54FFFFE1}, + + {3, 0, 0x5400000C}, + {3, 1, 0x5400002C}, + {3, -1, 0x54FFFFEC}, + + {4, 0, 0x5400000A}, + {4, 1, 0x5400002A}, + {4, -1, 0x54FFFFEA}, + + {5, 0, 0x54000009}, + {5, 1, 0x54000029}, + {5, -1, 0x54FFFFE9}, + + {6, 0, 0x5400000D}, + {6, 1, 0x5400002D}, + {6, -1, 0x54FFFFED}, + } + + for _, pattern := range usagePatterns { + t.Logf("b %d", pattern.Offset) + var code uint32 + + switch pattern.Type { + case 0: + code = arm.Jump(pattern.Offset) + case 1: + code = arm.JumpIfEqual(pattern.Offset) + case 2: + code = arm.JumpIfNotEqual(pattern.Offset) + case 3: + code = arm.JumpIfGreater(pattern.Offset) + case 4: + code = arm.JumpIfGreaterOrEqual(pattern.Offset) + case 5: + code = arm.JumpIfLess(pattern.Offset) + case 6: + code = arm.JumpIfLessOrEqual(pattern.Offset) + } + + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/Sub.go b/src/arm/Sub.go index 6d222e7..f468cea 100644 --- a/src/arm/Sub.go +++ b/src/arm/Sub.go @@ -4,6 +4,5 @@ import "git.urbach.dev/cli/q/src/cpu" // SubRegisterNumber subtracts a number from the given register. func SubRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 { - number &= 0b1111_1111_1111 - return 0b111100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination) + return encodeRegisterNumberFlags(0b11, destination, source, number, false) } diff --git a/src/arm/Sub_test.go b/src/arm/Sub_test.go new file mode 100644 index 0000000..d6cb4f6 --- /dev/null +++ b/src/arm/Sub_test.go @@ -0,0 +1,26 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/go/assert" +) + +func TestSubRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Source cpu.Register + Number int + Code uint32 + }{ + {arm.X0, arm.X0, 1, 0xD1000400}, + } + + for _, pattern := range usagePatterns { + t.Logf("sub %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) + code := arm.SubRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/encode.go b/src/arm/encode.go new file mode 100644 index 0000000..312cc37 --- /dev/null +++ b/src/arm/encode.go @@ -0,0 +1,16 @@ +package arm + +import "git.urbach.dev/cli/q/src/cpu" + +// encodeRegisterNumberFlags performs addition or subtraction on the given register +// and optionally updates the condition flags based on the result. +func encodeRegisterNumberFlags(op uint32, destination cpu.Register, source cpu.Register, number int, flags bool) uint32 { + number &= 0b1111_1111_1111 + common := op<<30 | 0b100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination) + + if flags { + return 1<<29 | common + } + + return common +} diff --git a/src/asmc/compileARM.go b/src/asmc/compileARM.go index 9de618b..77cfe02 100644 --- a/src/asmc/compileARM.go +++ b/src/asmc/compileARM.go @@ -117,7 +117,7 @@ func (c *compiler) compileARM(x asm.Instruction) { switch x.Type { case asm.TypeRegisterNumber: operand := c.assembler.Param.RegisterNumber[x.Index] - c.append(arm.SubRegisterNumber(0b11111, operand.Register, operand.Number)) + c.append(arm.CompareRegisterNumber(operand.Register, operand.Number)) case asm.TypeRegisterRegister: panic("not implemented") } diff --git a/src/asmc/jumpARM.go b/src/asmc/jumpARM.go index 6819262..81a96ee 100644 --- a/src/asmc/jumpARM.go +++ b/src/asmc/jumpARM.go @@ -8,13 +8,12 @@ import ( ) func (c *compiler) jumpARM(x asm.Instruction) { + label := c.assembler.Param.Label[x.Index] mnemonic := x.Mnemonic position := Address(len(c.code)) - label := c.assembler.Param.Label[x.Index] pointer := &pointer{ Position: position, - OpSize: 0, Size: 4, } diff --git a/src/x86/Jump.go b/src/x86/Jump.go index feed711..9baa597 100644 --- a/src/x86/Jump.go +++ b/src/x86/Jump.go @@ -6,14 +6,14 @@ func Jump8(code []byte, offset int8) []byte { return append(code, 0xEB, byte(offset)) } -// JumpIfLess jumps if the result was less. -func Jump8IfLess(code []byte, offset int8) []byte { - return append(code, 0x7C, byte(offset)) +// JumpIfEqual jumps if the result was equal. +func Jump8IfEqual(code []byte, offset int8) []byte { + return append(code, 0x74, byte(offset)) } -// JumpIfLessOrEqual jumps if the result was less or equal. -func Jump8IfLessOrEqual(code []byte, offset int8) []byte { - return append(code, 0x7E, byte(offset)) +// JumpIfNotEqual jumps if the result was not equal. +func Jump8IfNotEqual(code []byte, offset int8) []byte { + return append(code, 0x75, byte(offset)) } // JumpIfGreater jumps if the result was greater. @@ -26,12 +26,12 @@ func Jump8IfGreaterOrEqual(code []byte, offset int8) []byte { return append(code, 0x7D, byte(offset)) } -// JumpIfEqual jumps if the result was equal. -func Jump8IfEqual(code []byte, offset int8) []byte { - return append(code, 0x74, byte(offset)) +// JumpIfLess jumps if the result was less. +func Jump8IfLess(code []byte, offset int8) []byte { + return append(code, 0x7C, byte(offset)) } -// JumpIfNotEqual jumps if the result was not equal. -func Jump8IfNotEqual(code []byte, offset int8) []byte { - return append(code, 0x75, byte(offset)) +// JumpIfLessOrEqual jumps if the result was less or equal. +func Jump8IfLessOrEqual(code []byte, offset int8) []byte { + return append(code, 0x7E, byte(offset)) }