changeset 201:d5debbfc0200

Added all 27 core instructions of msp430
author Windel Bouwman
date Thu, 13 Jun 2013 00:07:28 +0200
parents 5e391d9a3381
children f22b431f4113
files python/asmnodes.py python/msp430.py python/target.py python/testasm.py
diffstat 4 files changed, 306 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/python/asmnodes.py	Sun Jun 09 16:06:49 2013 +0200
+++ b/python/asmnodes.py	Thu Jun 13 00:07:28 2013 +0200
@@ -52,6 +52,7 @@
     def __init__(self, n):
         assert type(n) is int
         self.n = n
+        self.number = n
     def __repr__(self):
         return '{0}'.format(self.n)
 
--- a/python/msp430.py	Sun Jun 09 16:06:49 2013 +0200
+++ b/python/msp430.py	Thu Jun 13 00:07:28 2013 +0200
@@ -1,4 +1,31 @@
 from target import Register, Instruction, Target
+from asmnodes import ASymbol, ANumber
+from ppci import CompilerError
+import struct, types
+
+# Create the target class (singleton):
+msp430target = Target("MSP430")
+
+REGISTER_MODE = 1
+#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
 
@@ -9,41 +36,263 @@
 
 # 8 bit registers:
 PCB = MSP430Reg(0, 'r0')
+rpc = PCB
+r11 = MSP430Reg(11, 'r11')
+r12 = MSP430Reg(12, 'r12')
 r13 = MSP430Reg(13, 'r13')
 r14 = MSP430Reg(14, 'r14')
 r15 = MSP430Reg(15, 'r15')
 
+class MSP430Mem:
+    pass
+
+msp430target.registers.append(r11)
+msp430target.registers.append(r12)
+msp430target.registers.append(r13)
+msp430target.registers.append(r14)
+msp430target.registers.append(r15)
+
 # .. etc
 
 #GR8 = RegisterClass((PCB, R15B))
 
-# Two operand arithmatic instructions:
+class MSP430Operand:
+    def __init__(self, mode, param):
+        self.mode = mode
+        self.param = param
+    def regField(self):
+        if self.mode == REGISTER_MODE:
+            return self.param
+        elif self.mode == IMMEDIATE_MODE:
+            return rpc.num
+    def asField(self):
+        if self.mode == REGISTER_MODE:
+            return 0
+        elif self.mode == IMMEDIATE_MODE:
+            return 3
+    def adField(self):
+        if self.mode == REGISTER_MODE:
+            return 0
+        elif self.mode == IMMEDIATE_MODE:
+            raise CompilerError('Cannot use immediate mode for destination operand')
+    def extraBytes(self):
+        if self.mode == IMMEDIATE_MODE:
+            return pack_ins(self.param)
+        return bytes()
+        
 
-class TwoOpArith(Instruction):
-    operands = (MSP430Reg, MSP430Reg)
-    def __init__(self, op1, op2):
+def pack_ins(h):
+    return struct.pack('<H', h)
+
+class MSP430Instruction(Instruction):
+    b = 0
+
+class BInstruction:
+    pass
+
+class MSP430CoreInstruction(Instruction):
+    pass
+
+#########################
+# Single operand arithmatic:
+#########################
+
+@msp430target.instruction
+class reti_ins(MSP430Instruction):
+    mnemonic = 'reti'
+    operands = ()
+    def encode(self):
+        h = 0x1300
+        return pack_ins(h)
+
+class OneOpArith(MSP430Instruction):
+    operands = (MSP430Reg, )
+    def __init__(self, op1):
         self.op1 = op1
-        self.op2 = op2
     def encode(self):
         # TODO:
-        b1 = (self.opcode << 4)
-        b2 = 0
-        ba = bytearray([b1, b2])
-        return bytes(ba)
+        bits[15:10] = '00100'
+        h1 = (self.opcode << 4)
+        return pack_ins(h1)
+
+@msp430target.instruction
+class rrc_ins(OneOpArith):
+    mnemonic = 'rrc'
+    opcode = 0
+
+@msp430target.instruction
+class swpb_ins(OneOpArith):
+    mnemonic = 'swpb'
+    opcode = 1
+
+@msp430target.instruction
+class rra_ins(OneOpArith):
+    mnemonic = 'rra'
+    opcode = 2
+
+@msp430target.instruction
+class sxt_ins(OneOpArith):
+    mnemonic = 'sxt'
+    opcode = 3
+
+@msp430target.instruction
+class push_ins(OneOpArith):
+    mnemonic = 'push'
+    opcode = 4
+
+@msp430target.instruction
+class call_ins(OneOpArith):
+    mnemonic = 'call'
+    opcode = 5
+
+#########################
+# Jump instructions:
+#########################
+
+class JumpInstruction(Instruction):
+    def __init__(self, offset):
+        self.offset = offset
+
+    def encode(self):
+        h = (1 << 13) | (self.condition << 10) | (self.offset)
+        return pack_ins(h)
+
+@msp430target.instruction
+class jnz_ins(JumpInstruction):
+    mnemonic = 'jnz'
+    condition = 0
+
+@msp430target.instruction
+class jz_ins(JumpInstruction):
+    mnemonic = 'jz'
+    condition = 1
+
+@msp430target.instruction
+class jnc_ins(JumpInstruction):
+    mnemonic = 'jnc'
+    condition = 2
 
+@msp430target.instruction
+class jc_ins(JumpInstruction):
+    mnemonic = 'jc'
+    condition = 3
+
+@msp430target.instruction
+class jn_ins(JumpInstruction):
+    mnemonic = 'jn'
+    condition = 4
+
+@msp430target.instruction
+class jge_ins(JumpInstruction):
+    mnemonic = 'jge'
+    condition = 5
+
+@msp430target.instruction
+class jl_ins(JumpInstruction):
+    mnemonic = 'jl'
+    condition = 6
+
+@msp430target.instruction
+class jmp_ins(JumpInstruction):
+    mnemonic = 'jmp'
+    condition = 7
+
+#########################
+# Two operand arithmatic instructions:
+#########################
+
+
+class TwoOpArith(MSP430Instruction):
+    operands = (MSP430Operand, MSP430Operand)
+    def __init__(self, src, dst):
+        self.op1 = src
+        self.op2 = dst
+
+    def encode(self):
+        """
+            Smart things have been done by MSP430 designers.
+            As (2 bits) is the source addressing mode selector.
+            Ad (1 bit) is the destination adressing mode selector.
+            For the source there are 7 different addressing mode.
+            For the destination there are 4.
+            The trick is to use also the register to distuingish the
+            different modes.
+
+        """
+        # TODO: Make memory also possible
+
+        As = self.op1.asField() # addressing mode for the source
+        Ad = self.op2.adField() # Addressing mode for dst
+        b = self.b # When b=1, the operation is byte mode
+        source = self.op1.regField()
+        destination = self.op2.regField()
+        h = (self.opcode << 12) | (source << 8)
+        h |= (self.b << 6) | (As << 4) | (Ad << 7) | destination
+        additions = self.op1.extraBytes() + self.op2.extraBytes()
+        return pack_ins(h) + additions
+
+    def decode(self, data):
+        pass
+
+@msp430target.instruction
 class mov_ins(TwoOpArith):
-    # class variables:
     mnemonic = 'mov'
     opcode = 4
 
+@msp430target.instruction
 class add_ins(TwoOpArith):
     mnemonic = 'add'
     opcode = 5
 
-class MSP430(Target):
-    def __init__(self):
-        self.registers = [PCB, r13, r14, r15]
-        self.instructions = [mov_ins, add_ins]
+@msp430target.instruction
+class addc_ins(TwoOpArith):
+    mnemonic = 'addc'
+    opcode = 6
+
+@msp430target.instruction
+class subc_ins(TwoOpArith):
+    mnemonic = 'subc'
+    opcode = 7
+
+@msp430target.instruction
+class sub_ins(TwoOpArith):
+    mnemonic = 'sub'
+    opcode = 8
+
+@msp430target.instruction
+class cmp_ins(TwoOpArith):
+    """ Compare, substract source from destination """
+    mnemonic = 'cmp'
+    opcode = 9
 
-t = MSP430()
+@msp430target.instruction
+class dadd_ins(TwoOpArith):
+    """ Decimal add source to destination """
+    mnemonic = 'dadd'
+    opcode = 10
+
+@msp430target.instruction
+class bit_ins(TwoOpArith):
+    mnemonic = 'bit'
+    opcode = 11
+
+@msp430target.instruction
+class bic_ins(TwoOpArith):
+    mnemonic = 'bic'
+    opcode = 12
 
+@msp430target.instruction
+class bis_ins(TwoOpArith):
+    mnemonic = 'bis'
+    opcode = 13
+
+@msp430target.instruction
+class xor_ins(TwoOpArith):
+    mnemonic = 'xor'
+    opcode = 14
+
+@msp430target.instruction
+class and_ins(TwoOpArith):
+    mnemonic = 'and'
+    opcode = 15
+
--- a/python/target.py	Sun Jun 09 16:06:49 2013 +0200
+++ b/python/target.py	Thu Jun 13 00:07:28 2013 +0200
@@ -15,14 +15,21 @@
         self.name = name
 
 class Instruction:
-   def __init__(self, opcode):
-      self.opcode = opcode
+    def encode(self):
+        raise NotImplementedError('TODO')
 
 class Target:
-    def __init__(self):
+    def __init__(self, name, desc=''):
+        self.name = name
+        self.desc = desc
         self.registers = []
         self.instructions = []
 
+    def instruction(self, cls):
+        """ Decorator function that registers an instruction to this target """
+        self.instructions.append(cls)
+        return cls
+
     def mapOperand(self, operand):
         """ Try to map an operand to a target type """
         if type(operand) is ASymbol:
@@ -32,8 +39,7 @@
                 regs[r.name] = r
             if operand.name in regs:
                 return regs[operand.name]
-        else:
-            return
+        raise CompilerError('Cannot map {0}'.format(operand))
 
     def mapInstruction(self, vi):
         """ Map ast tree to real instruction for this target """
@@ -47,5 +53,5 @@
             if ic.mnemonic == vi.opcode and ic.operands == optypes:
                 ri = ic(*rops)
                 return ri
-        raise CompilerError('No suitable instruction found')
+        raise CompilerError('No suitable instruction found for "{0}"'.format(vi))
 
--- a/python/testasm.py	Sun Jun 09 16:06:49 2013 +0200
+++ b/python/testasm.py	Thu Jun 13 00:07:28 2013 +0200
@@ -2,7 +2,8 @@
 
 import unittest, cProfile
 from ppci import CompilerError
-from asm import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber, tokenize, Assembler
+from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber
+from asm import tokenize, Assembler
 import msp430
 
 class AssemblerLexingCase(unittest.TestCase):
@@ -83,6 +84,7 @@
         a = Assembler()
         with self.assertRaises(CompilerError):
             a.assemble_line('')
+
     @unittest.skip 
     def testX86(self):
         testsrc = """ ; tst
@@ -98,18 +100,24 @@
 
 class AssemblerMSP430TestCase(unittest.TestCase):
     def setUp(self):
-        self.t = msp430.MSP430()
+        self.t = msp430.msp430target
         self.a = Assembler(target=self.t)
 
-    def testMapInstruction(self):
+    def testMapMovInstruction(self):
         i = AInstruction('mov', [ASymbol('r14'), ASymbol('r15')])
-        self.t.mapInstruction(i)
+        ri = self.t.mapInstruction(i)
 
+    def testMapRetiInstruction(self):
+        i = AInstruction('reti', [])
+        ri = self.t.mapInstruction(i)
+
+    @unittest.skip
     def testMapOperand(self):
         o = ASymbol('r14')
         mo = self.t.mapOperand(o)
         self.assertEqual(mo, msp430.r14)
 
+    @unittest.skip
     def testMapOperandIndirection(self):
         o = AUnop('[]', ASymbol('r14'))
         mo = self.t.mapOperand(o)
@@ -117,10 +125,26 @@
     def testMov(self):
         line1 = "mov r14, r15"
         self.a.assemble_line(line1)
+        self.assertEqual(bytes([0x0F, 0x4E]), self.a.binout)
+
+    def testMov1337(self):
+        line1 = "mov 0x1337, r12"
+        self.a.assemble_line(line1)
+        self.assertEqual(bytes([0x3C, 0x40, 0x37, 0x13]), self.a.binout)
 
     def testAdd(self):
-        line1 = "add r14, r15"
+        line1 = "add r15, r13"
         self.a.assemble_line(line1)
+        self.assertEqual(bytes([0x0D, 0x5F]), self.a.binout)
+
+    def testReti(self):
+        line1 = "reti"
+        self.a.assemble_line(line1)
+        self.assertEqual(bytes([0x0, 0x13]), self.a.binout)
+
+    def testMSPinstructionCount(self):
+        """ Check that there are 27 instructions """
+        self.assertEqual(27, len(self.t.instructions))
 
 
 if __name__ == '__main__':