This commit is contained in:
parent
a7fd4172b9
commit
6fda03fade
3 changed files with 42 additions and 3 deletions
|
@ -1,8 +1,15 @@
|
|||
package arm
|
||||
|
||||
import "git.urbach.dev/cli/q/src/cpu"
|
||||
|
||||
// Call branches to a PC-relative offset, setting the register X30 to PC+4.
|
||||
// The offset starts from the address of this instruction and is encoded as "imm26" times 4.
|
||||
// This instruction is also known as BL (branch with link).
|
||||
func Call(offset int) uint32 {
|
||||
return uint32(0b100101<<26) | uint32(offset&mask26)
|
||||
}
|
||||
|
||||
// Calls a function whose address is stored in the given register.
|
||||
func CallRegister(register cpu.Register) uint32 {
|
||||
return uint32(0b1101011000111111<<16) | uint32(register)<<5
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
|
@ -23,3 +24,20 @@ func TestCall(t *testing.T) {
|
|||
assert.Equal(t, code, pattern.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallRegister(t *testing.T) {
|
||||
usagePatterns := []struct {
|
||||
Register cpu.Register
|
||||
Code uint32
|
||||
}{
|
||||
{arm.X0, 0xD63F0000},
|
||||
{arm.X1, 0xD63F0020},
|
||||
{arm.X2, 0xD63F0040},
|
||||
}
|
||||
|
||||
for _, pattern := range usagePatterns {
|
||||
t.Logf("blr %d", pattern.Register)
|
||||
code := arm.CallRegister(pattern.Register)
|
||||
assert.Equal(t, code, pattern.Code)
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package asm
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
)
|
||||
|
@ -33,11 +34,24 @@ func (c *compilerARM) Compile(instr Instruction) {
|
|||
binary.LittleEndian.PutUint32(c.code[start:start+4], arm.Call(offset))
|
||||
})
|
||||
case *CallExtern:
|
||||
panic("not implemented")
|
||||
start := len(c.code)
|
||||
c.append(arm.LoadAddress(arm.X0, 0))
|
||||
c.append(arm.LoadRegister(arm.X0, arm.X0, 0, 8))
|
||||
c.append(arm.CallRegister(arm.X0))
|
||||
|
||||
c.Defer(func() {
|
||||
index := c.libraries.Index(instr.Library, instr.Function)
|
||||
|
||||
if index == -1 {
|
||||
panic(fmt.Sprintf("unknown extern function '%s' in library '%s'", instr.Function, instr.Library))
|
||||
}
|
||||
|
||||
address := c.importsStart + index*8
|
||||
offset := address - start
|
||||
binary.LittleEndian.PutUint32(c.code[start:start+4], arm.LoadAddress(arm.X0, offset))
|
||||
})
|
||||
case *CallExternStart:
|
||||
panic("not implemented")
|
||||
case *CallExternEnd:
|
||||
panic("not implemented")
|
||||
case *Jump:
|
||||
start := len(c.code)
|
||||
c.append(arm.Jump(0))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue