Added more tests

This commit is contained in:
2025-03-13 16:02:09 +01:00
parent 5a5061c5d7
commit d96c351b4b
12 changed files with 205 additions and 39 deletions

View File

@ -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)
}

26
src/arm/Add_test.go Normal file
View File

@ -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)
}
}

8
src/arm/Compare.go Normal file
View File

@ -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)
}

25
src/arm/Compare_test.go Normal file
View File

@ -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)
}
}

View File

@ -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

68
src/arm/Jump_test.go Normal file
View File

@ -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)
}
}

View File

@ -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)
}

26
src/arm/Sub_test.go Normal file
View File

@ -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)
}
}

16
src/arm/encode.go Normal file
View File

@ -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
}

View File

@ -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")
}

View File

@ -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,
}

View File

@ -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))
}