changeset 203:ca1ea402f6a1

Added some arm instructions
author Windel Bouwman
date Sat, 15 Jun 2013 19:13:05 +0200
parents f22b431f4113
children de3a68f677a5
files python/arm_cm3.py python/asm.py python/asmnodes.py python/msp430.py python/target.py python/testasm.py python/thex.py
diffstat 7 files changed, 152 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/python/arm_cm3.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/arm_cm3.py	Sat Jun 15 19:13:05 2013 +0200
@@ -8,25 +8,6 @@
 
 armtarget = Target('arm')
 
-# Add a custom operand mapping method:
-def mapOp(self, operand):
-    if type(operand) is ASymbol:
-        # try to map to register:
-        regs = {}
-        for r in self.registers:
-            regs[r.name] = r
-        if operand.name in regs:
-            reg = regs[operand.name]
-            return reg
-    elif type(operand) is ANumber:
-        return ArmImm(operand.number)
-    raise CompilerError('Cannot map {0}'.format(operand))
-
-armtarget.mapOperand = types.MethodType(mapOp, armtarget)
-
-# Define:
-registers = 'r0,r1,r2,r3,r4,r5'
-
 class ArmReg(Register):
     def __init__(self, num, name):
         super().__init__(name)
@@ -36,9 +17,52 @@
     def __init__(self, i):
         self.i = i
 
+class RegOp:
+    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]
+                return cls(r.num)
+
+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)
+
 # 8 bit registers:
 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)
 
 class ArmInstruction(Instruction):
     pass
@@ -49,15 +73,21 @@
     opcode = 1337
 
 
+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 """
     mnemonic = 'mov'
-    opcode = 4 # 00100
-    operands = (ArmReg, ArmImm)
-    def __init__(self, r, imm):
-        self.imm = imm.i
-        self.r = r.num
+    opcode = 4 # 00100 Rd(3) imm8
+    operands = (RegOp, Imm8)
+    def __init__(self, rd, imm):
+        self.imm = imm.imm
+        self.r = rd.num
     def encode(self):
         rd = self.r
         opcode = self.opcode
@@ -65,6 +95,59 @@
         h = (opcode << 11) | (rd << 8) | imm8
         return u16(h)
         
+@armtarget.instruction
+class movregreg_ins(ArmInstruction):
+    """ mov Rd, Rm """
+    mnemonic = 'mov'
+    opcode = 8 # 01000 Rd(3) imm8
+    operands = (RegOp, RegOp)
+    def __init__(self, rd, rm):
+        self.rd = rd
+        self.rm = rm
+    def encode(self):
+        rd = self.rd.num
+        D = (rd & 0x8) >> 3
+        assert D < 2
+        rd = rd & 0x7
+        rm = self.rm.num
+        assert rm < 16
+        opcode = self.opcode
+        h = (opcode << 11) | (3 << 9) | (D << 7) | (rm << 3) | rd
+        return u16(h)
+
+@armtarget.instruction
+class addregregimm3_ins(ArmInstruction):
+    """ add Rd, Rn, imm3 """
+    mnemonic = 'add'
+    opcode = 3 # 00011
+    operands = (RegOp, RegOp, Imm3)
+    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)
+
+@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)
 
 @armtarget.instruction
 class yield_ins(ArmInstruction):
--- a/python/asm.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/asm.py	Sat Jun 15 19:13:05 2013 +0200
@@ -160,10 +160,11 @@
             raise CompilerError('Cannot assemble without target')
         while self.output:
             vi = self.output.pop(0)
-            ri = self.target.mapInstruction(vi)
-            b = ri.encode()
-            assert type(b) is bytes
-            self.binout.extend(b)
+            if type(vi) is AInstruction:
+                ri = self.target.mapInstruction(vi)
+                b = ri.encode()
+                assert type(b) is bytes
+                self.binout.extend(b)
 
     def back_patch(self):
         """ Fix references to earlier labels """
--- a/python/asmnodes.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/asmnodes.py	Sat Jun 15 19:13:05 2013 +0200
@@ -12,12 +12,12 @@
         return '{0}:'.format(self.name)
 
 class AInstruction(ANode):
-    def __init__(self, opcode, operands):
-        self.opcode = opcode
+    def __init__(self, mnemonic, operands):
+        self.mnemonic = mnemonic
         self.operands = operands
     def __repr__(self):
         ops = ', '.join(map(str, self.operands))
-        return '{0} {1}'.format(self.opcode, ops)
+        return '{0} {1}'.format(self.mnemonic, ops)
 
 class AExpression(ANode):
     def __add__(self, other):
--- a/python/msp430.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/msp430.py	Sat Jun 15 19:13:05 2013 +0200
@@ -12,25 +12,6 @@
 #TODO: add more modes!
 IMMEDIATE_MODE = 7
 
-
-
-# Add a custom operand mapping method:
-def mapOp(self, operand):
-    if type(operand) is ASymbol:
-        # try to map to register:
-        regs = {}
-        for r in self.registers:
-            regs[r.name] = r
-        if operand.name in regs:
-            reg = regs[operand.name]
-            return MSP430Operand(REGISTER_MODE, reg.num)
-    elif type(operand) is ANumber:
-        # Immediate mode:
-        return MSP430Operand(IMMEDIATE_MODE, operand.number)
-    raise CompilerError('Cannot map {0}'.format(operand))
-
-msp430target.mapOperand = types.MethodType(mapOp, msp430target)
-
 # Target description for the MSP430 processor
 
 class MSP430Reg(Register):
@@ -83,7 +64,20 @@
         if self.mode == IMMEDIATE_MODE:
             return pack_ins(self.param)
         return bytes()
-        
+    
+    @classmethod
+    def Create(cls, vop):
+        if type(vop) is ASymbol:
+            # try to map to register:
+            regs = {}
+            for r in msp430target.registers:
+                regs[r.name] = r
+            if vop.name in regs:
+                reg = regs[vop.name]
+                return cls(REGISTER_MODE, reg.num)
+        elif type(vop) is ANumber:
+            # Immediate mode:
+            return cls(IMMEDIATE_MODE, vop.number)
 
 def pack_ins(h):
     return struct.pack('<H', h)
--- a/python/target.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/target.py	Sat Jun 15 19:13:05 2013 +0200
@@ -1,4 +1,4 @@
-from asmnodes import ASymbol, AInstruction
+from asmnodes import ASymbol, AInstruction, ALabel
 from ppci import CompilerError
 
 """
@@ -45,16 +45,20 @@
         raise CompilerError('Cannot map {0}'.format(operand))
 
     def mapInstruction(self, vi):
+        assert type(vi) is AInstruction
         """ Map ast tree to real instruction for this target """
 
         # map to real operands:
-        rops = tuple(map(self.mapOperand, vi.operands))
-        optypes = tuple(map(type, rops))
 
         # look for a suitable instruction
         for ic in self.instructions:
-            if ic.mnemonic == vi.opcode and ic.operands == optypes:
-                ri = ic(*rops)
-                return ri
+            if ic.mnemonic == vi.mnemonic and len(ic.operands) == len(vi.operands):
+                # Try to map operands to the correct operand types:
+                rops = [roptype.Create(vop) for roptype, vop in zip(ic.operands, vi.operands)]
+
+                # Check if we succeeded:
+                optypes = tuple(map(type, rops))
+                if ic.operands == optypes:
+                    return ic(*rops)
         raise CompilerError('No suitable instruction found for "{0}"'.format(vi))
 
--- a/python/testasm.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/testasm.py	Sat Jun 15 19:13:05 2013 +0200
@@ -164,8 +164,17 @@
         self.a.assemble('yield')
         self.assertEqual(bytes.fromhex('10bf'), self.a.binout)
 
+    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.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
+
 
 if __name__ == '__main__':
-    # cProfile.run('unittest.main()')
+    #cProfile.run('unittest.main()')
     unittest.main()
 
--- a/python/thex.py	Sat Jun 15 10:02:50 2013 +0200
+++ b/python/thex.py	Sat Jun 15 19:13:05 2013 +0200
@@ -12,6 +12,9 @@
         self.bv = self.ui.he.bv
         # Provide some random data:
         self.bv.Data = bytearray(range(10)) * 8 + b'x'
+    def tearDown(self):
+        self.app.processEvents()
+        self.app.quit()
     def testOpenButton(self):
         QTest.mouseClick(self.bv, Qt.LeftButton)
         self.assertEqual(self.bv.CursorPosition, 161)