Mercurial > lcfOS
view python/cortexm3.py @ 262:ed14e077124c
Added conditional branch instructions
author | Windel Bouwman |
---|---|
date | Fri, 09 Aug 2013 11:30:11 +0200 |
parents | 444b9df2ed99 |
children | 5ec7580976d9 |
line wrap: on
line source
import struct import types from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32 from asmnodes import ASymbol, ANumber, AUnop, ABinop from ppci import CompilerError import ir # TODO: encode this in DSL (domain specific language) def u16(h): return struct.pack('<H', h) def u32(x): return struct.pack('<I', x) armtarget = Target('arm') class ArmReg(Register): def __init__(self, num, name): super().__init__(name) self.num = num def __repr__(self): return self.name class RegOp: def __init__(self, num): assert num < 16 self.num = num @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] return cls(r.num) class Reg8Op: def __init__(self, num): assert num < 8 self.num = num @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 r.num < 8: return cls(r.num) 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 == '[]': 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 MemPcRel(MemRegXRel): regname = 'PC' class MemR8Rel: def __init__(self, basereg, offset): assert type(basereg) is ArmReg 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 = RegOp.Create(arg) if not reg: return regs.add(reg) elif type(arg) is ABinop and arg.op == '-': reg1 = RegOp.Create(arg.arg1) reg2 = RegOp.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] # 8 bit registers: r0 = ArmReg(0, 'r0') armtarget.registers.append(r0) r1 = ArmReg(1, 'r1') armtarget.registers.append(r1) r2 = ArmReg(2, 'r2') armtarget.registers.append(r2) r3 = ArmReg(3, 'r3') armtarget.registers.append(r3) r4 = ArmReg(4, 'r4') armtarget.registers.append(r4) r5 = ArmReg(5, 'r5') armtarget.registers.append(r5) r6 = ArmReg(6, 'r6') armtarget.registers.append(r6) r7 = ArmReg(7, 'r7') armtarget.registers.append(r7) # Other registers: # TODO sp = ArmReg(13, 'sp') armtarget.registers.append(sp) lr = ArmReg(14, 'lr') armtarget.registers.append(lr) pc = ArmReg(15, 'pc') armtarget.registers.append(pc) 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 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) # 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 @armtarget.instruction class loadimm5_ins(LS_imm5_base): mnemonic = 'LDR' opcode = 0xD 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, [PC, imm8], store value into memory """ mnemonic = 'ldr' operands = (RegOp, LabelRef) def __init__(self, rt, label): assert isinstance(label, LabelRef) self.rt = rt self.label = label self.offset = 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 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 @armtarget.instruction class mov_ins(ArmInstruction): """ mov Rd, imm8, move immediate value into register """ mnemonic = 'mov' opcode = 4 # 00100 Rd(3) imm8 operands = (RegOp, Imm8) irpattern = ir.ImmLoad def __init__(self, rd, imm): self.imm = imm.imm self.r = rd.num def encode(self): rd = self.r opcode = self.opcode imm8 = self.imm h = (opcode << 11) | (rd << 8) | imm8 return u16(h) def __repr__(self): return 'MOV {0}, xx?'.format(self.r) # Arithmatics: @armtarget.instruction class addregregimm3_ins(ArmInstruction): """ add Rd, Rn, imm3 """ mnemonic = 'add' opcode = 3 # 00011 operands = (RegOp, RegOp, Imm3) irpattern = 3 def __init__(self, rd, rn, imm3): self.rd = rd self.rn = rn self.imm3 = imm3 def encode(self): rd = self.rd.num rn = self.rn.num imm3 = self.imm3.imm opcode = self.opcode h = (opcode << 11) | (1 << 10) | (imm3 << 6) | (rn << 3) | rd return u16(h) 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 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 class regreg_base(ArmInstruction): """ ??? Rdn, Rm """ operands = (Reg8Op, Reg8Op) def __init__(self, rdn, rm): self.rdn = rdn self.rm = rm 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 """ mnemonic = 'mov' opcode = 0 @armtarget.instruction class andregs_ins(regreg_base): mnemonic = 'AND' opcode = 0b0100000000 @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 = (RegOp, 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) #if self.offset < 0: # # TODO: handle negative jump # self.offset = 0 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 blt_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) armtarget.check()