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.
|
// MoveRegisterRegister copies a register to another register.
|
||||||
func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 {
|
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)
|
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.X0, arm.X1, 0xAA0103E0},
|
||||||
{arm.X1, arm.X0, 0xAA0003E1},
|
{arm.X1, arm.X0, 0xAA0003E1},
|
||||||
|
{arm.FP, arm.SP, 0x910003FD},
|
||||||
|
{arm.SP, arm.FP, 0x910003BF},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range usagePatterns {
|
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:
|
case asm.LABEL:
|
||||||
label := c.assembler.Param.Label[x.Index]
|
label := c.assembler.Param.Label[x.Index]
|
||||||
c.codeLabels[label.Name] = Address(len(c.code))
|
c.codeLabels[label.Name] = Address(len(c.code))
|
||||||
c.append(0xa9be7bfd)
|
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
|
||||||
c.append(0x910003fd)
|
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
|
||||||
|
|
||||||
case asm.LOAD:
|
case asm.LOAD:
|
||||||
switch x.Type {
|
switch x.Type {
|
||||||
@ -96,8 +96,7 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case asm.RETURN:
|
case asm.RETURN:
|
||||||
c.append(0xa8c27bfd)
|
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
||||||
c.append(0xd65f03c0)
|
|
||||||
c.append(arm.Return())
|
c.append(arm.Return())
|
||||||
|
|
||||||
case asm.SYSCALL:
|
case asm.SYSCALL:
|
||||||
|
Reference in New Issue
Block a user