changeset 346:3bb7dcfe5529

expanded arm target
author Windel Bouwman
date Fri, 07 Mar 2014 17:05:32 +0100
parents b4882ff0ed06
children 742588fb8cd6 442fb043d149
files examples/c3/burn.c3proj examples/qemu_a9_hello/hello.c3 examples/qemu_a9_hello/recipe.yaml examples/qemu_a9_hello/startup.s examples/qemu_a9_hello/startup_a9.asm python/ppci/asmnodes.py python/ppci/assembler.py python/ppci/bitfun.py python/ppci/buildtasks.py python/ppci/codegen/codegen.py python/ppci/irmach.py python/ppci/outstream.py python/ppci/target/__init__.py python/ppci/target/arm/__init__.py python/ppci/target/arm/arm.brg python/ppci/target/arm/frame.py python/ppci/target/arm/instructions.py python/ppci/target/arm/selector.py python/ppci/target/basetarget.py python/ppci/target/instructionselector.py python/ppci/target/msp430/msp430.py python/ppci/target/thumb/armframe.py python/ppci/target/thumb/armtarget.py python/ppci/target/thumb/frame.py python/ppci/target/thumb/instructions.py python/ppci/tasks.py python/pyyacc.py test/m3_bare/recipe.yaml test/setenv.sh test/testarmasm.py test/testasm.py test/testbitfun.py test/testemulation.py test/testmsp430asm.py test/testregalloc.py test/testthumbasm.py test/testzcc.py util/serve_arm_as.py util/test_patterns.txt
diffstat 39 files changed, 843 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/examples/c3/burn.c3proj	Sun Mar 02 17:12:08 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-[Burn]
-srcs = burn2.c3
-imps = stm32f4xx.c3
-target = arm
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/hello.c3	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,21 @@
+module hello;
+
+function void main()
+{
+  var int* UART0DR;
+  UART0DR = cast<int*>(0x10009000); // UART0 Data register
+  *UART0DR = 72;
+  *UART0DR = 101;
+  *UART0DR = 108;
+  *UART0DR = 108;
+  *UART0DR = 111;
+  *UART0DR = 32;
+  *UART0DR = 119;
+  *UART0DR = 111;
+  *UART0DR = 114;
+  *UART0DR = 108;
+  *UART0DR = 101;
+
+    while(true) {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/recipe.yaml	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,16 @@
+
+
+link:
+  inputs:
+    - assemble:
+       source: startup_a9.asm
+       machine: arm
+    - compile:
+       sources: [hello.c3]
+       includes: []
+       machine: arm
+  layout:
+     code: 0x60010000
+     data: 0x60020000
+  output: hello.bin
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/startup.s	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,8 @@
+
+
+.global _Reset;
+_Reset:
+ LDR sp, =stack_top
+ BL start
+ B .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/startup_a9.asm	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,7 @@
+
+; DCD 0x20000678  ; Setup stack pointer
+; DCD 0x06daa0e3 ; mov sp, #0x60 << 8
+mov sp, 0x30000
+BL hello_main          ; Branch to main (this is actually in the interrupt vector)
+local_loop:
+B local_loop
--- a/python/ppci/asmnodes.py	Sun Mar 02 17:12:08 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-
-""" Assembler AST nodes """
-
-class ANode:
-    def __eq__(self, other):
-        return self.__repr__() == other.__repr__()
-
-class ALabel(ANode):
-    def __init__(self, name):
-        self.name = name
-    def __repr__(self):
-        return '{0}:'.format(self.name)
-
-
-class AInstruction(ANode):
-    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.mnemonic, ops)
-
-class AExpression(ANode):
-    def __add__(self, other):
-        assert isinstance(other, AExpression)
-        return ABinop('+', self, other)
-    def __mul__(self, other):
-        assert isinstance(other, AExpression)
-        return ABinop('*', self, other)
-
-class ABinop(AExpression):
-    def __init__(self, op, arg1, arg2):
-        self.op = op
-        self.arg1 = arg1
-        self.arg2 = arg2
-    def __repr__(self):
-        return '{0} {1} {2}'.format(self.op, self.arg1, self.arg2)
-
-class AUnop(AExpression):
-    def __init__(self, operation, arg):
-        self.operation = operation
-        self.arg = arg
-    def __repr__(self):
-        return '{0} {1}'.format(self.operation, self.arg)
-
-class ASymbol(AExpression):
-    def __init__(self, name):
-        self.name = name
-    def __repr__(self):
-        return self.name
-
-class ANumber(AExpression):
-    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/ppci/assembler.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/assembler.py	Fri Mar 07 17:05:32 2014 +0100
@@ -3,7 +3,6 @@
 import pyyacc
 from . import Token, CompilerError, SourceLocation
 from .target import Target, Label
-from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber
 
 
 def bit_type(value):
@@ -176,11 +175,13 @@
 
 
 class Assembler:
-    def __init__(self, target, stream):
+    def __init__(self, target):
         self.target = target
         assert isinstance(target, Target)
-        self.stream = stream
-        self.parser = Parser(target.asm_keywords, target.assembler_rules, self.stream.emit)
+        self.parser = Parser(target.asm_keywords, target.assembler_rules, self.emit)
+
+    def emit(self, *args):
+        self.stream.emit(*args)
 
     # Top level interface:
     def parse_line(self, line):
@@ -188,7 +189,7 @@
         tokens = Lexer(line, self.target.asm_keywords)
         self.parser.parse(tokens)
 
-    def assemble(self, asmsrc):
+    def assemble(self, asmsrc, stream):
         """ Assemble this source snippet """
         if hasattr(asmsrc, 'read'):
             asmsrc2 = asmsrc.read()
@@ -196,9 +197,8 @@
             asmsrc = asmsrc2
         # TODO: use generic newline??
         # TODO: the bothersome newline ...
+        self.stream = stream
         for line in asmsrc.split('\n'):
             self.parse_line(line)
+        self.stream = None
 
-    def assemble_line(self, line):
-        """ Assemble a single assembly line. """
-        self.parse_line(line)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/bitfun.py	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,14 @@
+
+
+def rotate_right(v, n):
+    """ bit-wise Rotate right n times """
+    mask = (2**n) - 1
+    mask_bits = v & mask
+    return (v >> n) | (mask_bits << (32 - n))
+
+def rotate_left(v, n):
+    assert n >= 0
+    assert n < 32
+    return rotate_right(v, 32 - n)
+
+
--- a/python/ppci/buildtasks.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/buildtasks.py	Fri Mar 07 17:05:32 2014 +0100
@@ -33,11 +33,11 @@
         self.source = source
         self.output = output_object
         self.ostream = BinaryOutputStream(self.output)
-        self.assembler = Assembler(target, self.ostream)
+        self.assembler = Assembler(target)
 
     def run(self):
         self.ostream.selectSection('code')
-        self.assembler.assemble(self.source)
+        self.assembler.assemble(self.source, self.ostream)
 
 
 class Compile(BuildTask):
--- a/python/ppci/codegen/codegen.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/codegen/codegen.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,7 +1,7 @@
 from .. import ir
 from ..irutils import Verifier
 from ..target import Target
-from ppci import CompilerError
+from .. import CompilerError
 from .canon import make as canonicalize
 from .registerallocator import RegisterAllocator
 import logging
@@ -42,7 +42,7 @@
 
         # Materialize the register allocated instructions into a stream of
         # real instructions.
-        frame.lower_to(outs)
+        self.target.lower_frame_to_stream(frame, outs)
         self.logger.debug('Instructions materialized')
         return frame
 
--- a/python/ppci/irmach.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/irmach.py	Fri Mar 07 17:05:32 2014 +0100
@@ -24,13 +24,6 @@
     def __repr__(self):
         return 'Frame {}'.format(self.name)
 
-    def lower_to(self, outs):
-        for im in self.instructions:
-            if isinstance(im.assem, Instruction):
-                outs.emit(im.assem)
-            else:
-                outs.emit(im.assem.fromim(im))
-
 
 class AbstractInstruction:
     """ 
@@ -48,12 +41,7 @@
         self.ismove = ismove
 
     def __repr__(self):
-        return self.render()
-
-    def render(self):
-        """
-            Substitutes source, dst and labels in the string
-        """
+        """ Substitutes source, dst and labels in the string """
         if isinstance(self.assem, Instruction):
             x = str(self.assem)
         else:
@@ -62,5 +50,3 @@
             x = x.format(cn, self.dst, self.src, self.others)
         return x
 
-
-makeIns = AbstractInstruction
--- a/python/ppci/outstream.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/outstream.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,5 +1,5 @@
 import binascii
-from ppci.target import Instruction, DebugInfo, Alignment
+from ppci.target import Instruction, Alignment
 from ppci.objectfile import ObjectFile
 
 """
@@ -27,8 +27,6 @@
 
     def dumpSection(self, s, f):
         for i in s.instructions:
-            if type(i) is DebugInfo:
-                continue
             addr = i.address
             insword = i.encode()
             assert type(insword) is bytes
--- a/python/ppci/target/__init__.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/__init__.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,7 +1,6 @@
 #!/usr/bin/env python
 
 from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment
-from .basetarget import Imm32, DebugInfo
 
 
 class SimpleTarget(Target):
--- a/python/ppci/target/arm/__init__.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/arm/__init__.py	Fri Mar 07 17:05:32 2014 +0100
@@ -4,12 +4,25 @@
 from ..arm.registers import R8, R9, R10, R11, R12, SP, LR, PC
 from ..arm.registers import register_range
 
-from .instructions import Mov, Add, Sub, Orr1, B, Bl, Ble, Bgt, Beq
+from .instructions import Dcd, Mov, Add, Sub, Orr1, Mul, Mov2
+from .instructions import B, Bl, Ble, Bgt, Beq, Blt
+from .instructions import Push, Pop, Str, Ldr, Ldr3, Str1, Ldr1
+from .selector import ArmInstructionSelector
+from .frame import ArmFrame
 
 class ArmTarget(Target):
     def __init__(self):
-        super().__init__('arm_arm')
+        super().__init__('arm')
+        self.make_parser()
+        self.ins_sel = ArmInstructionSelector()
+        self.FrameClass = ArmFrame
 
+        self.add_lowering(Ldr3, lambda im: Ldr3(im.dst[0], im.others[0]))
+        self.add_lowering(Str1, lambda im: Str1(im.src[1], im.src[0], im.others[0]))
+        self.add_lowering(Ldr1, lambda im: Ldr1(im.dst[0], im.src[0], im.others[0]))
+        self.add_lowering(Mov2, lambda im: Mov2(im.dst[0], im.src[0]))
+
+    def make_parser(self):
         # Assembly grammar:
         self.add_keyword('r0')
         self.add_keyword('r1')
@@ -24,6 +37,9 @@
         self.add_keyword('r10')
         self.add_keyword('r11')
         self.add_keyword('r12')
+        self.add_keyword('sp')
+        self.add_keyword('lr')
+        self.add_keyword('pc')
 
         self.add_rule('reg', ['r0'], lambda rhs: R0)
         self.add_rule('reg', ['r1'], lambda rhs: R1)
@@ -38,10 +54,16 @@
         self.add_rule('reg', ['r10'], lambda rhs: R10)
         self.add_rule('reg', ['r11'], lambda rhs: R11)
         self.add_rule('reg', ['r12'], lambda rhs: R12)
+        self.add_rule('reg', ['sp'], lambda rhs: SP)
+        self.add_rule('reg', ['lr'], lambda rhs: LR)
+        self.add_rule('reg', ['pc'], lambda rhs: PC)
 
+        self.add_keyword('dcd')
+        self.add_instruction(['dcd', 'imm32'],
+                lambda rhs: Dcd(rhs[1]))
 
         self.add_keyword('mov')
-        self.add_instruction(['mov', 'reg', ',', 'imm8'],
+        self.add_instruction(['mov', 'reg', ',', 'imm32'],
                 lambda rhs: Mov(rhs[1], rhs[3]))
 
         self.add_keyword('add')
@@ -58,6 +80,10 @@
         self.add_instruction(['sub', 'reg', ',', 'reg', ',', 'reg'],
                 lambda rhs: Sub(rhs[1], rhs[3], rhs[5]))
 
+        self.add_keyword('mul')
+        self.add_instruction(['mul', 'reg', ',', 'reg', ',', 'reg'],
+                lambda rhs: Mul(rhs[1], rhs[3], rhs[5]))
+
         self.add_keyword('orr')
         self.add_instruction(['orr', 'reg', ',', 'reg', ',', 'reg'],
                 lambda rhs: Orr1(rhs[1], rhs[3], rhs[5]))
@@ -72,6 +98,38 @@
         self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val))
         self.add_keyword('beq')
         self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val))
+        self.add_keyword('blt')
+        self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val))
 
         self.add_keyword('bl')
         self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val))
+
+        # memory:
+        self.add_keyword('pop')
+        self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1]))
+
+        self.add_keyword('push')
+        self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1]))
+
+        self.add_keyword('ldr')
+        self.add_instruction(['ldr', 'reg', ',', '[', 'reg', ',', 'imm8', ']'],
+            lambda rhs: Ldr(rhs[1], rhs[4], rhs[6]))
+
+        self.add_keyword('str')
+        self.add_instruction(['str', 'reg', ',', '[', 'reg', ',', 'imm8', ']'],
+            lambda rhs: Str(rhs[1], rhs[4], rhs[6]))
+
+        self.add_instruction(['str', 'reg', ',', '[', 'reg', ',', 'reg', ']'],
+            lambda rhs: Str(rhs[1], rhs[4], rhs[6]))
+
+        # Register list grammar:
+        self.add_rule('reg_list', ['{', 'reg_list_inner', '}'],
+            lambda rhs: rhs[1])
+        self.add_rule('reg_list_inner', ['reg_or_range'],
+            lambda rhs: rhs[0])
+        self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'],
+            lambda rhs: rhs[0] | rhs[2])
+        self.add_rule('reg_or_range', ['reg'], lambda rhs: {rhs[0]})
+
+        self.add_rule('reg_or_range', ['reg', '-', 'reg'],
+            lambda rhs: register_range(rhs[0], rhs[2]))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/target/arm/arm.brg	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,22 @@
+
+from ppci.target.arm.instructions import Add1, Sub1, Ldr1, Ldr3
+
+%%
+
+%terminal ADDI32 SUBI32 MULI32
+%terminal ORI32 SHLI32
+%terminal CONSTI32 MEMI32 REGI32 CALL
+%terminal MOVI32
+
+%%
+
+reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add1, dst=[d], src=[$1, $2]); return d .)
+reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub1, dst=[d], src=[$1, $2]); return d .)
+reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub1, dst=[d], src=[$1, $2]); return d .)
+reg: MEMI32(ADDI32(reg, cn)) 2 (. d = self.newTmp(); self.emit(Ldr1, dst=[d], src=[$1], others=[$2]); return d .)
+
+
+cn: CONSTI32 0 (. return $$.value .)
+
+reg: CONSTI32         3 (. d = self.newTmp(); ln = self.selector.frame.addConstant($$.value); self.emit(Ldr3, dst=[d], others=[ln]); return d .)
+reg: REGI32           1 (. return $$.value .)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/target/arm/frame.py	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,96 @@
+from ... import ir
+from ..basetarget import Label, Alignment
+from ...irmach import AbstractInstruction, Frame
+from .instructions import Dcd, Add, Sub, Push, Pop, Mov
+from .registers import R0, R1, R2, R3, R4, R5, R6, R7, R8, R11, LR, PC, SP
+
+
+class ArmFrame(Frame):
+    """ Arm specific frame for functions. """
+    def __init__(self, name):
+        # We use r7 as frame pointer.
+        super().__init__(name)
+        self.regs = [R0, R1, R2, R3, R4, R5, R6, R7, R8]
+        self.rv = ir.Temp('special_RV')
+        self.p1 = ir.Temp('special_P1')
+        self.p2 = ir.Temp('special_P2')
+        self.p3 = ir.Temp('special_P3')
+        self.p4 = ir.Temp('special_P4')
+        self.fp = ir.Temp('special_FP')
+        # Pre-colored registers:
+        self.tempMap = {}
+        self.tempMap[self.rv] = R0
+        self.tempMap[self.p1] = R1
+        self.tempMap[self.p2] = R2
+        self.tempMap[self.p3] = R3
+        self.tempMap[self.p4] = R4
+        self.tempMap[self.fp] = R11
+        self.locVars = {}
+        self.parMap = {}
+        # Literal pool:
+        self.constants = []
+
+    def argLoc(self, pos):
+        """
+            Gets the function parameter location in IR-code format.
+        """
+        if pos == 0:
+            return self.p1
+        elif pos == 1:
+            return self.p2
+        elif pos == 2:
+            return self.p3
+        elif pos == 3:
+            return self.p4
+        else:
+            raise NotImplementedError('No more than 4 parameters implemented')
+
+    def allocVar(self, lvar):
+        if lvar not in self.locVars:
+            self.locVars[lvar] = self.stacksize
+            self.stacksize = self.stacksize + 4
+        return self.locVars[lvar]
+
+    def addConstant(self, value):
+        lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
+        self.constants.append((lab_name, value))
+        return lab_name
+
+    def prologue(self):
+        """ Returns prologue instruction sequence """
+        pre = [
+            Label(self.name),                     # Label indication function
+            Push({LR, R11})
+            ]
+        if self.stacksize > 0:
+            pre.append(Sub(SP, SP, self.stacksize))  # Reserve stack space
+        pre += [
+            Mov(R11, SP)                          # Setup frame pointer
+            ]
+        return pre
+
+    def epilogue(self):
+        """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
+        post = []
+        if self.stacksize > 0:
+            post.append(Add(SP, SP, self.stacksize))
+        post += [
+            Pop({PC, R11}),
+            Alignment(4)   # Align at 4 bytes
+            ]
+        # Add constant literals:
+        for ln, v in self.constants:
+            post.extend([Label(ln), Dcd(v)])
+        return post
+
+    def EntryExitGlue3(self):
+        """
+            Add code for the prologue and the epilogue. Add a label, the
+            return instruction and the stack pointer adjustment for the frame.
+        """
+        for index, ins in enumerate(self.prologue()):
+            self.instructions.insert(index, AbstractInstruction(ins))
+
+        # Postfix code:
+        for ins in self.epilogue():
+            self.instructions.append(AbstractInstruction(ins))
--- a/python/ppci/target/arm/instructions.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/arm/instructions.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,31 +1,10 @@
-
 
 from ..basetarget import Instruction
+from ...bitfun import rotate_left
 
 from .token import ArmToken
 from .registers import R0, SP, ArmRegister
 
-# Helpers:
-
-def rotate_right(v, n):
-    """ bit-wise Rotate right n times """
-    mask = (2**n) - 1
-    mask_bits = v & mask
-    return (v >> n) | (mask_bits << (32 - n))
-
-def rotate_left(v, n):
-    assert n >= 0
-    assert n < 32
-    return rotate_right(v, 32 - n)
-
-masks = [rotate_right(0xFF, i * 2) for i in range(16)]
-#0x000000FF,
-#0xC000007F,
-#0xF000000F,
-#0xFC000003,
-#0xFF000000, # 4
-
-assert masks[4] == 0xFF000000, hex(masks[4])
 
 def encode_imm32(v):
     """ Bundle 32 bit value into 4 bits rotation and 8 bits value
@@ -46,20 +25,40 @@
         self.token = ArmToken()
 
 
-class Mov(ArmInstruction):
+class Dcd(ArmInstruction):
+    def __init__(self, v):
+        super().__init__()
+        self.v = v
+
+    def encode(self):
+        self.token[0:32] = self.v
+        return self.token.encode()
+
+
+def Mov(*args):
+    if len(args) == 2:
+        if isinstance(args[1], int):
+            return Mov1(*args)
+        elif isinstance(args[1], ArmRegister):
+            return Mov2(*args)
+    raise Exception()
+
+
+class Mov1(ArmInstruction):
     """ Mov Rd, imm16 """
     def __init__(self, reg, imm):
         super().__init__()
+        assert type(imm) is int
         self.reg = reg
         self.imm = imm
 
     def encode(self):
-        self.token[0:12] = self.imm
+        self.token[0:12] = encode_imm32(self.imm)
         self.token.Rd = self.reg.num
         self.token[16:20] = 0
-        self.token[20] = 0
+        self.token[20] = 0  # Set flags
         self.token[21:28] = 0b0011101
-        self.token.cond = 0xE # Always!
+        self.token.cond = AL
         return self.token.encode()
 
     def relocations(self):
@@ -69,6 +68,23 @@
         return 'Mov {}, {}'.format(self.reg, self.imm)
 
 
+class Mov2(ArmInstruction):
+    def __init__(self, rd, rm):
+        super().__init__()
+        self.rd = rd
+        self.rm = rm
+
+    def encode(self):
+        self.token[0:4] = self.rm.num
+        self.token[4:12] = 0
+        self.token[12:16] = self.rd.num
+        self.token[16:20] = 0
+        self.token.S = 0
+        self.token[21:28] = 0xD
+        self.token.cond = AL
+        return self.token.encode()
+
+
 def Add(*args):
     if len(args) == 3 and isinstance(args[0], ArmRegister) and \
             isinstance(args[1], ArmRegister):
@@ -87,6 +103,27 @@
             return Sub2(args[0], args[1], args[2])
     raise Exception()
 
+def Mul(*args):
+    return Mul1(args[0], args[1], args[2])
+
+
+class Mul(ArmInstruction):
+    def __init__(self, rd, rn, rm):
+        super().__init__()
+        self.rd = rd
+        self.rn = rn
+        self.rm = rm
+
+    def encode(self):
+        self.token[0:4] = self.rn.num
+        self.token[4:8] = 0b1001
+        self.token[8:12] = self.rm.num
+        self.token[16:20] = self.rd.num
+        self.token.S = 0
+        self.token.cond = AL
+        return self.token.encode()
+
+
 class OpRegRegReg(ArmInstruction):
     """ add rd, rn, rm """
     def __init__(self, rd, rn, rm, shift=0):
@@ -170,6 +207,8 @@
         return [(self.target, 'b_imm24')]
 
 
+EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = range(15)
+
 class BranchBase(BranchBaseRoot):
     opcode = 0b1010
 
@@ -177,18 +216,108 @@
     opcode = 0b1011
 
 class Bl(BranchLinkBase):
-    cond = 0xE
+    cond = AL
 
 class B(BranchBase):
-    cond = 0xE
+    cond = AL
 
 class Beq(BranchBase):
-    cond = 0x0
+    cond = EQ
 
 class Bgt(BranchBase):
-    cond = 0xC
+    cond = GT
 
 class Ble(BranchBase):
-    cond = 0xD
+    cond = LE
+
+class Blt(BranchBase):
+    cond = LT
+
+
+# Memory:
+
+def reg_list_to_mask(reg_list):
+    mask = 0
+    for reg in reg_list:
+        mask |= (1 << reg.num)
+    return mask
+
+
+class Push(ArmInstruction):
+    def __init__(self, register_set):
+        super().__init__()
+        self.reg_list = register_set
+
+    def encode(self):
+        self.token.cond = AL
+        self.token[16:28] = 0b100100101101
+        reg_list = 0
+        self.token[0:16] = reg_list_to_mask(self.reg_list)
+        return self.token.encode()
+
+class Pop(ArmInstruction):
+    def __init__(self, register_set):
+        super().__init__()
+        self.reg_list = register_set
+
+    def encode(self):
+        self.token.cond = AL
+        self.token[16:28] = 0b100010111101
+        self.token[0:16] = reg_list_to_mask(self.reg_list)
+        return self.token.encode()
 
 
+def Ldr(*args):
+    if len(args) == 3 and isinstance(args[1], ArmRegister):
+        return Ldr1(*args)
+    elif len(args) == 2 and isinstance(args[1], ArmRegister):
+        return Ldr1(args[0], args[1], 0)
+    raise Exception()
+
+def Str(*args):
+    if len(args) == 3 and isinstance(args[1], ArmRegister):
+        return Str1(*args)
+    elif len(args) == 2 and isinstance(args[1], ArmRegister):
+        return Str1(args[0], args[1], 0)
+    raise Exception()
+
+
+class LdrStrBase(ArmInstruction):
+    def __init__(self, rt, rn, offset):
+        super().__init__()
+        self.rt = rt
+        self.rn = rn
+        self.offset = offset
+
+    def encode(self):
+        self.token.cond = AL
+        self.token.Rn = self.rn.num
+        self.token[25:28] = self.opcode
+        self.token[20] = self.bit20
+        self.token[12:16] = self.rt.num
+        self.token[24] = 1  # Index
+        if self.offset >= 0:
+            self.token[23] = 1  # U == 1 'add'
+            self.token[0:12] = self.offset
+        else:
+            self.token[23] = 0
+            self.token[0:12] = -self.offset
+        return self.token.encode()
+
+
+class Str1(LdrStrBase):
+    opcode = 0b010
+    bit20 = 0
+
+
+class Ldr1(LdrStrBase):
+    opcode = 0b010
+    bit20 = 1
+
+
+class Ldr3(ArmInstruction):
+    """ Load PC relative constant value """
+    def __init__(self, rt, label):
+        self.rt = rt
+        self.label = label
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/target/arm/selector.py	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,90 @@
+from ... import ir, same_dir
+from ppci.irmach import AbstractInstruction as makeIns
+from ppci.ir2tree import makeTree
+from .instructions import Str1, Mov2
+from .instructions import B, Bl, Blt, Bgt, Beq
+import pyburg
+from ..basetarget import Nop
+from ..instructionselector import InstructionSelector
+
+# Import BURG spec for arm:
+spec_file = same_dir(__file__, 'arm.brg')
+arm_matcher = pyburg.load_as_module(spec_file)
+
+
+class ArmMatcher(arm_matcher.Matcher):
+    """ Matcher that derives from a burg spec generated matcher """
+    def __init__(self, selector):
+        super().__init__()
+        self.newTmp = selector.newTmp
+        self.emit = selector.emit
+        self.selector = selector
+
+
+class ArmInstructionSelector(InstructionSelector):
+    """ Instruction selector for the arm architecture """
+    def __init__(self):
+        super().__init__()
+        self.matcher = ArmMatcher(self)
+
+    def munchExpr(self, e):
+        # Use BURG system here:
+        t = makeTree(e)
+        return self.matcher.gen(t)
+
+    def munchCall(self, e):
+        """ Generate code for call sequence """
+        # Move arguments into proper locations:
+        reguses = []
+        for i, a in enumerate(e.arguments):
+            loc = self.frame.argLoc(i)
+            m = ir.Move(loc, a)
+            self.munchStm(m)
+            if isinstance(loc, ir.Temp):
+                reguses.append(loc)
+        self.emit(Bl(e.f), src=reguses, dst=[self.frame.rv])
+        d = self.newTmp()
+        self.move(d, self.frame.rv)
+        return d
+
+    def munchStm(self, s):
+        if isinstance(s, ir.Terminator):
+            pass
+        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \
+            isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \
+            isinstance(s.dst.e.b, ir.Const):
+            a = self.munchExpr(s.dst.e.a)
+            val = self.munchExpr(s.src)
+            c = s.dst.e.b.value
+            self.emit(Str1, others=[c], src=[a, val])
+        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
+            memloc = self.munchExpr(s.dst.e)
+            val = self.munchExpr(s.src)
+            self.emit(Str1, others=[0], src=[memloc, val])
+        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
+            val = self.munchExpr(s.src)
+            dreg = s.dst
+            self.move(dreg, val)
+        elif isinstance(s, ir.Exp):
+            # Generate expression code and discard the result.
+            x = self.munchExpr(s.e)
+            self.emit(Nop(), src=[x])
+        elif isinstance(s, ir.Jump):
+            tgt = self.targets[s.target]
+            self.emit(B(ir.label_name(s.target)), jumps=[tgt])
+        elif isinstance(s, ir.CJump):
+            a = self.munchExpr(s.a)
+            b = self.munchExpr(s.b)
+            self.emit(Cmp, src=[a, b])
+            ntgt = self.targets[s.lab_no]
+            ytgt = self.targets[s.lab_yes]
+            jmp_ins = makeIns(B(ir.label_name(s.lab_no)), jumps=[ntgt])
+            opnames = {'<': Blt, '>':Bgt, '==':Beq, '!=':Bne}
+            op = opnames[s.cond](ir.label_name(s.lab_yes))
+            self.emit(op, jumps=[ytgt, jmp_ins])  # Explicitely add fallthrough
+            self.emit2(jmp_ins)
+        else:
+            raise NotImplementedError('Stmt --> {}'.format(s))
+
+    def move(self, dst, src):
+        self.emit(Mov2, src=[src], dst=[dst], ismove=True)
--- a/python/ppci/target/basetarget.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/basetarget.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,49 +1,9 @@
-from ppci.asmnodes import ASymbol, AInstruction, ANumber
 from ppci import CompilerError
 
 """
   Base classes for defining a target
 """
 
-# Machine code interface:
-class Operand:
-   """ Single machine operand """
-   pass
-
-# standard immediates:
-
-class ImmBase:
-    def __init__(self, imm):
-        assert type(imm) is int
-        assert imm < self.Max()
-        self.imm = imm
-
-    @classmethod
-    def Max(cls):
-        return 2**cls.bits
-
-    @classmethod
-    def Create(cls, vop):
-        if type(vop) is ANumber and vop.number < cls.Max():
-            return cls(vop.number)
-
-
-class Imm3(ImmBase):
-    bits = 3
-
-
-class Imm7(ImmBase):
-    bits = 7
-
-
-class Imm8(ImmBase):
-    bits = 8
-
-
-class Imm32(ImmBase):
-    bits = 32
-
-
 class Instruction:
     """ Base instruction class """
     def encode(self):
@@ -76,12 +36,6 @@
     def symbols(self):
         return [self.name]
 
-    @classmethod
-    def Create(cls, vop):
-        if type(vop) is ASymbol:
-            name = vop.name
-            return cls(name)
-
 
 class Comment(PseudoInstruction):
     def __init__(self, txt):
@@ -119,7 +73,7 @@
         return 'DebugInfo: {}'.format(self.info)
 
 
-class Register(Operand):
+class Register:
     def __init__(self, name):
         self.name = name
 
@@ -131,10 +85,16 @@
         self.registers = []
         self.byte_sizes = {'int' : 4}  # For front end!
 
+        # For lowering:
+        self.lower_functions = {}
+
         # For assembler:
         self.assembler_rules = []
         self.asm_keywords = []
 
+        self.generate_base_rules()
+
+    def generate_base_rules(self):
         # Base rules for constants:
         self.add_rule('imm32', ['val32'], lambda x: x[0].val)
         self.add_rule('imm32', ['imm16'], lambda x: x[0])
@@ -162,11 +122,15 @@
     def add_rule(self, lhs, rhs, f):
         self.assembler_rules.append((lhs, rhs, f))
 
-    def instruction(self, cls):
-        """ Decorator function that registers an instruction to this target """
-        self.addInstruction(cls)
-        return cls
+    def lower_frame_to_stream(self, frame, outs):
+        """ Lower instructions from frame to output stream """
+        for im in frame.instructions:
+            if isinstance(im.assem, Instruction):
+                outs.emit(im.assem)
+            else:
+                ins = self.lower_functions[im.assem](im)
+                outs.emit(ins)
 
-    def addInstruction(self, i):
-        pass
-
+    def add_lowering(self, cls, f):
+        """ Add a function to the table of lowering options for this target """
+        self.lower_functions[cls] = f
--- a/python/ppci/target/instructionselector.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/instructionselector.py	Fri Mar 07 17:05:32 2014 +0100
@@ -21,7 +21,6 @@
     def newTmp(self):
         return self.temps.__next__()
 
-
     def munchFunction(self, f, frame):
         # Entry point for instruction selection
         assert isinstance(f, ir.Function)
--- a/python/ppci/target/msp430/msp430.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/msp430/msp430.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,7 +1,6 @@
 import struct
 import types
 from ..basetarget import Register, Instruction, Target
-from ppci.asmnodes import ASymbol, ANumber
 from ppci import CompilerError
 from .registers import r10, r11, r12, r13, r14, r15
 from .instructions import Reti, Mov, Add
--- a/python/ppci/target/thumb/armframe.py	Sun Mar 02 17:12:08 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-from ... import ir
-from ..basetarget import Label, Alignment
-from ...irmach import makeIns, Frame
-from .instructions import Dcd, AddSp, SubSp, Push, Pop, Mov2
-from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP
-
-
-class ArmFrame(Frame):
-    """ Arm specific frame for functions. """
-    def __init__(self, name):
-        # We use r7 as frame pointer.
-        super().__init__(name)
-        self.regs = [R0, R1, R2, R3, R4, R5, R6]
-        self.rv = ir.Temp('special_RV')
-        self.p1 = ir.Temp('special_P1')
-        self.p2 = ir.Temp('special_P2')
-        self.p3 = ir.Temp('special_P3')
-        self.p4 = ir.Temp('special_P4')
-        self.fp = ir.Temp('special_FP')
-        # Pre-colored registers:
-        self.tempMap = {}
-        self.tempMap[self.rv] = R0
-        self.tempMap[self.p1] = R1
-        self.tempMap[self.p2] = R2
-        self.tempMap[self.p3] = R3
-        self.tempMap[self.p4] = R4
-        self.tempMap[self.fp] = R7
-        self.locVars = {}
-        self.parMap = {}
-        # Literal pool:
-        self.constants = []
-
-    def argLoc(self, pos):
-        """
-            Gets the function parameter location in IR-code format.
-        """
-        if pos == 0:
-            return self.p1
-        elif pos == 1:
-            return self.p2
-        elif pos == 2:
-            return self.p3
-        elif pos == 3:
-            return self.p4
-        else:
-            raise NotImplementedError('No more than 4 parameters implemented')
-
-    def allocVar(self, lvar):
-        if lvar not in self.locVars:
-            self.locVars[lvar] = self.stacksize
-            self.stacksize = self.stacksize + 4
-        return self.locVars[lvar]
-
-    def addConstant(self, value):
-        lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
-        self.constants.append((lab_name, value))
-        return lab_name
-
-    def prologue(self):
-        """ Returns prologue instruction sequence """
-        pre = [
-            Label(self.name),                     # Label indication function
-            Push({LR, R7})
-            ]
-        if self.stacksize > 0:
-            pre.append(SubSp(self.stacksize))  # Reserve stack space
-        pre += [
-            Mov2(R7, SP)                          # Setup frame pointer
-            ]
-        return pre
-
-    def epilogue(self):
-        """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
-        post = []
-        if self.stacksize > 0:
-            post.append(AddSp(self.stacksize))
-        post += [
-            Pop({PC, R7}),
-            Alignment(4)   # Align at 4 bytes
-            ]
-        # Add constant literals:
-        for ln, v in self.constants:
-            post.extend([Label(ln), Dcd(v)])
-        return post
-
-    def EntryExitGlue3(self):
-        """
-            Add code for the prologue and the epilogue. Add a label, the
-            return instruction and the stack pointer adjustment for the frame.
-        """
-        for index, ins in enumerate(self.prologue()):
-            self.instructions.insert(index, makeIns(ins))
-
-        # Postfix code:
-        for ins in self.epilogue():
-            self.instructions.append(makeIns(ins))
--- a/python/ppci/target/thumb/armtarget.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/thumb/armtarget.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,12 +1,11 @@
 import struct
 from ..basetarget import Register, Instruction, Target, Label, Alignment
-from ..basetarget import Imm32, Imm8, Imm7, Imm3
-from .instructions import Add2, Sub, Add3, Cmp, Lsl, Orr, Add, Cmp2
+from .instructions import Add2, Sub, Sub3, Add3, Cmp, Lsl, Orr, Add, Cmp2, Sub2, Add2, Mul, And
 from .instructions import Dcd, Pop, Push, Yield, Mov2, Mov3
 from .instructions import B, Bl, Bne, Beq, Blt, Bgt
-from .instructions import Ldr, Str2, Ldr2, Str1, Ldr1
+from .instructions import Ldr, Str2, Ldr2, Str1, Ldr1, Ldr3
 
-from .armframe import ArmFrame
+from .frame import ArmFrame
 from .arminstructionselector import ArmInstructionSelector
 from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC
 from ..arm.registers import register_range
@@ -30,6 +29,22 @@
         self.FrameClass = ArmFrame
         self.add_rules()
 
+        # Add lowering options:
+        self.add_lowering(Str2, lambda im: Str2(im.src[1], im.src[0], im.others[0]))
+        self.add_lowering(Ldr2, lambda im: Ldr2(im.dst[0], im.src[0], im.others[0]))
+        self.add_lowering(Ldr3, lambda im: Ldr3(im.dst[0],  im.others[0]))
+        self.add_lowering(Mov3, lambda im: Mov3(im.dst[0],  im.others[0]))
+        self.add_lowering(Add2, lambda im: Add2(im.dst[0], im.src[0], im.others[0]))
+        self.add_lowering(Sub2, lambda im: Sub2(im.dst[0], im.src[0], im.others[0]))
+        self.add_lowering(Mov2, lambda im: Mov2(im.dst[0], im.src[0]))
+        self.add_lowering(Add3, lambda im: Add3(im.dst[0], im.src[0], im.src[1]))
+        self.add_lowering(Sub3, lambda im: Sub3(im.dst[0], im.src[0], im.src[1]))
+        self.add_lowering(Mul, lambda im: Mul(im.src[0], im.dst[0]))
+        self.add_lowering(And, lambda im: And(im.src[0], im.src[1]))
+        self.add_lowering(Orr, lambda im: Orr(im.src[0], im.src[1]))
+        self.add_lowering(Lsl, lambda im: Lsl(im.src[0], im.src[1]))
+        self.add_lowering(Cmp, lambda im: Cmp(im.src[0], im.src[1]))
+
     def add_rules(self):
 
         # Add instructions:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/target/thumb/frame.py	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,96 @@
+from ... import ir
+from ..basetarget import Label, Alignment
+from ...irmach import AbstractInstruction, Frame
+from .instructions import Dcd, AddSp, SubSp, Push, Pop, Mov2
+from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP
+
+
+class ArmFrame(Frame):
+    """ Arm specific frame for functions. """
+    def __init__(self, name):
+        # We use r7 as frame pointer.
+        super().__init__(name)
+        self.regs = [R0, R1, R2, R3, R4, R5, R6]
+        self.rv = ir.Temp('special_RV')
+        self.p1 = ir.Temp('special_P1')
+        self.p2 = ir.Temp('special_P2')
+        self.p3 = ir.Temp('special_P3')
+        self.p4 = ir.Temp('special_P4')
+        self.fp = ir.Temp('special_FP')
+        # Pre-colored registers:
+        self.tempMap = {}
+        self.tempMap[self.rv] = R0
+        self.tempMap[self.p1] = R1
+        self.tempMap[self.p2] = R2
+        self.tempMap[self.p3] = R3
+        self.tempMap[self.p4] = R4
+        self.tempMap[self.fp] = R7
+        self.locVars = {}
+        self.parMap = {}
+        # Literal pool:
+        self.constants = []
+
+    def argLoc(self, pos):
+        """
+            Gets the function parameter location in IR-code format.
+        """
+        if pos == 0:
+            return self.p1
+        elif pos == 1:
+            return self.p2
+        elif pos == 2:
+            return self.p3
+        elif pos == 3:
+            return self.p4
+        else:
+            raise NotImplementedError('No more than 4 parameters implemented')
+
+    def allocVar(self, lvar):
+        if lvar not in self.locVars:
+            self.locVars[lvar] = self.stacksize
+            self.stacksize = self.stacksize + 4
+        return self.locVars[lvar]
+
+    def addConstant(self, value):
+        lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
+        self.constants.append((lab_name, value))
+        return lab_name
+
+    def prologue(self):
+        """ Returns prologue instruction sequence """
+        pre = [
+            Label(self.name),                     # Label indication function
+            Push({LR, R7})
+            ]
+        if self.stacksize > 0:
+            pre.append(SubSp(self.stacksize))  # Reserve stack space
+        pre += [
+            Mov2(R7, SP)                          # Setup frame pointer
+            ]
+        return pre
+
+    def epilogue(self):
+        """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
+        post = []
+        if self.stacksize > 0:
+            post.append(AddSp(self.stacksize))
+        post += [
+            Pop({PC, R7}),
+            Alignment(4)   # Align at 4 bytes
+            ]
+        # Add constant literals:
+        for ln, v in self.constants:
+            post.extend([Label(ln), Dcd(v)])
+        return post
+
+    def EntryExitGlue3(self):
+        """
+            Add code for the prologue and the epilogue. Add a label, the
+            return instruction and the stack pointer adjustment for the frame.
+        """
+        for index, ins in enumerate(self.prologue()):
+            self.instructions.insert(index, AbstractInstruction(ins))
+
+        # Postfix code:
+        for ins in self.epilogue():
+            self.instructions.append(AbstractInstruction(ins))
--- a/python/ppci/target/thumb/instructions.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/target/thumb/instructions.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,5 +1,4 @@
 from ..basetarget import Register, Instruction, Target, Label
-from ..basetarget import Imm32, Imm8, Imm7, Imm3
 from ..token import u16, u32
 from .armtoken import ThumbToken
 from ..arm.registers import R0, ArmRegister, SP
@@ -13,10 +12,7 @@
 
 class Dcd(ThumbInstruction):
     def __init__(self, expr):
-        if isinstance(expr, Imm32):
-            self.expr = expr.imm
-            self.label = None
-        elif isinstance(expr, int):
+        if isinstance(expr, int):
             self.expr = expr
             self.label = None
         else:
@@ -71,17 +67,10 @@
 class Str2(LS_imm5_base):
     opcode = 0xC
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.src[1], im.src[0], im.others[0])
-
 
 class Ldr2(LS_imm5_base):
     opcode = 0xD
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.src[0], im.others[0])
 
 class ls_sp_base_imm8(ThumbInstruction):
     def __init__(self, rt, offset):
@@ -100,10 +89,6 @@
         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) \
@@ -115,15 +100,10 @@
 
 class Ldr3(ThumbInstruction):
     """ ldr Rt, LABEL, load value from pc relative position """
-    mnemonic = 'ldr'
     def __init__(self, rt, label):
         self.rt = rt
         self.label = label
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.others[0])
-
     def relocations(self):
         return [(self.label, 'lit_add_8')]
 
@@ -157,10 +137,6 @@
         self.rd = rd
         self.token = ThumbToken()
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.others[0])
-
     def encode(self):
         rd = self.rd.num
         self.token[8:11] = rd
@@ -172,11 +148,9 @@
         return 'MOV {}, {}'.format(self.rd, self.imm)
 
 
-
 # Arithmatics:
 
 
-
 class regregimm3_base(ThumbInstruction):
     def __init__(self, rd, rn, imm3):
         self.rd = rd
@@ -185,10 +159,6 @@
         self.imm3 = imm3
         self.token = ThumbToken()
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.src[0], im.others[0])
-
     def encode(self):
         rd = self.rd.num
         self.token[0:3] = rd
@@ -244,10 +214,6 @@
         self.rn = rn
         self.rm = rm
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.src[0], im.src[1])
-
     def encode(self):
         at = ThumbToken()
         at.rd = self.rd.num
@@ -279,10 +245,6 @@
         self.rd = rd
         self.rm = rm
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.dst[0], im.src[0])
-
     def encode(self):
         at = ThumbToken()
         at.rd = self.rd.num & 0x7
@@ -305,11 +267,6 @@
         self.rn = rn
         self.rdm = rdm
 
-    @classmethod
-    def fromim(cls, im):
-        assert im.src[1] is im.dst[0]
-        return cls(im.src[0], im.dst[0])
-
     def encode(self):
         at = ThumbToken()
         rn = self.rn.num
@@ -330,10 +287,6 @@
         self.rdn = rdn
         self.rm = rm
 
-    @classmethod
-    def fromim(cls, im):
-        return cls(im.src[0], im.src[1])
-
     def encode(self):
         at = ThumbToken()
         at.rd = self.rdn.num
--- a/python/ppci/tasks.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/ppci/tasks.py	Fri Mar 07 17:05:32 2014 +0100
@@ -6,7 +6,8 @@
 import logging
 
 class TaskError(Exception):
-    pass
+    def __init__(self, msg):
+        self.msg = msg
 
 
 class Task:
--- a/python/pyyacc.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/python/pyyacc.py	Fri Mar 07 17:05:32 2014 +0100
@@ -288,6 +288,7 @@
         self.dotpos = dotpos
         assert self.dotpos <= len(self.production.symbols)
         self.look_ahead = look_ahead
+        self._is_shift = self.dotpos < len(self.production.symbols)
 
     def getdata(self):
         """ Gets the members as a tuple """
@@ -304,12 +305,12 @@
     @property
     def IsReduce(self):
         """ Check if this item has the dot at the end """
-        return self.dotpos == len(self.production.symbols)
+        return not self._is_shift
 
     @property
     def IsShift(self):
         """ Check if this item is a shift item, i.e. the dot can proceed """
-        return self.dotpos < len(self.production.symbols)
+        return self._is_shift
 
     @property
     def Next(self):
--- a/test/m3_bare/recipe.yaml	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/m3_bare/recipe.yaml	Fri Mar 07 17:05:32 2014 +0100
@@ -3,11 +3,11 @@
   inputs:
     - assemble:
        source: startup_m3.asm
-       machine: arm
+       machine: thumb
     - compile:
        sources: [hello.c3]
        includes: []
-       machine: arm
+       machine: thumb
   layout:
       code: 0x0
       data: 0x20000000
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/setenv.sh	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+export PYTHONPATH=$PYTHONPATH:`pwd`/../python
+
+export TESTEMU=1
+
--- a/test/testarmasm.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testarmasm.py	Fri Mar 07 17:05:32 2014 +0100
@@ -6,20 +6,25 @@
 from ppci.target.target_list import arm_target
 
 
+a = Assembler(arm_target)
 
 class ArmAssemblerTestCase(AsmTestCaseBase):
     """ ARM-mode (not thumb-mode) instruction assembly test case """
     def setUp(self):
         self.t = arm_target
         self.obj = ObjectFile()
-        self.o = BinaryOutputStream(self.obj)
-        self.o.selectSection('.text')
-        self.a = Assembler(target=self.t, stream=self.o)
+        self.ostream = BinaryOutputStream(self.obj)
+        self.ostream.selectSection('.text')
+        self.a = a #Assembler(target=self.t)
 
     def testMovImm(self):
         self.feed('mov r4, 100')
         self.check('6440a0e3')
 
+    def testMovImm2(self):
+        self.feed('mov sp, 0x6000')
+        self.check('06daa0e3')
+
     def testAdd2(self):
         self.feed('add r12, r11, 300')
         self.check('4bcf8be2')
@@ -53,3 +58,30 @@
         self.feed('beq sjakie')
         self.feed('bl sjakie')
         self.check('030000ea 020000da 010000ca 0000000a ffffffeb feffffea fdffffda fcffffca fbffff0a faffffeb')
+
+    def testPush(self):
+        self.feed('push {r11,r5,r4,lr}')
+        self.check('30482de9')
+
+    def testPop(self):
+        self.feed('pop {r4,r5,r6}')
+        self.check('7000bde8')
+
+    def testStr(self):
+        self.feed('str r9, [r2, 33]')
+        self.check('219082e5')
+
+    def testLdr(self):
+        self.feed('ldr r5, [r3, 87]')
+        self.check('575093e5')
+
+    def testSequence1(self):
+        self.feed('sub r4,r5,23')
+        self.feed('blt x')
+        self.feed('x:')
+        self.feed('mul r4,r5,r2')
+        self.check('174045e2 ffffffba 950204e0')
+
+
+if __name__ == '__main__':
+    unittest.main()
--- a/test/testasm.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testasm.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,8 +1,7 @@
 #!/usr/bin/python
 
-import unittest, cProfile
+import unittest
 from ppci import CompilerError
-from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber
 from ppci.assembler import tokenize, Assembler, Lexer
 from ppci.objectfile import ObjectFile
 from ppci.linker import Linker
@@ -36,7 +35,7 @@
 
 
 class AssemblerParsingTestCase(unittest.TestCase):
-    """ 
+    """
         Tests the assembler parts
     """
     def setUp(self):
@@ -105,7 +104,7 @@
 class AsmTestCaseBase(unittest.TestCase):
     """ Base testcase for assembly """
     def feed(self, line):
-        self.a.assemble(line)
+        self.a.assemble(line, self.ostream)
 
     def check(self, hexstr):
         l = Linker()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testbitfun.py	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,20 @@
+
+
+import unittest
+import sys
+from ppci.bitfun import rotate_left, rotate_right
+
+
+class BitRotationTestCase(unittest.TestCase):
+    def testRightRotation(self):
+        self.assertEqual(0xFF000000, rotate_right(0xFF, 8))
+        self.assertEqual(0x0FF00000, rotate_right(0xFF, 12))
+
+    def testLeftRotation(self):
+        self.assertEqual(0x0000FF00, rotate_left(0xFF, 8))
+        self.assertEqual(0x001FE000, rotate_left(0xFF, 13))
+
+
+if __name__ == '__main__':
+    unittest.main()
+    sys.exit()
--- a/test/testemulation.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testemulation.py	Fri Mar 07 17:05:32 2014 +0100
@@ -14,15 +14,11 @@
 class EmulationTestCase(ZccBaseTestCase):
     """ Tests the compiler driver """
     def setUp(self):
-        os.chdir(testdir)
         if 'TESTEMU' not in os.environ:
             self.skipTest('Not running emulation tests')
 
-    def tearDown(self):
-        os.chdir(testdir)
-
-    def runQemu(self, kernel):
-        args = ['qemu-system-arm', '-M', 'lm3s811evb', '-m', '16M', 
+    def runQemu(self, kernel, machine='lm3s811evb'):
+        args = ['qemu-system-arm', '-M', machine, '-m', '16M', 
             '-nographic', '-kernel', kernel, '-monitor',
             'unix:qemucontrol.sock,server',
             '-serial', 'unix:qemuserial.sock,server']
@@ -41,9 +37,19 @@
         qemu_serial = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         qemu_serial.connect('qemuserial.sock')
 
+        time.sleep(0.5)
 
-        data = qemu_serial.recv(11).decode('ascii')
-        print(data)
+        qemu_serial.settimeout(0.2)
+
+        # Receive all data:
+        data = bytearray()
+        for i in range(40):
+            try:
+                data += qemu_serial.recv(1)
+            except socket.timeout as e:
+                break
+        data = data.decode('ascii')
+        # print(data)
 
         # Send quit command:
         qemu_control.send("quit\n".encode('ascii'))
@@ -52,13 +58,21 @@
         qemu_serial.close()
 
         # Check that output was correct:
-        self.assertEqual('Hello worle', data)
+        return data
 
     def testM3Bare(self):
         """ Build bare m3 binary and emulate it """
         recipe = os.path.join(testdir, 'm3_bare', 'recipe.yaml')
         self.buildRecipe(recipe)
-        self.runQemu('m3_bare/bare.bin')
+        data = self.runQemu('m3_bare/bare.bin')
+        self.assertEqual('Hello worle', data)
+
+    def testA9Bare(self):
+        """ Build vexpress cortex-A9 binary and emulate it """
+        recipe = os.path.join(testdir, '..', 'examples', 'qemu_a9_hello', 'recipe.yaml')
+        self.buildRecipe(recipe)
+        data = self.runQemu('../examples/qemu_a9_hello/hello.bin', machine='vexpress-a9')
+        self.assertEqual('Hello worle', data)
 
 
 if __name__ == '__main__':
--- a/test/testmsp430asm.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testmsp430asm.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,22 +1,21 @@
 #!/usr/bin/python
 
 import unittest
-from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber
 from ppci.assembler import tokenize, Assembler
 from ppci.objectfile import ObjectFile
 from ppci.outstream import BinaryOutputStream
-from ppci.target import Label
 from ppci.target.target_list import msp430target
 from testasm import AsmTestCaseBase
 
+a = Assembler(msp430target)
 
 class Msp430AssemblerTestCase(AsmTestCaseBase):
     def setUp(self):
         self.t = msp430target
         self.obj = ObjectFile()
-        self.o = BinaryOutputStream(self.obj)
-        self.o.selectSection('.text')
-        self.a = Assembler(target=self.t, stream=self.o)
+        self.ostream = BinaryOutputStream(self.obj)
+        self.ostream.selectSection('.text')
+        self.a = a
 
     def testMov(self):
         self.feed("mov r14, r15")
--- a/test/testregalloc.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testregalloc.py	Fri Mar 07 17:05:32 2014 +0100
@@ -1,7 +1,7 @@
 import unittest
 import os
 import sys
-from ppci.irmach import makeIns, Frame
+from ppci.irmach import AbstractInstruction as makeIns, Frame
 from ppci.codegen.registerallocator import RegisterAllocator
 from ppci import ir
 from ppci.target import Nop
--- a/test/testthumbasm.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testthumbasm.py	Fri Mar 07 17:05:32 2014 +0100
@@ -5,14 +5,15 @@
 from testasm import AsmTestCaseBase
 from ppci.target.target_list import thumb_target
 
+a = Assembler(thumb_target)
 
 class ThumbAssemblerTestCase(AsmTestCaseBase):
     def setUp(self):
         self.t = thumb_target
         self.obj = ObjectFile()
-        self.o = BinaryOutputStream(self.obj)
-        self.o.selectSection('.text')
-        self.a = Assembler(target=self.t, stream=self.o)
+        self.ostream = BinaryOutputStream(self.obj)
+        self.ostream.selectSection('.text')
+        self.a = a #
 
     def testMovImm8(self):
         self.feed('mov r4, 100')
--- a/test/testzcc.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/test/testzcc.py	Fri Mar 07 17:05:32 2014 +0100
@@ -11,6 +11,8 @@
 # Store testdir for safe switch back to directory:
 testdir = os.path.dirname(os.path.abspath(__file__))
 
+def relpath(*args):
+    return os.path.join(testdir, *args)
 
 class ZccBaseTestCase(unittest.TestCase):
     def callZcc(self, arg_list):
@@ -46,7 +48,7 @@
 
 
     def testDumpIr(self):
-        basedir = os.path.join('..', 'examples', 'c3', 'comments.c3')
+        basedir = relpath('..', 'examples', 'c3', 'comments.c3')
         arg_list = ['compile', basedir]
         arg_list.append('--target')
         arg_list.append('thumb')
@@ -54,14 +56,14 @@
 
     def testKernel(self):
         """ Build kernel using zcc: """
-        recipe = os.path.join(testdir, '..', 'kernel', 'recipe.yaml')
+        recipe = relpath('..', 'kernel', 'recipe.yaml')
         self.buildRecipe(recipe)
 
     @unittest.skip('Too difficult to fix')
     def testKernelBuildsEqualTwice(self):
         """ Build kernel two times and check the output is equal """
-        recipe = os.path.join(testdir, '..', 'kernel', 'recipe.yaml')
-        bin_filename = os.path.join(testdir, '..', 'kernel', 'kernel.bin')
+        recipe = relpath('..', 'kernel', 'recipe.yaml')
+        bin_filename = relpath('..', 'kernel', 'kernel.bin')
         self.buildRecipe(recipe)
         with open(bin_filename, 'rb') as f:
             a = f.read()
@@ -72,14 +74,18 @@
 
     def testUser(self):
         """ Build userspace using zcc: """
-        recipe = os.path.join(testdir, '..', 'user', 'recipe.yaml')
+        recipe = relpath('..', 'user', 'recipe.yaml')
         self.buildRecipe(recipe)
 
     def testBurn2(self):
         self.do(['burn2.c3'], ['stm32f4xx.c3'])
 
     def testBurn2_recipe(self):
-        recipe = os.path.join(testdir, '..', 'examples', 'c3', 'recipe.yaml')
+        recipe = relpath('..', 'examples', 'c3', 'recipe.yaml')
+        self.buildRecipe(recipe)
+
+    def test_hello_A9_c3_recipe(self):
+        recipe = relpath('..', 'examples', 'qemu_a9_hello', 'recipe.yaml')
         self.buildRecipe(recipe)
 
     @unittest.skip('Skip because of logfile')
--- a/util/serve_arm_as.py	Sun Mar 02 17:12:08 2014 +0100
+++ b/util/serve_arm_as.py	Fri Mar 07 17:05:32 2014 +0100
@@ -4,23 +4,38 @@
 """
 
 import subprocess
-import tornado.web
-import tornado.ioloop
+try:
+    import tornado.web
+    import tornado.ioloop
+    from tornado.web import RequestHandler
+except Exception as e:
+    print(e)
+    RequestHandler = object
+
 import io
 
+prefix = 'arm-none-eabi-'
+AS = prefix + 'as'
+objdump = prefix + 'objdump'
+
 def mangle(inp, outstream):
     print('assembling...', file=outstream)
-    p_as = subprocess.Popen(['arm-elf-as'], stdin=subprocess.PIPE)
+    p_as = subprocess.Popen([AS], stdin=subprocess.PIPE)
     p_as.communicate(input=inp.encode('ascii'))
+    if p_as.returncode != 0:
+        raise Exception('{}'.format(p_as.returncode))
 
-    p_objdump = subprocess.Popen(['arm-elf-objdump', '-d'], stdout=subprocess.PIPE)
+    p_objdump = subprocess.Popen([objdump, '-d'], stdout=subprocess.PIPE)
     output = p_objdump.communicate()[0].decode('ascii')
+    if p_objdump.returncode != 0:
+        raise Exception('{}'.format(p_objdump.returncode))
     print(output, file=outstream)
 
-    p_objdump = subprocess.Popen(['arm-elf-objdump', '-s'], stdout=subprocess.PIPE)
+    p_objdump = subprocess.Popen([objdump, '-s', '-j', '.text'], stdout=subprocess.PIPE)
     output = p_objdump.communicate()[0].decode('ascii')
+    if p_objdump.returncode != 0:
+        raise Exception('{}'.format(p_objdump.returncode))
     print(output, file=outstream)
-    print('Done!', file=outstream)
 
 page = """
 <html>
@@ -44,10 +59,11 @@
 </html>
 """
 
-class MainHandler(tornado.web.RequestHandler):
+class MainHandler(RequestHandler):
     def get(self):
         src="sub sp,sp,#8"
         self.write(page.replace('%result%', '').replace('%src%', src))
+
     def post(self):
         #print(self.request.body)
         src = self.get_argument('source')
@@ -58,9 +74,45 @@
         self.write(page.replace('%result%', txt).replace('%src%', src))
 
 
-application = tornado.web.Application([(r"/", MainHandler)])
-
-if __name__ == '__main__':
+def serve_tornado():
+    application = tornado.web.Application([(r"/", MainHandler)])
     application.listen(8888)
     tornado.ioloop.IOLoop.instance().start()
 
+def extract_bytes(txt):
+    lines = list(filter(None, (line.strip() for line in txt.split('\n'))))
+    idx = lines.index('Contents of section .text:')
+
+    byte_txt = ''
+    for line in lines[idx+1:]:
+        parts = list(filter(None, line.split(' ')))
+        byte_txt += ' '.join(parts[1:-1]) + ' '
+    byte_txt = byte_txt.strip()
+    return byte_txt
+
+def run_on_file():
+    with open('test_patterns.txt', 'r') as f:
+        data = f.read()
+
+    outfile = open('tests.pygen', 'w')
+    snippets = data.split('===')
+    for snippet in snippets:
+        make_test(snippet, outfile)
+    outfile.close()
+
+def make_test(src, output_file):
+    out = io.StringIO()
+    try:
+        mangle(src, out)
+    except Exception as e:
+        return
+    txt = out.getvalue()
+    byte_txt = extract_bytes(txt)
+    print("    def testTODO(self):", file=output_file)
+    for line in filter(None, src.split('\n')):
+        print("        self.feed('{}')".format(line), file=output_file)
+    print("        self.check('{}')".format(byte_txt), file=output_file)
+
+if __name__ == '__main__':
+    #serve_tornado()
+    run_on_file()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/test_patterns.txt	Fri Mar 07 17:05:32 2014 +0100
@@ -0,0 +1,22 @@
+
+mov r4, #100
+===
+mov sp, #0x6000
+===
+mov r3, sp
+===
+yield
+===
+push {r11,r5,r4,lr}
+===
+pop {r4,r5,r6}
+===
+sub r4,r5,#23
+blt x
+x:
+mul r4,r5,r2
+===
+str r9, [r2, #33]
+===
+ldr r5, [r3, #87]
+