diff python/target/arminstructions.py @ 341:4d204f6f7d4e devel

Rewrite of assembler parts
author Windel Bouwman
date Fri, 28 Feb 2014 18:07:14 +0100
parents c7cc54c0dfdf
children
line wrap: on
line diff
--- 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('<H', h)
@@ -16,7 +15,6 @@
     return struct.pack('<I', x)
 
 
-thumb_assembly_rules = []
 arm_assembly_rules = []
 
 
@@ -55,120 +53,15 @@
         return x.number
 
 
-class MemRegXRel:
-    def __init__(self, offset):
-        assert offset % 4 == 0
-        self.offset = offset
 
-    def __repr__(self):
-        return '[{}, #{}]'.format(self.regname, self.offset)
-
-    @classmethod
-    def Create(cls, vop):
-        if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+':
-            vop = vop.arg # descent
-            offset = isRegOffset(cls.regname, vop.arg1, vop.arg2)
-            if type(offset) is int:
-                if offset % 4 == 0:
-                    offset = vop.arg2.number
-                    return cls(offset)
-            elif type(vop) is ASymbol and vop.name.upper() == self.regname:
-                return cls(0)
-
-
-class MemSpRel(MemRegXRel):
-    regname = 'SP'
-
-
-class MemR8Rel:
-    def __init__(self, basereg, offset):
-        assert type(basereg) is Reg8Op
-        assert type(offset) is int
-        self.basereg = basereg
-        self.offset = offset
-
-    def __repr__(self):
-        return '[{}, #{}]'.format(self.basereg, self.offset)
+# Instructions:
 
-    @classmethod
-    def Create(cls, vop):
-        if type(vop) is AUnop and vop.operation == '[]':
-            vop = vop.arg # descent
-            if type(vop) is ABinop:
-                if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber:
-                    offset = vop.arg2.number
-                    if offset > 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('<I', struct.pack('<i', x))[0]
-    mask = (1 << bits) - 1
-    return b & mask
-
-class jumpBase_ins(ArmInstruction):
-    operands = (LabelRef,)
+class jumpBase_ins(ThumbInstruction):
     def __init__(self, target_label):
-        assert type(target_label) is LabelRef
         self.target = target_label
         self.offset = 0
 
     def __repr__(self):
-        return '{} {}'.format(self.mnemonic, self.target.name)
+        mnemonic = self.__class__.__name__
+        return '{} {}'.format(mnemonic, self.target)
 
 
-class Imm11Reloc:
-    def apply(self, P, S):
-        pass
-
-
-@instruction
 class B(jumpBase_ins):
-    mnemonic = 'B'
     def encode(self):
-        imm11 = wrap_negative(self.offset >> 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