Mercurial > lcfOS
diff python/target/armtarget.py @ 292:534b94b40aa8
Fixup reorganize
author | Windel Bouwman |
---|---|
date | Wed, 27 Nov 2013 08:06:42 +0100 |
parents | 7b38782ed496 |
children | 44f336460c2a |
line wrap: on
line diff
--- a/python/target/armtarget.py Sun Nov 24 11:24:15 2013 +0100 +++ b/python/target/armtarget.py Wed Nov 27 08:06:42 2013 +0100 @@ -1,759 +1,32 @@ import struct -import types -import ir -from asmnodes import ASymbol, ANumber, AUnop, ABinop -from ppci import CompilerError from .basetarget import Register, Instruction, Target, Label, LabelRef from .basetarget import Imm32, Imm8, Imm7, Imm3 -from .armframe import ArmFrame, ArmInstructionSelector +from .arminstructions import allins, Reg8Op, ArmRegister +from .arminstructions import Dcd, B +from .arminstructions import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP """ ARM target description. """ # TODO: encode this in DSL (domain specific language) # TBD: is this required? - -def u16(h): - return struct.pack('<H', h) - -def u32(x): - return struct.pack('<I', x) - -armtarget = Target('arm') -armtarget.InstructionSelector = ArmInstructionSelector -armtarget.Frame = ArmFrame - -class ArmRegister(Register): - def __init__(self, num, name): - super().__init__(name) - self.num = num - - def __repr__(self): - return self.name - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - name = vop.name - regs = {} - for r in armtarget.registers: - regs[r.name] = r - if name in regs: - r = regs[name] - if isinstance(r, cls): - return r - - -class Reg8Op(ArmRegister): - pass - - -class Reg16Op(ArmRegister): - pass - - -class RegSpOp: - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - if vop.name.lower() == 'sp': - return cls() - -def getRegNum(n): - for r in armtarget.registers: - if r.num == n: - return r - -def getRegisterRange(n1, n2): - regs = [] - if n1.num < n2.num: - for n in range(n1.num, n2.num + 1): - r = getRegNum(n) - assert r - regs.append(r) - return regs - -def isRegOffset(regname, x, y): - if type(x) is ASymbol and type(y) is ANumber and x.name.upper() == regname: - return y.number - elif type(y) is ASymbol and type(x) is ANumber and y.name.upper() == regname: - return x.number - - -class MemRegXRel: - def __init__(self, offset): - assert offset % 4 == 0 - self.offset = offset - - def __repr__(self): - return '[{}, #{}]'.format(self.regname, self.offset) - - @classmethod - def Create(cls, vop): - if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+': - vop = vop.arg # descent - offset = isRegOffset(cls.regname, vop.arg1, vop.arg2) - if type(offset) is int: - if offset % 4 == 0: - offset = vop.arg2.number - return cls(offset) - elif type(vop) is ASymbol and vop.name.upper() == self.regname: - return cls(0) - - -class MemSpRel(MemRegXRel): - regname = 'SP' - - -class MemR8Rel: - def __init__(self, basereg, offset): - assert type(basereg) is Reg8Op - assert type(offset) is int - self.basereg = basereg - self.offset = offset - - def __repr__(self): - return '[{}, #{}]'.format(self.basereg, self.offset) - - @classmethod - def Create(cls, vop): - if type(vop) is AUnop and vop.operation == '[]': - vop = vop.arg # descent - if type(vop) is ABinop: - if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber: - offset = vop.arg2.number - if offset > 120: - return - basereg = Reg8Op.Create(vop.arg1) - if not basereg: - return - else: - return - elif type(vop) is ASymbol: - offset = 0 - basereg = Reg8Op.Create(vop) - if not basereg: - return - else: - return - return cls(getRegNum(basereg.num), offset) - -class RegisterSet: - def __init__(self, regs): - assert type(regs) is set - self.regs = regs - - def __repr__(self): - return ','.join([str(r) for r in self.regs]) - - @classmethod - def Create(cls, vop): - assert type(vop) is AUnop and vop.operation == '{}' - assert type(vop.arg) is list - regs = set() - for arg in vop.arg: - if type(arg) is ASymbol: - reg = ArmRegister.Create(arg) - if not reg: - return - regs.add(reg) - elif type(arg) is ABinop and arg.op == '-': - reg1 = ArmRegister.Create(arg.arg1) - reg2 = ArmRegister.Create(arg.arg2) - if not reg1: - return - if not reg2: - return - for r in getRegisterRange(reg1, reg2): - regs.add(r) - else: - raise Exception('Cannot be') - return cls(regs) - - def registerNumbers(self): - return [r.num for r in self.regs] - -def makeReg(cls, num, name): - r = cls(num, name) - armtarget.registers.append(r) - return r - -# 8 bit registers: -r0 = makeReg(Reg8Op, 0, 'r0') -r1 = makeReg(Reg8Op, 1, 'r1') -r2 = makeReg(Reg8Op, 2, 'r2') -r3 = makeReg(Reg8Op, 3, 'r3') -r4 = makeReg(Reg8Op, 4, 'r4') -r5 = makeReg(Reg8Op, 5, 'r5') -r6 = makeReg(Reg8Op, 6, 'r6') -r7 = makeReg(Reg8Op, 7, 'r7') -# Other registers: -# TODO -sp = makeReg(ArmRegister, 13, 'sp') -lr = makeReg(ArmRegister, 14, 'lr') -pc = makeReg(ArmRegister, 15, 'pc') - -# Sanity checks: -assert isinstance(sp, ArmRegister) -assert isinstance(r3, ArmRegister) -assert ArmRegister.Create(ASymbol('r3')) is r3 -assert ArmRegister.Create(ASymbol('sp')) is sp - - -class ArmInstruction(Instruction): - pass - - -@armtarget.instruction -class dcd_ins(ArmInstruction): - mnemonic = 'dcd' - operands = (Imm32,) - def __init__(self, expr): - if isinstance(expr, Imm32): - self.expr = expr.imm - self.label = None - elif isinstance(expr, LabelRef): - self.expr = 0 - self.label = expr - elif isinstance(expr, int): - self.expr = expr - self.label = None - else: - raise NotImplementedError() - - def resolve(self, f): - if self.label: - self.expr = f(self.label.name) - - def encode(self): - return u32(self.expr) - - def __repr__(self): - return 'DCD 0x{0:X}'.format(self.expr) - - -@armtarget.instruction -class nop_ins(ArmInstruction): - mnemonic = 'nop' - operands = tuple() - - def encode(self): - return bytes() - - def __repr__(self): - return 'NOP' - - -# Memory related - -class LS_imm5_base(ArmInstruction): - """ ??? Rt, [Rn, imm5] """ - operands = (Reg8Op, MemR8Rel) - def __init__(self, rt, memop): - assert memop.offset % 4 == 0 - self.imm5 = memop.offset >> 2 - self.rn = memop.basereg.num - self.rt = rt - self.memloc = memop - assert self.rn < 8 - assert self.rt.num < 8 - - def encode(self): - Rn = self.rn - Rt = self.rt.num - imm5 = self.imm5 - - h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt - return u16(h) - - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) - - -@armtarget.instruction -class storeimm5_ins(LS_imm5_base): - mnemonic = 'STR' - opcode = 0xC - - @classmethod - def fromim(cls, im): - mem = MemR8Rel(im.src[0], im.others[0]) - return cls(im.src[1], mem) - - -@armtarget.instruction -class loadimm5_ins(LS_imm5_base): - mnemonic = 'LDR' - opcode = 0xD - - @classmethod - def fromim(cls, im): - mem = MemR8Rel(im.src[0], im.others[0]) - return cls(im.dst[0], mem) - -class ls_sp_base_imm8(ArmInstruction): - operands = (Reg8Op, MemSpRel) - def __init__(self, rt, memop): - self.rt = rt - self.offset = memop.offset - - def encode(self): - rt = self.rt.num - assert rt < 8 - imm8 = self.offset >> 2 - assert imm8 < 256 - h = (self.opcode << 8) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset) - -def align(x, m): - while ((x % m) != 0): - x = x + 1 - return x - - -@armtarget.instruction -class ldr_pcrel(ArmInstruction): - """ ldr Rt, LABEL, load value from pc relative position """ - mnemonic = 'ldr' - operands = (Reg8Op, LabelRef) - def __init__(self, rt, label): - assert isinstance(label, LabelRef) - self.rt = rt - self.label = label - self.offset = 0 - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def resolve(self, f): - la = f(self.label.name) - sa = align(self.address + 2, 4) - self.offset = (la - sa) - if self.offset < 0: - self.offset = 0 - - def encode(self): - rt = self.rt.num - assert rt < 8 - assert self.offset % 4 == 0 - imm8 = self.offset >> 2 - assert imm8 < 256 - assert imm8 >= 0 - h = (0x9 << 11) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - return 'LDR {}, {}'.format(self.rt, self.label.name) - - -@armtarget.instruction -class ldr_sprel(ls_sp_base_imm8): - """ ldr Rt, [SP, imm8] """ - mnemonic = 'LDR' - opcode = 0x98 - - -@armtarget.instruction -class str_sprel(ls_sp_base_imm8): - """ str Rt, [SP, imm8] """ - mnemonic = 'STR' - opcode = 0x90 +# TODO: make a difference between armv7 and armv5? -@armtarget.instruction -class mov_imm8_ins(ArmInstruction): - """ mov Rd, imm8, move immediate value into register """ - mnemonic = 'mov' - opcode = 4 # 00100 Rd(3) imm8 - operands = (Reg8Op, Imm8) - def __init__(self, rd, imm): - if type(imm) is int: - imm = Imm8(imm) - assert type(imm) is Imm8 - self.imm = imm.imm - assert type(rd) is Reg8Op, str(type(rd)) - self.rd = rd - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def encode(self): - rd = self.rd.num - opcode = self.opcode - imm8 = self.imm - h = (opcode << 11) | (rd << 8) | imm8 - return u16(h) - - def __repr__(self): - return 'MOV {}, {}'.format(self.rd, self.imm) - - - -# Arithmatics: - - - -class regregimm3_base(ArmInstruction): - operands = (Reg8Op, Reg8Op, Imm3) - def __init__(self, rd, rn, imm3): - self.rd = rd - self.rn = rn - assert type(imm3) is Imm3 - self.imm3 = imm3 - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.others[0]) - - def encode(self): - rd = self.rd.num - rn = self.rn.num - imm3 = self.imm3.imm - opcode = self.opcode - h = (self.opcode << 9) | (imm3 << 6) | (rn << 3) | rd - return u16(h) - - def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm3.imm) - -@armtarget.instruction -class addregregimm3_ins(regregimm3_base): - """ add Rd, Rn, imm3 """ - mnemonic = 'add' - opcode = 0b0001110 - - -@armtarget.instruction -class subregregimm3_ins(regregimm3_base): - """ sub Rd, Rn, imm3 """ - mnemonic = 'sub' - opcode = 0b0001111 - - -class regregreg_base(ArmInstruction): - """ ??? Rd, Rn, Rm """ - operands = (Reg8Op, Reg8Op, Reg8Op) - def __init__(self, rd, rn, rm): - self.rd = rd - self.rn = rn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.src[1]) - - def encode(self): - rd = self.rd.num - rn = self.rn.num - rm = self.rm.num - h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd - return u16(h) - - def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) - - -@armtarget.instruction -class addregs_ins(regregreg_base): - mnemonic = 'ADD' - opcode = 0b0001100 - - -@armtarget.instruction -class subregs_ins(regregreg_base): - mnemonic = 'SUB' - opcode = 0b0001101 - - - -@armtarget.instruction -class movregreg_ext_ins(ArmInstruction): - """ mov rd, rm """ - operands = (ArmRegister, ArmRegister) - mnemonic = 'MOV' - def __init__(self, rd, rm): - self.rd = rd - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0]) - - def encode(self): - Rd = self.rd.num & 0x7 - D = (self.rd.num >> 3) & 0x1 - Rm = self.rm.num - opcode = 0b01000110 - return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) - - -@armtarget.instruction -class mulregreg_ins(ArmInstruction): - """ mul Rn, Rdm """ - operands = (Reg8Op, Reg8Op) - mnemonic = 'MUL' - def __init__(self, rn, rdm): - self.rn = rn - self.rdm = rdm - - @classmethod - def fromim(cls, im): - assert im.src[1] is im.dst[0] - return cls(im.src[0], im.dst[0]) - - def encode(self): - rn = self.rn.num - rdm = self.rdm.num - opcode = 0b0100001101 - h = (opcode << 6) | (rn << 3) | rdm - return u16(h) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) - - -class regreg_base(ArmInstruction): - """ ??? Rdn, Rm """ - operands = (Reg8Op, Reg8Op) - # TODO: integrate with the code gen interface: - src = (0, 1) - dst = (0,) - def __init__(self, rdn, rm): - self.rdn = rdn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.src[0], im.src[1]) - - def encode(self): - rdn = self.rdn.num - rm = self.rm.num - h = (self.opcode << 6) | (rm << 3) | rdn - return u16(h) - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm) - - -@armtarget.instruction -class movregreg_ins(regreg_base): - """ mov Rd, Rm (reg8 operands) """ - # TODO: match this: - pattern = ir.Move(ir.Temp, ir.Temp) - mnemonic = 'mov' - opcode = 0 - - -@armtarget.instruction -class andregs_ins(regreg_base): - mnemonic = 'AND' - opcode = 0b0100000000 - +class ArmTarget(Target): + def __init__(self): + super().__init__('arm') + for i in allins: + self.addInstruction(i) + # TODO: fix this nicer? + #setattr(self, i.__name__, i) + self.check() -@armtarget.instruction -class orrregs_ins(regreg_base): - mnemonic = 'ORR' - opcode = 0b0100001100 - - -@armtarget.instruction -class cmp_ins(regreg_base): - mnemonic = 'CMP' - opcode = 0b0100001010 - - -@armtarget.instruction -class lslregs_ins(regreg_base): - mnemonic = 'LSL' - opcode = 0b0100000010 - -@armtarget.instruction -class cmpregimm8_ins(ArmInstruction): - """ cmp Rn, imm8 """ - mnemonic = 'cmp' - opcode = 5 # 00101 - operands = (Reg8Op, Imm8) - def __init__(self, rn, imm): - self.rn = rn - self.imm = imm - def encode(self): - rn = self.rn.num - imm = self.imm.imm - opcode = self.opcode - h = (opcode << 11) | (rn << 8) | imm - return u16(h) - - -# Jumping: - -def wrap_negative(x, bits): - b = struct.unpack('<I', struct.pack('<i', x))[0] - mask = (1 << bits) - 1 - return b & mask - -class jumpBase_ins(ArmInstruction): - operands = (LabelRef,) - def __init__(self, target_label): - assert type(target_label) is LabelRef - self.target = target_label - self.offset = 0 - - def resolve(self, f): - la = f(self.target.name) - sa = self.address + 4 - self.offset = (la - sa) - - def __repr__(self): - return '{} {}'.format(self.mnemonic, self.target.name) - - -@armtarget.instruction -class b_ins(jumpBase_ins): - mnemonic = 'B' - def encode(self): - imm11 = wrap_negative(self.offset >> 1, 11) - h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode - return u16(h) - - -@armtarget.instruction -class bl_ins(jumpBase_ins): - mnemonic = 'BL' - def encode(self): - imm32 = wrap_negative(self.offset >> 1, 32) - imm11 = imm32 & 0x7FF - imm10 = (imm32 >> 11) & 0x3FF - j1 = 1 # TODO: what do these mean? - j2 = 1 - s = (imm32 >> 24) & 0x1 - h1 = (0b11110 << 11) | (s << 10) | imm10 - h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 - return u16(h1) + u16(h2) - - -class cond_base_ins(jumpBase_ins): - def encode(self): - imm8 = wrap_negative(self.offset >> 1, 8) - h = (0b1101 << 12) | (self.cond << 8) | imm8 - return u16(h) - - -@armtarget.instruction -class beq_ins(cond_base_ins): - mnemonic = 'beq' - cond = 0 - - -@armtarget.instruction -class bne_ins(cond_base_ins): - mnemonic = 'bne' - cond = 1 - - -@armtarget.instruction -class blt_ins(cond_base_ins): - mnemonic = 'blt' - cond = 0b1011 - - -@armtarget.instruction -class bgt_ins(cond_base_ins): - mnemonic = 'bgt' - cond = 0b1100 - - -@armtarget.instruction -class push_ins(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'push' - def __init__(self, regs): - assert (type(regs),) == self.operands, (type(regs),) - self.regs = regs - def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) - def encode(self): - reg_list = 0 - M = 0 - for n in self.regs.registerNumbers(): - if n < 8: - reg_list |= (1 << n) - elif n == 14: - M = 1 - else: - raise NotImplementedError('not implemented for this register') - h = (0x5a << 9) | (M << 8) | reg_list - return u16(h) - - -@armtarget.instruction -class pop_ins(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'pop' - - def __init__(self, regs): - self.regs = regs - - def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) - - def encode(self): - reg_list = 0 - P = 0 - for n in self.regs.registerNumbers(): - if n < 8: - reg_list |= (1 << n) - elif n == 15: - P = 1 - else: - raise NotImplementedError('not implemented for this register') - h = (0x5E << 9) | (P << 8) | reg_list - return u16(h) - - -@armtarget.instruction -class yield_ins(ArmInstruction): - operands = () - mnemonic = 'yield' - - def encode(self): - return u16(0xbf10) - -# misc: - -# add/sub SP: -class addspsp_base(ArmInstruction): - operands = (RegSpOp, RegSpOp, Imm7) - def __init__(self, _sp, _sp2, imm7): - self.imm7 = imm7.imm - assert self.imm7 % 4 == 0 - self.imm7 >>= 2 - - def encode(self): - return u16((self.opcode << 7) |self.imm7) - - def __repr__(self): - return '{} sp, sp, {}'.format(self.mnemonic, self.imm7 << 2) - -@armtarget.instruction -class addspsp_ins(addspsp_base): - mnemonic = 'add' - opcode = 0b101100000 - - -@armtarget.instruction -class subspsp_ins(addspsp_base): - mnemonic = 'sub' - opcode = 0b101100001 - -armtarget.check() - + def startCode(self, outs): + """ Emit some startup code in the output stream """ + outs.selectSection('code') + # assembly glue to make it work: + # TODO: this must be in source code, not in compiler + outs.emit(Dcd(Imm32(0x20000678))) # initial SP + outs.emit(Dcd(Imm32(0x08000009))) # reset vector + outs.emit(B(LabelRef('main')))