changeset 206:6c6bf8890d8a

Added push and pop encodings
author Windel Bouwman
date Fri, 28 Jun 2013 16:49:38 +0200
parents d77cb5962cc5
children 8b2f20aae086
files python/arm_cm3.py python/asm.py python/asmnodes.py python/target.py python/testasm.py
diffstat 5 files changed, 175 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- 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()
+
--- 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):
--- 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):
--- 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)
 
--- 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