# HG changeset patch # User Windel Bouwman # Date 1372430978 -7200 # Node ID 6c6bf8890d8ac6cd8baa58185d109295746001f8 # Parent d77cb5962cc563e52bd99b554a671dc11fa494d3 Added push and pop encodings diff -r d77cb5962cc5 -r 6c6bf8890d8a python/arm_cm3.py --- a/python/arm_cm3.py Sun Jun 23 18:23:18 2013 +0200 +++ b/python/arm_cm3.py Fri Jun 28 16:49:38 2013 +0200 @@ -1,6 +1,6 @@ import struct, types -from target import Register, Instruction, Target -from asmnodes import ASymbol, ANumber +from target import Register, Instruction, Target, Imm8, Label, Imm3 +from asmnodes import ASymbol, ANumber, AUnop, ABinop from ppci import CompilerError import ir @@ -16,14 +16,12 @@ def __init__(self, num, name): super().__init__(name) self.num = num - -class ArmImm: - def __init__(self, i): - self.i = i + def __repr__(self): + return self.name class RegOp: def __init__(self, num): - assert num < 8 + assert num < 16 self.num = num @classmethod @@ -37,44 +35,62 @@ r = regs[name] return cls(r.num) -class Label: - def __init__(self, name): - self.name = name - - @classmethod - def Create(cls, vop): - if type(vop) is ASymbol: - name = vop.name - return cls(name) - -class Imm8: - def __init__(self, imm): - assert imm < 256 - self.imm = imm +def getRegNum(n): + for r in armtarget.registers: + if r.num == n: + return r - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 256: - return cls(vop.number) - -class Imm3: - def __init__(self, imm): - assert imm < 8 - assert type(imm) is int - self.imm = imm - - @classmethod - def Create(cls, vop): - if type(vop) is ANumber and vop.number < 8: - return cls(vop.number) +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 class RegisterSet: def __init__(self, regs): - pass + 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') @@ -83,17 +99,23 @@ 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 ldr_ins(ArmInstruction): mnemonic = 'ldr' opcode = 1337 irpattern = 'todo' -@armtarget.instruction class dcd_ins(ArmInstruction): mnemonic = 'dcd' def __init__(self, expr): @@ -101,12 +123,6 @@ def encode(self): return u32(self.expr) -class Operand2: - def __init__(self, expr): - if type(expr) is ANumber: - pass - pass - @armtarget.instruction class mov_ins(ArmInstruction): """ mov Rd, imm8, move immediate value into register """ @@ -186,7 +202,7 @@ @armtarget.instruction class jmp_ins(ArmInstruction): - operands = (Label) + operands = (Label,) mnemonic = 'jmp' def __init__(self, target_label): self.target = target_label @@ -198,20 +214,45 @@ @armtarget.instruction class push_ins(ArmInstruction): - operands = (RegisterSet) + operands = (RegisterSet,) mnemonic = 'push' def __init__(self, regs): + print(self.operands) + assert (type(regs),) == self.operands, (type(regs),) self.regs = regs + def __repr__(self): + return '{0} {{{1}}}'.format(self.mnemonic, self.regs) def encode(self): - return u16(0) + 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) + operands = (RegisterSet,) mnemonic = 'pop' def __init__(self, regs): self.regs = 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) return u16(0) @armtarget.instruction @@ -221,3 +262,5 @@ def encode(self): return u16(0xbf10) +armtarget.check() + diff -r d77cb5962cc5 -r 6c6bf8890d8a python/asm.py --- a/python/asm.py Sun Jun 23 18:23:18 2013 +0200 +++ b/python/asm.py Fri Jun 28 16:49:38 2013 +0200 @@ -17,7 +17,7 @@ ('NUMBER', r'\d+'), ('ID', r'[A-Za-z][A-Za-z\d_]*'), ('SKIP', r'[ \t]'), - ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<'), + ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{'), ('STRING', r"'.*?'"), ('COMMENT', r";.*") ] @@ -73,7 +73,7 @@ self.restart() # Construct a parser given a grammar: ident = lambda x: x # Identity helper function - g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT']) + g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}']) g.add_production('asmline', ['asmline2']) g.add_production('asmline', ['asmline2', 'COMMENT']) g.add_production('asmline2', ['label', 'instruction']) @@ -90,6 +90,9 @@ g.add_production('operands', ['operands', ',', 'operand'], self.p_operands_2) g.add_production('operand', ['expression'], ident) g.add_production('operand', ['[', 'expression', ']'], self.p_mem_op) + g.add_production('operand', ['{', 'listitems', '}'], self.p_list_op) + g.add_production('listitems', ['expression'], self.p_listitems_1) + g.add_production('listitems', ['listitems', ',', 'expression'], self.p_listitems_2) g.add_production('expression', ['term'], ident) g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) g.add_production('addop', ['-'], ident) @@ -114,6 +117,17 @@ assert type(ops) is list ops.append(op2) return ops + + def p_listitems_1(self, li1): + return [li1] + + def p_listitems_2(self, lis, comma, li2): + assert type(lis) is list + lis.append(li2) + return lis + + def p_list_op(self, brace_open, lst, brace_close): + return AUnop('{}', lst) def p_mem_op(self, brace_open, exp, brace_close): return AUnop('[]', exp) def p_label(self, lname, cn): diff -r d77cb5962cc5 -r 6c6bf8890d8a python/asmnodes.py --- a/python/asmnodes.py Sun Jun 23 18:23:18 2013 +0200 +++ b/python/asmnodes.py Fri Jun 28 16:49:38 2013 +0200 @@ -36,11 +36,11 @@ return '{0} {1} {2}'.format(self.op, self.arg1, self.arg2) class AUnop(AExpression): - def __init__(self, op, arg): - self.op = op + def __init__(self, operation, arg): + self.operation = operation self.arg = arg def __repr__(self): - return '{0} {1}'.format(self.op, self.arg) + return '{0} {1}'.format(self.operation, self.arg) class ASymbol(AExpression): def __init__(self, name): diff -r d77cb5962cc5 -r 6c6bf8890d8a python/target.py --- a/python/target.py Sun Jun 23 18:23:18 2013 +0200 +++ b/python/target.py Fri Jun 28 16:49:38 2013 +0200 @@ -1,4 +1,4 @@ -from asmnodes import ASymbol, AInstruction, ALabel +from asmnodes import ASymbol, AInstruction, ALabel, ANumber from ppci import CompilerError """ @@ -10,6 +10,39 @@ """ Single machine operand """ pass +# standard immediates: + +class Imm8: + def __init__(self, imm): + assert imm < 256 + self.imm = imm + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 256: + return cls(vop.number) + +class Imm3: + def __init__(self, imm): + assert imm < 8 + assert type(imm) is int + self.imm = imm + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 8: + return cls(vop.number) + +class Label: + def __init__(self, name): + self.name = name + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + name = vop.name + return cls(name) + class Register(Operand): def __init__(self, name): self.name = name @@ -30,6 +63,14 @@ self.addInstruction(cls) return cls + def check(self): + """ Check target """ + for i in self.instructions: + assert hasattr(i, 'mnemonic') + assert hasattr(i, 'operands'), str(i) + assert type(i.mnemonic) is str + assert type(i.operands) is tuple, str(i) + def addInstruction(self, ins_class): self.instructions.append(ins_class) diff -r d77cb5962cc5 -r 6c6bf8890d8a python/testasm.py --- a/python/testasm.py Sun Jun 23 18:23:18 2013 +0200 +++ b/python/testasm.py Fri Jun 28 16:49:38 2013 +0200 @@ -153,22 +153,36 @@ self.t = arm_cm3.armtarget self.a = Assembler(target=self.t) + def feed(self, line): + self.a.assemble(line) + + def check(self, hexstr): + self.assertEqual(bytes.fromhex(hexstr), self.a.binout) + def testMapOperand(self): pass def testMovImm8(self): - self.a.assemble('mov r4, 100') - self.assertEqual(bytes.fromhex('6424'), self.a.binout) + self.feed('mov r4, 100') + self.check('6424') def testYield(self): - self.a.assemble('yield') - self.assertEqual(bytes.fromhex('10bf'), self.a.binout) + self.feed('yield') + self.check('10bf') + + def testPush(self): + self.feed('push {r2,r3,lr}') + self.check('0cb5') + + def testPop(self): + self.feed('pop {r4-r6, pc}') + self.check('70bd') def testSequence1(self): - self.a.assemble('mov r5, 3') - self.a.assemble('add r4, r5, 0') - self.a.assemble('loop: add r6, r4, 7') - self.a.assemble('cmp r6, 5') + self.feed('mov r5, 3') + self.feed('add r4, r5, 0') + self.feed('loop: add r6, r4, 7') + self.feed('cmp r6, 5') #self.a.assemble('ble loop') #self.assertEqual(bytes.fromhex('0325 2c1c e61d 052e fcdd'), self.a.binout) self.assertEqual(bytes.fromhex('0325 2c1c e61d 052e'), self.a.binout) # without branch