# HG changeset patch # User Windel Bouwman # Date 1393607234 -3600 # Node ID 4d204f6f7d4e5ce74b30c913a8827b3039d53805 # Parent c7cc54c0dfdf597413f9c0751a691ecce4fe3d65 Rewrite of assembler parts diff -r c7cc54c0dfdf -r 4d204f6f7d4e examples/c3/recipe.yaml --- a/examples/c3/recipe.yaml Sun Feb 23 16:24:01 2014 +0100 +++ b/examples/c3/recipe.yaml Fri Feb 28 18:07:14 2014 +0100 @@ -3,11 +3,11 @@ inputs: - assemble: source: startup_stm32f4.asm - machine: arm + machine: thumb - compile: sources: [burn2.c3] includes: [stm32f4xx.c3] - machine: arm + machine: thumb output: burn.elf2 output: burn2.bin layout: diff -r c7cc54c0dfdf -r 4d204f6f7d4e kernel/recipe.yaml --- a/kernel/recipe.yaml Sun Feb 23 16:24:01 2014 +0100 +++ b/kernel/recipe.yaml Fri Feb 28 18:07:14 2014 +0100 @@ -3,11 +3,11 @@ inputs: - assemble: source: startup_a9.asm - machine: arm + machine: thumb - compile: sources: [memory.c3, kernel.c3, syscall.c3, process.c3, schedule.c3, arch_arm.c3] includes: [] - machine: arm + machine: thumb output: kernel.elf2 layout: code: 0x10000 diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/outstream.py --- a/python/outstream.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/outstream.py Fri Feb 28 18:07:14 2014 +0100 @@ -48,7 +48,7 @@ def emit(self, item): """ Encode instruction and add symbol and relocation information """ - assert isinstance(item, Instruction) + assert isinstance(item, Instruction), str(item) + str(type(item)) assert self.currentSection section = self.currentSection address = self.currentSection.Size diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/ppci/assembler.py --- a/python/ppci/assembler.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/ppci/assembler.py Fri Feb 28 18:07:14 2014 +0100 @@ -6,7 +6,16 @@ from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber -def tokenize(s): +def bit_type(value): + assert value < (2**31) + assert value >= 0 + t = 'val32' + for n in [8, 5, 3]: + if value < (2**n): + t = 'val{}'.format(n) + return t + +def tokenize(s, kws): """ Tokenizer, generates an iterator that returns tokens! @@ -46,8 +55,13 @@ val = float(val) elif typ == 'STRING': val = val[1:-1] + elif typ == 'ID': + if val.lower() in kws: # ['r3', 'sp', 'add', 'yield', 'r4', 'r0', 'r1', 'sub', 'r5', 'r6', 'r2']: + typ = val.lower() col = mo.start() - line_start loc = SourceLocation('', line, col, 0) # TODO retrieve length? + if typ == 'NUMBER': + typ = bit_type(val) yield Token(typ, val, loc) pos = mo.end() mo = gettok(s, pos) @@ -59,8 +73,8 @@ class Lexer: - def __init__(self, src): - self.tokens = tokenize(src) + def __init__(self, src, kws): + self.tokens = tokenize(src, kws) self.curTok = self.tokens.__next__() def next_token(self): @@ -71,11 +85,26 @@ class Parser: - def __init__(self, tokens, instruction_rules): + def add_rule(self, prod, rhs, f): + """ Helper function to add a rule, why this is required? """ + if prod == 'instruction': + def f_wrap(*args): + i = f(args) + self.emit(i) + else: + def f_wrap(*rhs): + return f(rhs) + self.g.add_production(prod, rhs, f_wrap) + + def __init__(self, kws, instruction_rules, emit): # Construct a parser given a grammar: - ident = lambda x: x # Identity helper function - g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}', - pyyacc.EOF]) + tokens2 = ['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', + pyyacc.EPS, 'COMMENT', '{', '}', + pyyacc.EOF, 'val32', 'val8', 'val5', 'val3'] + tokens2.extend(kws) + self.kws = kws + g = pyyacc.Grammar(tokens2) + self.g = g # Global structure of assembly line: g.add_production('asmline', ['asmline2']) g.add_production('asmline', ['asmline2', 'COMMENT']) @@ -88,27 +117,22 @@ # Add instruction rules for the target in question: for prod, rhs, f in instruction_rules: - if prod is 'instruction': - def f_wrap(*rhs): - i = f(rhs) - self.emit(i) - else: - def f_wrap(*rhs): - return f(rhs) - g.add_production(prod, rhs, f_wrap) + self.add_rule(prod, rhs, f) #g.add_production('instruction', []) - g.add_production('expression', ['term'], ident) + g.add_production('expression', ['term'], lambda x: x) g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) g.add_production('addop', ['-'], lambda x: x.val) g.add_production('addop', ['+'], lambda x: x.val) g.add_production('mulop', ['*'], lambda x: x.val) - g.add_production('term', ['factor'], ident) + g.add_production('term', ['factor'], lambda x: x) g.add_production('term', ['term', 'mulop', 'factor'], self.p_binop) g.add_production('factor', ['ID'], lambda name: ASymbol(name.val)) g.add_production('factor', ['NUMBER'], lambda num: ANumber(int(num.val))) g.start_symbol = 'asmline' - self.p = g.genParser() + self.emit = emit + self.p = g.generate_parser() + print('length of table:', len(self.p.action_table)) # Parser handlers: def p_ins_1(self, opc, ops): @@ -141,14 +165,13 @@ return AUnop('[]', exp) def p_label(self, lname, cn): - lab = ALabel(lname.val) + lab = Label(lname.val) self.emit(lab) def p_binop(self, exp1, op, exp2): return ABinop(op, exp1, exp2) - def parse(self, lexer, emitter): - self.emit = emitter + def parse(self, lexer): self.p.parse(lexer) @@ -157,12 +180,12 @@ self.target = target assert isinstance(target, Target) self.stream = stream - self.parser = Parser(None, target.assembler_rules, self.stream.emit) + self.parser = Parser(target.asm_keywords, target.assembler_rules, self.stream.emit) # Top level interface: def parse_line(self, line): """ Parse line into assembly instructions """ - tokens = Lexer(line) + tokens = Lexer(line, self.target.asm_keywords) self.parser.parse(tokens) def assemble(self, asmsrc): diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/pyyacc.py --- a/python/pyyacc.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/pyyacc.py Fri Feb 28 18:07:14 2014 +0100 @@ -266,7 +266,7 @@ class Production: """ Production rule for a grammar """ - def __init__(self, name, symbols, f=None): + def __init__(self, name, symbols, f): self.name = name self.symbols = symbols self.f = f @@ -309,7 +309,7 @@ @property def IsShift(self): """ Check if this item is a shift item, i.e. the dot can proceed """ - return not self.IsReduce + return self.dotpos < len(self.production.symbols) @property def Next(self): diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/arm.brg --- a/python/target/arm.brg Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/arm.brg Fri Feb 28 18:07:14 2014 +0100 @@ -3,7 +3,7 @@ from target.arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3 from target.arminstructions import B, Bl, Bgt, Blt, Beq, Bne from target.arminstructions import Mov2, Mov3 -from target.arminstructions import Add, Sub, Cmp, Sub2, Add2, Mul +from target.arminstructions import Add3, Sub, Cmp, Sub2, Add2, Mul from ppci import ir %% @@ -16,7 +16,7 @@ %% -reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add, dst=[d], src=[$1, $2]); return d .) +reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add3, dst=[d], src=[$1, $2]); return d .) reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub, dst=[d], src=[$1, $2]); return d .) reg: ORI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Orr, dst=[], src=[d, $2]); return d .) reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Lsl, dst=[], src=[d, $2]); return d .) diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/armframe.py --- a/python/target/armframe.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/armframe.py Fri Feb 28 18:07:14 2014 +0100 @@ -3,7 +3,7 @@ from .basetarget import Imm7 from ppci.irmach import makeIns, Frame from .arminstructions import Dcd, AddSp, SubSp, Push, Pop, Mov2 -from .arminstructions import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP +from .armregisters import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP class ArmFrame(Frame): @@ -64,7 +64,7 @@ Push({LR, R7}) ] if self.stacksize > 0: - pre.append(SubSp(SP, SP, Imm7(self.stacksize))) # Reserve stack space + pre.append(SubSp(self.stacksize)) # Reserve stack space pre += [ Mov2(R7, SP) # Setup frame pointer ] @@ -74,7 +74,7 @@ """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """ post = [] if self.stacksize > 0: - post.append(AddSp(SP, SP, Imm7(self.stacksize))) + post.append(AddSp(self.stacksize)) post += [ Pop({PC, R7}), Alignment(4) # Align at 4 bytes diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/arminstructions.py --- a/python/target/arminstructions.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/arminstructions.py Fri Feb 28 18:07:14 2014 +0100 @@ -3,11 +3,10 @@ from .basetarget import Register, Instruction, Target, Label, LabelRef from .basetarget import Imm32, Imm8, Imm7, Imm3 -from .armtokens import ThumbToken, ArmToken -from .armregisters import R0 +from .armtoken import ThumbToken, ArmToken +from .armregisters import R0, ArmRegister, SP -def add_rule(rhs, f): - pass + def u16(h): return struct.pack(' 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] +class ThumbInstruction(Instruction): + pass -# Instructions: - -class ArmInstruction(Instruction): - pass - - -allins = [] - - -def instruction(i): - allins.append(i) - return i - -add_rule(['dcd', 'imm32'], lambda rhs: Dcd(rhs[1])) - -class Dcd(ArmInstruction): - mnemonic = 'dcd' - operands = (Imm32,) +class Dcd(ThumbInstruction): def __init__(self, expr): if isinstance(expr, Imm32): self.expr = expr.imm @@ -193,11 +86,7 @@ return 'DCD 0x{0:X}'.format(self.expr) -@instruction -class nop_ins(ArmInstruction): - mnemonic = 'nop' - operands = tuple() - +class nop_ins(ThumbInstruction): def encode(self): return bytes() @@ -207,57 +96,51 @@ # Memory related -class LS_imm5_base(ArmInstruction): +class LS_imm5_base(ThumbInstruction): """ ??? 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 + def __init__(self, rt, rn, imm5): + assert imm5 % 4 == 0 + self.imm5 = imm5 >> 2 + self.rn = rn self.rt = rt - self.memloc = memop - assert self.rn < 8 + assert self.rn.num < 8 assert self.rt.num < 8 + self.token = ThumbToken() def encode(self): - Rn = self.rn + Rn = self.rn.num Rt = self.rt.num imm5 = self.imm5 + self.token[0:3] = Rt + self.token[3:6] = Rn + self.token[6:11] = imm5 + self.token[11:16] = self.opcode + return self.token.encode() - h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt - return u16(h) + def __repr__(self): + mnemonic = "???" + return '{} {}, [{}, {}]'.format(mnemonic, self.rt, self.rn, self.imm5) - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) - - -@instruction class Str2(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) + return cls(im.src[1], im.src[0], im.others[0]) -@instruction class Ldr2(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) + return cls(im.dst[0], im.src[0], im.others[0]) -class ls_sp_base_imm8(ArmInstruction): - operands = (Reg8Op, MemSpRel) - def __init__(self, rt, memop): +class ls_sp_base_imm8(ThumbInstruction): + def __init__(self, rt, offset): self.rt = rt - self.offset = memop.offset + self.offset = offset def encode(self): rt = self.rt.num @@ -268,73 +151,65 @@ return u16(h) def __repr__(self): - return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset) + mnemonic = self.__class__.__name__ + return '{} {}, [sp,#{}]'.format(mnemonic, self.rt, self.offset) def align(x, m): while ((x % m) != 0): x = x + 1 return x +def Ldr(*args): + if len(args) == 2 and isinstance(args[0], ArmRegister) \ + and isinstance(args[1], str): + return Ldr3(*args) + else: + raise Exception() -@instruction -class Ldr3(ArmInstruction): + +class Ldr3(ThumbInstruction): """ 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 relocations(self): - return [(self.label.name, 'lit_add_8')] + return [(self.label, 'lit_add_8')] 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 + imm8 = 0 h = (0x9 << 11) | (rt << 8) | imm8 return u16(h) def __repr__(self): - return 'LDR {}, {}'.format(self.rt, self.label.name) + return 'LDR {}, {}'.format(self.rt, self.label) -@instruction class Ldr1(ls_sp_base_imm8): """ ldr Rt, [SP, imm8] """ - mnemonic = 'LDR' opcode = 0x98 -@instruction class Str1(ls_sp_base_imm8): """ str Rt, [SP, imm8] """ - mnemonic = 'STR' opcode = 0x90 -@instruction -class Mov3(ArmInstruction): +class Mov3(ThumbInstruction): """ 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)) + assert imm < 256 + self.imm = imm self.rd = rd + self.token = ThumbToken() @classmethod def fromim(cls, im): @@ -342,10 +217,10 @@ def encode(self): rd = self.rd.num - opcode = self.opcode - imm8 = self.imm - h = (opcode << 11) | (rd << 8) | imm8 - return u16(h) + self.token[8:11] = rd + self.token[0:8] = self.imm + self.token[11:16] = self.opcode + return self.token.encode() def __repr__(self): return 'MOV {}, {}'.format(self.rd, self.imm) @@ -356,13 +231,13 @@ -class regregimm3_base(ArmInstruction): - operands = (Reg8Op, Reg8Op, Imm3) +class regregimm3_base(ThumbInstruction): def __init__(self, rd, rn, imm3): self.rd = rd self.rn = rn - assert type(imm3) is Imm3 + assert imm3 < 8 self.imm3 = imm3 + self.token = ThumbToken() @classmethod def fromim(cls, im): @@ -370,35 +245,41 @@ 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) + self.token[0:3] = rd + self.token[3:6] = self.rn.num + self.token[6:9] = self.imm3 + self.token[9:16] = self.opcode + return self.token.encode() def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm3.imm) + mnemonic = self.__class__.__name__ + return '{} {}, {}, {}'.format(mnemonic, self.rd, self.rn, self.imm3) -add_rule(['add', 'r8', ',', 'r8', ',', 'imm3'], lambda rhs: Add2(rhs[1], rhs[3], rhs[5])) -@instruction class Add2(regregimm3_base): """ add Rd, Rn, imm3 """ - mnemonic = 'add' opcode = 0b0001110 -@instruction class Sub2(regregimm3_base): """ sub Rd, Rn, imm3 """ - mnemonic = 'sub' opcode = 0b0001111 -class regregreg_base(ArmInstruction): +def Sub(*args): + if len(args) == 3 and args[0] is SP and args[1] is SP and \ + isinstance(args[2], int) and args[2] < 256: + return SubSp(args[2]) + elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ + isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ + args[2] < 8: + return Sub2(args[0], args[1], args[2]) + else: + raise Exception() + +class regregreg_base(ThumbInstruction): """ ??? Rd, Rn, Rm """ - operands = (Reg8Op, Reg8Op, Reg8Op) def __init__(self, rd, rn, rm): self.rd = rd self.rn = rn @@ -416,30 +297,24 @@ at[3:6] = rn at[6:9] = rm at[9:16] = self.opcode - #h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd - #return u16(h) return at.encode() def __repr__(self): return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) -@instruction -class Add(regregreg_base): +class Add3(regregreg_base): mnemonic = 'ADD' opcode = 0b0001100 -@instruction -class Sub(regregreg_base): +class Sub3(regregreg_base): mnemonic = 'SUB' opcode = 0b0001101 -@instruction -class Mov2(ArmInstruction): +class Mov2(ThumbInstruction): """ mov rd, rm """ - operands = (ArmRegister, ArmRegister) mnemonic = 'MOV' def __init__(self, rd, rm): self.rd = rd @@ -458,16 +333,14 @@ at[8:16] = opcode at[3:7] = Rm at[7] = D - return at.encode() # u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) + return at.encode() def __repr__(self): return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) -@instruction -class Mul(ArmInstruction): +class Mul(ThumbInstruction): """ mul Rn, Rdm """ - operands = (Reg8Op, Reg8Op) mnemonic = 'MUL' def __init__(self, rn, rdm): self.rn = rn @@ -492,12 +365,8 @@ return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) -class regreg_base(ArmInstruction): +class regreg_base(ThumbInstruction): """ ??? 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 @@ -515,118 +384,90 @@ return at.encode() def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm) + mnemonic = self.__class__.__name__ + return '{} {}, {}'.format(mnemonic, self.rdn, self.rm) -@instruction class movregreg_ins(regreg_base): """ mov Rd, Rm (reg8 operands) """ - mnemonic = 'mov' opcode = 0 -@instruction class And(regreg_base): - mnemonic = 'AND' opcode = 0b0100000000 -@instruction class Orr(regreg_base): - mnemonic = 'ORR' opcode = 0b0100001100 -@instruction class Cmp(regreg_base): - mnemonic = 'CMP' opcode = 0b0100001010 -@instruction class Lsl(regreg_base): - mnemonic = 'LSL' opcode = 0b0100000010 -@instruction -class cmpregimm8_ins(ArmInstruction): +class cmpregimm8_ins(ThumbInstruction): """ 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) + at = ThumbToken() + at[0:8] = self.imm.imm + at[8:11] = self.rn.num + at[11:16] = self.opcode + return at.encode() # Jumping: -def wrap_negative(x, bits): - b = struct.unpack('> 1, 11) - h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode + h = (0b11100 << 11) | 0 + # | 1 # 1 to enable thumb mode return u16(h) def relocations(self): - return [(self.target.name, 'wrap_new11')] + return [(self.target, 'wrap_new11')] -@instruction class Bl(jumpBase_ins): - mnemonic = 'BL' def encode(self): - imm32 = wrap_negative(self.offset >> 1, 32) - imm11 = imm32 & 0x7FF - imm10 = (imm32 >> 11) & 0x3FF + imm11 = 0 + imm10 = 0 j1 = 1 # TODO: what do these mean? j2 = 1 - s = (imm32 >> 24) & 0x1 + s = 0 h1 = (0b11110 << 11) | (s << 10) | imm10 h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 return u16(h1) + u16(h2) def relocations(self): - return [(self.target.name, 'bl_imm11_imm10')] + return [(self.target, 'bl_imm11_imm10')] class cond_base_ins(jumpBase_ins): def encode(self): - imm8 = wrap_negative(self.offset >> 1, 8) + imm8 = 0 h = (0b1101 << 12) | (self.cond << 8) | imm8 return u16(h) def relocations(self): - return [(self.target.name, 'rel8')] + return [(self.target, 'rel8')] class cond_base_ins_long(jumpBase_ins): @@ -639,123 +480,97 @@ return u16(h1) + u16(h2) def relocations(self): - return [(self.target.name, 'b_imm11_imm6')] + return [(self.target, 'b_imm11_imm6')] -@instruction class Beq(cond_base_ins): - mnemonic = 'beq' cond = 0 -@instruction class Bne(cond_base_ins): - mnemonic = 'bne' cond = 1 -@instruction class Blt(cond_base_ins): - mnemonic = 'blt' cond = 0b1011 -@instruction class Bgt(cond_base_ins): - mnemonic = 'bgt' cond = 0b1100 -@instruction -class Push(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'push' - +class Push(ThumbInstruction): def __init__(self, regs): - if type(regs) is set: - regs = RegisterSet(regs) - assert (type(regs),) == self.operands, (type(regs),) + assert type(regs) is set self.regs = regs def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) + return 'Push {{{}}}'.format(self.regs) def encode(self): - reg_list = 0 - M = 0 - for n in self.regs.registerNumbers(): + at = ThumbToken() + for n in register_numbers(self.regs): if n < 8: - reg_list |= (1 << n) + at[n] = 1 elif n == 14: - M = 1 + at[8] = 1 else: - raise NotImplementedError('not implemented for this register') - h = (0x5a << 9) | (M << 8) | reg_list - return u16(h) + raise NotImplementedError('not implemented for {}'.format(n)) + at[9:16] = 0x5a + return at.encode() + -add_rule(['pop', 'reg_list'], lambda rhs: Pop(rhs[1])) +def register_numbers(regs): + for r in regs: + yield r.num -@instruction -class Pop(ArmInstruction): - operands = (RegisterSet,) - mnemonic = 'pop' - +class Pop(ThumbInstruction): def __init__(self, regs): - if type(regs) is set: - regs = RegisterSet(regs) - assert (type(regs),) == self.operands, (type(regs),) + assert type(regs) is set self.regs = regs + self.token = ThumbToken() def __repr__(self): - return '{0} {{{1}}}'.format(self.mnemonic, self.regs) + return 'Pop {{{}}}'.format(self.regs) def encode(self): - reg_list = 0 - P = 0 - for n in self.regs.registerNumbers(): + for n in register_numbers(self.regs): if n < 8: - reg_list |= (1 << n) + self.token[n] = 1 elif n == 15: - P = 1 + self.token[8] = 1 else: raise NotImplementedError('not implemented for this register') - h = (0x5E << 9) | (P << 8) | reg_list - return u16(h) + self.token[9:16] = 0x5E + return self.token.encode() -@instruction -class Yield(ArmInstruction): - operands = () - mnemonic = 'yield' +class Yield(ThumbInstruction): 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 +class addspsp_base(ThumbInstruction): + def __init__(self, imm7): + self.imm7 = imm7 assert self.imm7 % 4 == 0 self.imm7 >>= 2 def encode(self): - return u16((self.opcode << 7) |self.imm7) + return u16((self.opcode << 7) | self.imm7) def __repr__(self): - return '{} sp, sp, {}'.format(self.mnemonic, self.imm7 << 2) + mnemonic = self.__class__.__name__ + return '{} sp, sp, {}'.format(mnemonic, self.imm7 << 2) -@instruction class AddSp(addspsp_base): - mnemonic = 'add' opcode = 0b101100000 -@instruction class SubSp(addspsp_base): - mnemonic = 'sub' opcode = 0b101100001 diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/arminstructionselector.py --- a/python/target/arminstructionselector.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/arminstructionselector.py Fri Feb 28 18:07:14 2014 +0100 @@ -8,7 +8,7 @@ from .arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3 from .arminstructions import B, Bl, Bgt, Blt, Beq, Bne from .arminstructions import Mov2, Mov3 -from .arminstructions import Add, Sub, Cmp, Sub2, Add2, Mul +from .arminstructions import Cmp, Sub2, Mul from .basetarget import Imm8, Imm7, Imm3 # Import BURG spec for arm: diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/armregisters.py --- a/python/target/armregisters.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/armregisters.py Fri Feb 28 18:07:14 2014 +0100 @@ -17,6 +17,17 @@ class Reg16Op(ArmRegister): pass +def get_register(n): + for x in registers: + if x.num == n: + return x + raise Exception() + +def register_range(a, b): + """ Return set of registers from a to b """ + assert a.num < b.num + return {get_register(n) for n in range(a.num, b.num + 1)} + R0 = Reg8Op(0, 'r0') R1 = Reg8Op(1, 'r1') @@ -26,11 +37,11 @@ R5 = Reg8Op(5, 'r5') R6 = Reg8Op(6, 'r6') R7 = Reg8Op(7, 'r7') -R7 = Reg8Op(8, 'r8') -R7 = Reg8Op(9, 'r9') -R7 = Reg8Op(10, 'r10') -R7 = Reg8Op(11, 'r11') -R7 = Reg8Op(12, 'r12') +R8 = Reg8Op(8, 'r8') +R9 = Reg8Op(9, 'r9') +R10 = Reg8Op(10, 'r10') +R11 = Reg8Op(11, 'r11') +R12 = Reg8Op(12, 'r12') # Other registers: # TODO diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/armtarget.py --- a/python/target/armtarget.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/armtarget.py Fri Feb 28 18:07:14 2014 +0100 @@ -1,11 +1,16 @@ import struct -from .basetarget import Register, Instruction, Target, Label, LabelRef +from .basetarget import Register, Instruction, Target, Label, Alignment from .basetarget import Imm32, Imm8, Imm7, Imm3 -from .arminstructions import allins, Reg8Op, ArmRegister -from .arminstructions import thumb_assembly_rules +from .arminstructions import Add2, Sub, Add3, Cmp, Lsl, Orr +from .arminstructions import Dcd, Pop, Push, Yield, Mov2, Mov3 +from .arminstructions import B, Bl, Bne, Beq, Blt, Bgt +from .arminstructions import Ldr, Str2, Ldr2, Str1, Ldr1 from .armframe import ArmFrame from .arminstructionselector import ArmInstructionSelector +from .armregisters import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC +from .armregisters import register_range + """ ARM target description. """ @@ -13,21 +18,171 @@ # TBD: is this required? # TODO: make a difference between armv7 and armv5? +thumb_assembly_rules = [] +def add_rule(rhs, f): + thumb_assembly_rules.append(('instruction', rhs, f)) -class ArmThumbTarget(Target): + +class ThumbTarget(Target): def __init__(self): - super().__init__('arm_thumb') - for i in allins: - self.addInstruction(i) - # TODO: fix this nicer? - #setattr(self, i.__name__, i) - self.check() + super().__init__('thumb') self.ins_sel = ArmInstructionSelector() self.FrameClass = ArmFrame - self.assembler_rules = thumb_assembly_rules + self.add_rules() + + def add_rules(self): + + # Add instructions: + self.add_keyword('dcd') + self.add_instruction(['dcd', 'imm32'], lambda rhs: Dcd(rhs[1])) + + self.add_keyword('mov') + self.add_instruction(['mov', 'reg8', ',', 'reg8'], + lambda rhs: Mov2(rhs[1], rhs[3])) + + self.add_instruction(['mov', 'reg8', ',', 'imm8'], + lambda rhs: Mov3(rhs[1], rhs[3])) + + self.add_keyword('add') + self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'imm3'], + lambda rhs: Add2(rhs[1], rhs[3], rhs[5])) + + self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'reg8'], + lambda rhs: Add3(rhs[1], rhs[3], rhs[5])) + + self.add_keyword('sub') + self.add_instruction(['sub', 'reg8', ',', 'reg8', ',', 'imm3'], + lambda rhs: Sub(rhs[1], rhs[3], rhs[5])) + + self.add_instruction(['sub', 'sp', ',', 'sp', ',', 'imm8'], + lambda rhs: Sub(SP, SP, rhs[5])) + + self.add_instruction(['add', 'sp', ',', 'sp', ',', 'imm8'], + lambda rhs: Sub(SP, SP, rhs[5])) + + self.add_keyword('cmp') + self.add_instruction(['cmp', 'reg8', ',', 'reg8'], + lambda rhs: Cmp(rhs[1], rhs[3])) + + self.add_keyword('lsl') + self.add_instruction(['lsl', 'reg8', ',', 'reg8'], + lambda rhs: Lsl(rhs[1], rhs[3])) + + self.add_keyword('str') + self.add_instruction(['str', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], + lambda rhs: Str2(rhs[1], rhs[4], rhs[6])) + + self.add_keyword('ldr') + self.add_instruction(['ldr', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], + lambda rhs: Ldr2(rhs[1], rhs[4], rhs[6])) + + self.add_instruction(['str', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], + lambda rhs: Str1(rhs[1], rhs[6])) + + self.add_instruction(['ldr', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], + lambda rhs: Ldr1(rhs[1], rhs[6])) + + self.add_keyword('pop') + self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1])) + self.add_keyword('push') + self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1])) + + self.add_keyword('yield') + self.add_instruction(['yield'], lambda rhs: Yield()) + + self.add_keyword('b') + self.add_keyword('bl') + self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val)) + self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val)) + self.add_keyword('beq') + self.add_keyword('bne') + self.add_keyword('blt') + self.add_keyword('bgt') + self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val)) + self.add_instruction(['bne', 'ID'], lambda rhs: Bne(rhs[1].val)) + self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val)) + self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val)) + + self.add_keyword('align') + self.add_instruction(['align', 'imm8'], lambda rhs: Alignment(rhs[1])) + + self.add_instruction(['ldr', 'reg8', ',', 'ID'], + lambda rhs: Ldr(rhs[1], rhs[3].val)) + + # Additional rules: + + # Register list grammar: + self.add_rule('reg_list', ['{', 'reg_list_inner', '}'], + lambda rhs: rhs[1]) + self.add_rule('reg_list_inner', ['reg_or_range'], + lambda rhs: rhs[0]) + self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'], + lambda rhs: rhs[0] | rhs[2]) + self.add_rule('reg_or_range', ['reg8'], lambda rhs: {rhs[0]}) + self.add_rule('reg_or_range', ['lr'], lambda rhs: {LR}) + self.add_rule('reg_or_range', ['pc'], lambda rhs: {PC}) + + self.add_rule('reg_or_range', ['reg8', '-', 'reg8'], + lambda rhs: register_range(rhs[0], rhs[2])) + + self.add_keyword('r0') + self.add_keyword('r1') + self.add_keyword('r2') + self.add_keyword('r3') + self.add_keyword('r4') + self.add_keyword('r5') + self.add_keyword('r6') + self.add_keyword('r7') + self.add_keyword('sp') + self.add_keyword('lr') + self.add_keyword('pc') + self.add_rule('reg8', ['r0'], lambda rhs: R0) + self.add_rule('reg8', ['r1'], lambda rhs: R1) + self.add_rule('reg8', ['r2'], lambda rhs: R2) + self.add_rule('reg8', ['r3'], lambda rhs: R3) + self.add_rule('reg8', ['r4'], lambda rhs: R4) + self.add_rule('reg8', ['r5'], lambda rhs: R5) + self.add_rule('reg8', ['r6'], lambda rhs: R6) + self.add_rule('reg8', ['r7'], lambda rhs: R7) + # Constants: + self.add_rule('imm32', ['val32'], lambda x: x[0].val) + self.add_rule('imm32', ['imm8'], lambda x: x[0]) + self.add_rule('imm8', ['val8'], lambda x: x[0].val) + self.add_rule('imm8', ['imm5'], lambda x: x[0]) + self.add_rule('imm5', ['val5'], lambda x: x[0].val) + self.add_rule('imm5', ['imm3'], lambda x: x[0]) + self.add_rule('imm3', ['val3'], lambda x: x[0].val) + class ArmArmTarget(Target): def __init__(self): super().__init__('arm_arm') + # Assembly grammar: + self.add_keyword('mov') + self.add_keyword('r0') + self.add_keyword('r1') + self.add_keyword('r2') + self.add_keyword('r3') + self.add_keyword('r4') + self.add_keyword('r5') + + self.add_rule('reg', ['r0'], lambda rhs: R0) + self.add_rule('reg', ['r1'], lambda rhs: R1) + self.add_rule('reg', ['r2'], lambda rhs: R2) + self.add_rule('reg', ['r3'], lambda rhs: R3) + self.add_rule('reg', ['r4'], lambda rhs: R4) + self.add_rule('reg', ['r5'], lambda rhs: R5) + + + self.add_instruction(['mov', 'reg', ',', 'imm8'], + lambda rhs: Yield()) + + self.add_rule('imm32', ['val32'], lambda x: x[0].val) + self.add_rule('imm32', ['imm8'], lambda x: x[0]) + self.add_rule('imm8', ['val8'], lambda x: x[0].val) + self.add_rule('imm8', ['imm5'], lambda x: x[0]) + self.add_rule('imm5', ['val5'], lambda x: x[0].val) + self.add_rule('imm5', ['imm3'], lambda x: x[0]) + self.add_rule('imm3', ['val3'], lambda x: x[0].val) diff -r c7cc54c0dfdf -r 4d204f6f7d4e python/target/armtoken.py --- a/python/target/armtoken.py Sun Feb 23 16:24:01 2014 +0100 +++ b/python/target/armtoken.py Fri Feb 28 18:07:14 2014 +0100 @@ -1,3 +1,8 @@ + +import struct + +def u16(h): + return struct.pack('