Implemented arm64 instructions: ldp and stp
This commit is contained in:
9
src/arm/Add.go
Normal file
9
src/arm/Add.go
Normal file
@ -0,0 +1,9 @@
|
||||
package arm
|
||||
|
||||
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 &= 0xFFF
|
||||
return 0b100100010<<23 | (uint32(number) << 10) | (uint32(source) << 5) | uint32(destination)
|
||||
}
|
12
src/arm/LoadPair.go
Normal file
12
src/arm/LoadPair.go
Normal file
@ -0,0 +1,12 @@
|
||||
package arm
|
||||
|
||||
import "git.urbach.dev/cli/q/src/cpu"
|
||||
|
||||
// LoadPair calculates an address from a base register value and an immediate offset,
|
||||
// loads two 64-bit doublewords from memory, and writes them to two registers.
|
||||
// This is the post-index version of the instruction so the offset is applied to the base register after the memory access.
|
||||
func LoadPair(reg1 cpu.Register, reg2 cpu.Register, base cpu.Register, offset int) uint32 {
|
||||
offset /= 8
|
||||
offset &= 0b1111111
|
||||
return 0b1010100011<<22 | (uint32(offset) << 15) | (uint32(reg2) << 10) | (uint32(base) << 5) | uint32(reg1)
|
||||
}
|
28
src/arm/LoadPair_test.go
Normal file
28
src/arm/LoadPair_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
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 TestLoadPair(t *testing.T) {
|
||||
usagePatterns := []struct {
|
||||
Reg1 cpu.Register
|
||||
Reg2 cpu.Register
|
||||
Base cpu.Register
|
||||
Offset int
|
||||
Code uint32
|
||||
}{
|
||||
{arm.FP, arm.LR, arm.SP, 32, 0xA8C27BFD},
|
||||
{arm.FP, arm.LR, arm.SP, 16, 0xA8C17BFD},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ import (
|
||||
|
||||
// MoveRegisterRegister copies a register to another register.
|
||||
func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 {
|
||||
if source == SP || destination == SP {
|
||||
return AddRegisterNumber(destination, source, 0)
|
||||
}
|
||||
|
||||
return 0b10101010<<24 | uint32(source)<<16 | 0b11111<<5 | uint32(destination)
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ func TestMoveRegisterRegister(t *testing.T) {
|
||||
}{
|
||||
{arm.X0, arm.X1, 0xAA0103E0},
|
||||
{arm.X1, arm.X0, 0xAA0003E1},
|
||||
{arm.FP, arm.SP, 0x910003FD},
|
||||
{arm.SP, arm.FP, 0x910003BF},
|
||||
}
|
||||
|
||||
for _, pattern := range usagePatterns {
|
||||
|
14
src/arm/StorePair.go
Normal file
14
src/arm/StorePair.go
Normal file
@ -0,0 +1,14 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
)
|
||||
|
||||
// StorePair calculates an address from a base register value and an immediate offset multiplied by 8,
|
||||
// and stores the values of two registers to the calculated address.
|
||||
// This is the pre-index version of the instruction so the offset is applied to the base register before the memory access.
|
||||
func StorePair(reg1 cpu.Register, reg2 cpu.Register, base cpu.Register, offset int) uint32 {
|
||||
offset /= 8
|
||||
offset &= 0b1111111
|
||||
return 0b1010100110<<22 | uint32(offset)<<15 | uint32(reg2)<<10 | uint32(base)<<5 | uint32(reg1)
|
||||
}
|
28
src/arm/StorePair_test.go
Normal file
28
src/arm/StorePair_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
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 TestStorePair(t *testing.T) {
|
||||
usagePatterns := []struct {
|
||||
Reg1 cpu.Register
|
||||
Reg2 cpu.Register
|
||||
Base cpu.Register
|
||||
Offset int
|
||||
Code uint32
|
||||
}{
|
||||
{arm.FP, arm.LR, arm.SP, -32, 0xA9BE7BFD},
|
||||
{arm.FP, arm.LR, arm.SP, -16, 0xA9BF7BFD},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -42,8 +42,8 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
case asm.LABEL:
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
c.append(0xa9be7bfd)
|
||||
c.append(0x910003fd)
|
||||
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
|
||||
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
|
||||
|
||||
case asm.LOAD:
|
||||
switch x.Type {
|
||||
@ -96,8 +96,7 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
}
|
||||
|
||||
case asm.RETURN:
|
||||
c.append(0xa8c27bfd)
|
||||
c.append(0xd65f03c0)
|
||||
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
||||
c.append(arm.Return())
|
||||
|
||||
case asm.SYSCALL:
|
||||
|
Reference in New Issue
Block a user