180 lines
4.6 KiB
Go
180 lines
4.6 KiB
Go
package asmc
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.urbach.dev/cli/q/src/arm"
|
|
"git.urbach.dev/cli/q/src/asm"
|
|
)
|
|
|
|
func (c *compiler) compileARM(x asm.Instruction) {
|
|
switch x.Mnemonic {
|
|
case asm.CALL:
|
|
switch x.Type {
|
|
case asm.TypeLabel:
|
|
label := c.assembler.Param.Label[x.Index]
|
|
position := Address(len(c.code))
|
|
c.append(arm.Call(0))
|
|
|
|
pointer := &pointer{
|
|
Position: position,
|
|
OpSize: 0,
|
|
Size: 4,
|
|
}
|
|
|
|
pointer.Resolve = func() Address {
|
|
destination, exists := c.codeLabels[label.Name]
|
|
|
|
if !exists {
|
|
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
|
}
|
|
|
|
distance := (destination - position) / 4
|
|
return arm.Call(distance)
|
|
}
|
|
|
|
c.codePointers = append(c.codePointers, pointer)
|
|
|
|
default:
|
|
panic("not implemented")
|
|
}
|
|
|
|
case asm.LABEL:
|
|
label := c.assembler.Param.Label[x.Index]
|
|
c.codeLabels[label.Name] = Address(len(c.code))
|
|
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 {
|
|
case asm.TypeMemoryRegister:
|
|
operands := c.assembler.Param.MemoryRegister[x.Index]
|
|
|
|
if operands.Address.OffsetRegister < 0 {
|
|
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
|
} else {
|
|
panic("not implemented")
|
|
}
|
|
}
|
|
|
|
case asm.STORE:
|
|
switch x.Type {
|
|
case asm.TypeMemoryRegister:
|
|
operands := c.assembler.Param.MemoryRegister[x.Index]
|
|
|
|
if operands.Address.OffsetRegister < 0 {
|
|
c.append(arm.StoreRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
|
} else {
|
|
panic("not implemented")
|
|
}
|
|
|
|
case asm.TypeMemoryNumber:
|
|
operands := c.assembler.Param.MemoryNumber[x.Index]
|
|
|
|
if operands.Address.OffsetRegister < 0 {
|
|
c.append(arm.MoveRegisterNumber(arm.X0, operands.Number))
|
|
c.append(arm.StoreRegister(arm.X0, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
|
} else {
|
|
panic("not implemented")
|
|
}
|
|
}
|
|
|
|
case asm.PUSH:
|
|
switch x.Type {
|
|
case asm.TypeRegister:
|
|
operand := c.assembler.Param.Register[x.Index]
|
|
c.append(arm.StorePair(operand.Register, operand.Register, arm.SP, -16))
|
|
}
|
|
|
|
case asm.POP:
|
|
switch x.Type {
|
|
case asm.TypeRegister:
|
|
operand := c.assembler.Param.Register[x.Index]
|
|
c.append(arm.LoadPair(operand.Register, operand.Register, arm.SP, 16))
|
|
}
|
|
|
|
case asm.ADD:
|
|
switch x.Type {
|
|
case asm.TypeRegisterNumber:
|
|
operand := c.assembler.Param.RegisterNumber[x.Index]
|
|
c.append(arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number))
|
|
case asm.TypeRegisterRegister:
|
|
panic("not implemented")
|
|
}
|
|
|
|
case asm.SUB:
|
|
switch x.Type {
|
|
case asm.TypeRegisterNumber:
|
|
operand := c.assembler.Param.RegisterNumber[x.Index]
|
|
c.append(arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number))
|
|
case asm.TypeRegisterRegister:
|
|
panic("not implemented")
|
|
}
|
|
|
|
case asm.COMPARE:
|
|
switch x.Type {
|
|
case asm.TypeRegisterNumber:
|
|
operand := c.assembler.Param.RegisterNumber[x.Index]
|
|
c.append(arm.CompareRegisterNumber(operand.Register, operand.Number))
|
|
case asm.TypeRegisterRegister:
|
|
panic("not implemented")
|
|
}
|
|
|
|
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
|
|
c.jumpARM(x)
|
|
|
|
case asm.MOVE:
|
|
switch x.Type {
|
|
case asm.TypeRegisterRegister:
|
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
|
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
|
|
|
case asm.TypeRegisterNumber:
|
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
|
c.append(arm.MoveRegisterNumber(operands.Register, operands.Number))
|
|
|
|
case asm.TypeRegisterLabel:
|
|
operands := c.assembler.Param.RegisterLabel[x.Index]
|
|
position := Address(len(c.code))
|
|
c.append(arm.LoadAddress(operands.Register, 0))
|
|
|
|
if strings.HasPrefix(operands.Label, "data ") {
|
|
c.dataPointers = append(c.dataPointers, &pointer{
|
|
Position: position,
|
|
OpSize: 0,
|
|
Size: 4,
|
|
Resolve: func() Address {
|
|
destination, exists := c.dataLabels[operands.Label]
|
|
|
|
if !exists {
|
|
panic("unknown label")
|
|
}
|
|
|
|
destination += c.dataStart - c.codeStart
|
|
distance := destination - position + 8
|
|
return arm.LoadAddress(operands.Register, int(distance))
|
|
},
|
|
})
|
|
} else {
|
|
panic("not implemented")
|
|
}
|
|
}
|
|
|
|
case asm.RETURN:
|
|
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
|
c.append(arm.Return())
|
|
|
|
case asm.SYSCALL:
|
|
c.append(arm.Syscall())
|
|
|
|
default:
|
|
panic("unknown mnemonic: " + x.Mnemonic.String())
|
|
}
|
|
}
|
|
|
|
func (c *compiler) append(code uint32) {
|
|
c.code = binary.LittleEndian.AppendUint32(c.code, code)
|
|
}
|