Added more tests
This commit is contained in:
@ -4,6 +4,5 @@ import "git.urbach.dev/cli/q/src/cpu"
|
|||||||
|
|
||||||
// AddRegisterNumber adds a number to a register.
|
// AddRegisterNumber adds a number to a register.
|
||||||
func AddRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 {
|
func AddRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 {
|
||||||
number &= 0b1111_1111_1111
|
return encodeRegisterNumberFlags(0b10, destination, source, number, false)
|
||||||
return 0b100100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination)
|
|
||||||
}
|
}
|
||||||
|
26
src/arm/Add_test.go
Normal file
26
src/arm/Add_test.go
Normal 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
8
src/arm/Compare.go
Normal 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
25
src/arm/Compare_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -6,26 +6,6 @@ func Jump(offset int) uint32 {
|
|||||||
return 0b000101<<26 | uint32(offset)
|
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.
|
// JumpIfEqual jumps if the result was equal.
|
||||||
func JumpIfEqual(offset int) uint32 {
|
func JumpIfEqual(offset int) uint32 {
|
||||||
return branchCond(0b0000, offset)
|
return branchCond(0b0000, offset)
|
||||||
@ -36,6 +16,26 @@ func JumpIfNotEqual(offset int) uint32 {
|
|||||||
return branchCond(0b0001, offset)
|
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.
|
// branchCond performs a conditional branch to a PC-relative offset.
|
||||||
func branchCond(cond uint32, offset int) uint32 {
|
func branchCond(cond uint32, offset int) uint32 {
|
||||||
offset &= 0b111_1111_1111_1111_1111
|
offset &= 0b111_1111_1111_1111_1111
|
||||||
|
68
src/arm/Jump_test.go
Normal file
68
src/arm/Jump_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,5 @@ import "git.urbach.dev/cli/q/src/cpu"
|
|||||||
|
|
||||||
// SubRegisterNumber subtracts a number from the given register.
|
// SubRegisterNumber subtracts a number from the given register.
|
||||||
func SubRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 {
|
func SubRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 {
|
||||||
number &= 0b1111_1111_1111
|
return encodeRegisterNumberFlags(0b11, destination, source, number, false)
|
||||||
return 0b111100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination)
|
|
||||||
}
|
}
|
||||||
|
26
src/arm/Sub_test.go
Normal file
26
src/arm/Sub_test.go
Normal 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
16
src/arm/encode.go
Normal 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
|
||||||
|
}
|
@ -117,7 +117,7 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
switch x.Type {
|
switch x.Type {
|
||||||
case asm.TypeRegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
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:
|
case asm.TypeRegisterRegister:
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) jumpARM(x asm.Instruction) {
|
func (c *compiler) jumpARM(x asm.Instruction) {
|
||||||
|
label := c.assembler.Param.Label[x.Index]
|
||||||
mnemonic := x.Mnemonic
|
mnemonic := x.Mnemonic
|
||||||
position := Address(len(c.code))
|
position := Address(len(c.code))
|
||||||
label := c.assembler.Param.Label[x.Index]
|
|
||||||
|
|
||||||
pointer := &pointer{
|
pointer := &pointer{
|
||||||
Position: position,
|
Position: position,
|
||||||
OpSize: 0,
|
|
||||||
Size: 4,
|
Size: 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,14 +6,14 @@ func Jump8(code []byte, offset int8) []byte {
|
|||||||
return append(code, 0xEB, byte(offset))
|
return append(code, 0xEB, byte(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpIfLess jumps if the result was less.
|
// JumpIfEqual jumps if the result was equal.
|
||||||
func Jump8IfLess(code []byte, offset int8) []byte {
|
func Jump8IfEqual(code []byte, offset int8) []byte {
|
||||||
return append(code, 0x7C, byte(offset))
|
return append(code, 0x74, byte(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpIfLessOrEqual jumps if the result was less or equal.
|
// JumpIfNotEqual jumps if the result was not equal.
|
||||||
func Jump8IfLessOrEqual(code []byte, offset int8) []byte {
|
func Jump8IfNotEqual(code []byte, offset int8) []byte {
|
||||||
return append(code, 0x7E, byte(offset))
|
return append(code, 0x75, byte(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpIfGreater jumps if the result was greater.
|
// JumpIfGreater jumps if the result was greater.
|
||||||
@ -26,12 +26,12 @@ func Jump8IfGreaterOrEqual(code []byte, offset int8) []byte {
|
|||||||
return append(code, 0x7D, byte(offset))
|
return append(code, 0x7D, byte(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpIfEqual jumps if the result was equal.
|
// JumpIfLess jumps if the result was less.
|
||||||
func Jump8IfEqual(code []byte, offset int8) []byte {
|
func Jump8IfLess(code []byte, offset int8) []byte {
|
||||||
return append(code, 0x74, byte(offset))
|
return append(code, 0x7C, byte(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpIfNotEqual jumps if the result was not equal.
|
// JumpIfLessOrEqual jumps if the result was less or equal.
|
||||||
func Jump8IfNotEqual(code []byte, offset int8) []byte {
|
func Jump8IfLessOrEqual(code []byte, offset int8) []byte {
|
||||||
return append(code, 0x75, byte(offset))
|
return append(code, 0x7E, byte(offset))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user