This commit is contained in:
parent
a7fd4172b9
commit
6fda03fade
3 changed files with 42 additions and 3 deletions
|
@ -1,8 +1,15 @@
|
||||||
package arm
|
package arm
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/cpu"
|
||||||
|
|
||||||
// Call branches to a PC-relative offset, setting the register X30 to PC+4.
|
// 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.
|
// 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).
|
// This instruction is also known as BL (branch with link).
|
||||||
func Call(offset int) uint32 {
|
func Call(offset int) uint32 {
|
||||||
return uint32(0b100101<<26) | uint32(offset&mask26)
|
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"
|
"testing"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/arm"
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
"git.urbach.dev/go/assert"
|
"git.urbach.dev/go/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,3 +24,20 @@ func TestCall(t *testing.T) {
|
||||||
assert.Equal(t, code, pattern.Code)
|
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 (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/arm"
|
"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))
|
binary.LittleEndian.PutUint32(c.code[start:start+4], arm.Call(offset))
|
||||||
})
|
})
|
||||||
case *CallExtern:
|
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:
|
case *CallExternStart:
|
||||||
panic("not implemented")
|
|
||||||
case *CallExternEnd:
|
case *CallExternEnd:
|
||||||
panic("not implemented")
|
|
||||||
case *Jump:
|
case *Jump:
|
||||||
start := len(c.code)
|
start := len(c.code)
|
||||||
c.append(arm.Jump(0))
|
c.append(arm.Jump(0))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue