changeset 347:742588fb8cd6 devel

Merge into devel branch
author Windel Bouwman
date Fri, 07 Mar 2014 17:10:21 +0100
parents 11c5a8a70c02 (current diff) 3bb7dcfe5529 (diff)
children f381cea07fec 8fe299cd2d55
files examples/c3/burn.c3proj python/ppci/asmnodes.py python/ppci/target/thumb/armframe.py
diffstat 42 files changed, 1244 insertions(+), 532 deletions(-) [+]
line wrap: on
line diff
--- a/examples/c3/burn.c3proj	Sat Mar 01 16:27:52 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:10:21 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:10:21 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:10:21 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:10:21 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	Sat Mar 01 16:27:52 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/assembler.py	Fri Mar 07 17:10:21 2014 +0100
@@ -3,14 +3,13 @@
 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):
-    assert value < (2**31)
+    assert value < (2**32)
     assert value >= 0
     t = 'val32'
-    for n in [16, 8, 5, 3]:
+    for n in [16, 12, 8, 5, 3]:
         if value < (2**n):
             t = 'val{}'.format(n)
     return t
@@ -100,7 +99,7 @@
         # Construct a parser given a grammar:
         tokens2 = ['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*',
                    pyyacc.EPS, 'COMMENT', '{', '}',
-                   pyyacc.EOF, 'val32', 'val16', 'val8', 'val5', 'val3']
+                   pyyacc.EOF, 'val32', 'val16', 'val12', 'val8', 'val5', 'val3']
         tokens2.extend(kws)
         self.kws = kws
         g = pyyacc.Grammar(tokens2)
@@ -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:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/buildtasks.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/codegen/codegen.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/irmach.py	Fri Mar 07 17:10:21 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/linker.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/linker.py	Fri Mar 07 17:10:21 2014 +0100
@@ -76,6 +76,18 @@
     section.data[reloc.offset] |= imm6
     section.data[reloc.offset + 1] |= (s << 2)
 
+# ARM reloc!!
+# TODO: move to target classes???
+@reloc('b_imm24')
+def apply_b_imm24(reloc, sym, section, reloc_value):
+    assert sym.value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = (sym.value - (reloc_value + 8))
+    rel24 = wrap_negative(offset >> 2, 24)
+    section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF
+    section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF
+    section.data[reloc.offset+0] = rel24 & 0xFF
+
 
 class Linker:
     """ Merges the sections of several object files and 
--- a/python/ppci/outstream.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/outstream.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/__init__.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/arm/__init__.py	Fri Mar 07 17:10:21 2014 +0100
@@ -1,16 +1,29 @@
 
 from ..basetarget import Target
-from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC
+from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7
+from ..arm.registers import R8, R9, R10, R11, R12, SP, LR, PC
 from ..arm.registers import register_range
 
-from .instructions import Mov
+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 ArmArmTarget(Target):
+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('mov')
         self.add_keyword('r0')
         self.add_keyword('r1')
         self.add_keyword('r2')
@@ -19,6 +32,14 @@
         self.add_keyword('r5')
         self.add_keyword('r6')
         self.add_keyword('r7')
+        self.add_keyword('r8')
+        self.add_keyword('r9')
+        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)
@@ -28,15 +49,87 @@
         self.add_rule('reg', ['r5'], lambda rhs: R5)
         self.add_rule('reg', ['r6'], lambda rhs: R6)
         self.add_rule('reg', ['r7'], lambda rhs: R7)
-
+        self.add_rule('reg', ['r8'], lambda rhs: R8)
+        self.add_rule('reg', ['r9'], lambda rhs: R9)
+        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_instruction(['mov', 'reg', ',', 'imm8'],
+        self.add_keyword('dcd')
+        self.add_instruction(['dcd', 'imm32'],
+                lambda rhs: Dcd(rhs[1]))
+
+        self.add_keyword('mov')
+        self.add_instruction(['mov', 'reg', ',', 'imm32'],
                 lambda rhs: Mov(rhs[1], rhs[3]))
 
-        self.add_rule('imm32', ['val32'], lambda x: x[0].val)
-        self.add_rule('imm32', ['imm8'], lambda x: x[0])
-        self.add_rule('imm8', ['val8'], lambda x: x[0].val)
-        self.add_rule('imm8', ['imm5'], lambda x: x[0])
-        self.add_rule('imm5', ['val5'], lambda x: x[0].val)
-        self.add_rule('imm5', ['imm3'], lambda x: x[0])
-        self.add_rule('imm3', ['val3'], lambda x: x[0].val)
+        self.add_keyword('add')
+        self.add_instruction(['add', 'reg', ',', 'reg', ',', 'imm32'],
+                lambda rhs: Add(rhs[1], rhs[3], rhs[5]))
+
+        self.add_instruction(['add', 'reg', ',', 'reg', ',', 'reg'],
+                lambda rhs: Add(rhs[1], rhs[3], rhs[5]))
+
+        self.add_keyword('sub')
+        self.add_instruction(['sub', 'reg', ',', 'reg', ',', 'imm32'],
+                lambda rhs: Sub(rhs[1], rhs[3], rhs[5]))
+
+        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]))
+
+
+        # Jumping:
+        self.add_keyword('b')
+        self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val))
+        self.add_keyword('ble')
+        self.add_instruction(['ble', 'ID'], lambda rhs: Ble(rhs[1].val))
+        self.add_keyword('bgt')
+        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:10:21 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:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/arm/instructions.py	Fri Mar 07 17:10:21 2014 +0100
@@ -1,10 +1,22 @@
-
 
 from ..basetarget import Instruction
+from ...bitfun import rotate_left
 
 from .token import ArmToken
-from .registers import R0, SP
+from .registers import R0, SP, ArmRegister
+
 
+def encode_imm32(v):
+    """ Bundle 32 bit value into 4 bits rotation and 8 bits value
+     """
+    for i in range(0, 16):
+        v2 = rotate_left(v, i*2)
+        if (v2 & 0xFFFFFF00) == 0:
+            rotation = i
+            val = v2 & 0xFF
+            x = (rotation << 8) | val
+            return x
+    raise Exception("Invalid value {}".format(v))
 
 # Instructions:
 
@@ -13,25 +25,299 @@
         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[12:16] = self.reg.num
+        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):
         return []
 
     def __repr__(self):
-        return 'DCD 0x{0:X}'.format(self.expr)
+        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):
+        if isinstance(args[2], ArmRegister):
+            return Add1(args[0], args[1], args[2])
+        elif isinstance(args[2], int):
+            return Add2(args[0], args[1], args[2])
+    raise Exception()
+
+def Sub(*args):
+    if len(args) == 3 and isinstance(args[0], ArmRegister) and \
+            isinstance(args[1], ArmRegister):
+        if isinstance(args[2], ArmRegister):
+            return Sub1(args[0], args[1], args[2])
+        elif isinstance(args[2], int):
+            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):
+        super().__init__()
+        self.rd = rd
+        self.rn = rn
+        self.rm = rm
+
+    def encode(self):
+        self.token[0:4] = self.rm.num
+        self.token[4] = 0
+        self.token[5:7] = 0
+        self.token[7:12] = 0 # Shift
+        self.token.Rd = self.rd.num
+        self.token.Rn = self.rn.num
+        self.token.S = 0 # Set flags
+        self.token[21:28] = self.opcode
+        self.token.cond = 0xE # Always!
+        return self.token.encode()
+
+    def __repr__(self):
+        return 'add {}, {}, {}'.format(self.rd, self.rn, self.rm)
+
+
+class Add1(OpRegRegReg):
+    opcode = 0b0000100
+
+
+class Sub1(OpRegRegReg):
+    opcode = 0b0000010
+
+
+class Orr1(OpRegRegReg):
+    opcode = 0b0001100
+
+
+class OpRegRegImm(ArmInstruction):
+    """ add rd, rn, imm12 """
+    def __init__(self, rd, rn, imm):
+        super().__init__()
+        self.rd = rd
+        self.rn = rn
+        self.imm2 = encode_imm32(imm)
+        self.imm = imm
+
+    def encode(self):
+        self.token[0:12] = self.imm2
+        self.token.Rd = self.rd.num
+        self.token.Rn = self.rn.num
+        self.token.S = 0 # Set flags
+        self.token[21:28] = self.opcode
+        self.token.cond = 0xE # Always!
+        return self.token.encode()
+
+    def __repr__(self):
+        return 'add {}, {}, {}'.format(self.rd, self.rn, self.imm)
+
+
+class Add2(OpRegRegImm):
+    opcode = 0b0010100
+
+
+class Sub2(OpRegRegImm):
+    opcode = 0b0010010
+
+
+
+# Branches:
 
+class BranchBaseRoot(ArmInstruction):
+    def __init__(self, target):
+        super().__init__()
+        self.target = target
+
+    def encode(self):
+        self.token.cond = self.cond
+        self.token[24:28] = self.opcode
+        return self.token.encode()
+
+    def relocations(self):
+        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
+
+class BranchLinkBase(BranchBaseRoot):
+    opcode = 0b1011
+
+class Bl(BranchLinkBase):
+    cond = AL
+
+class B(BranchBase):
+    cond = AL
+
+class Beq(BranchBase):
+    cond = EQ
+
+class Bgt(BranchBase):
+    cond = GT
+
+class Ble(BranchBase):
+    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:10:21 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/arm/token.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/arm/token.py	Fri Mar 07 17:10:21 2014 +0100
@@ -7,6 +7,9 @@
         super().__init__(32)
 
     cond = bit_range(28, 32)
+    S = bit_range(20, 21)
+    Rd = bit_range(12, 16)
+    Rn = bit_range(16, 20)
 
     def encode(self):
         return u32(self.bit_value)
--- a/python/ppci/target/basetarget.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/basetarget.py	Fri Mar 07 17:10:21 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,34 @@
         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])
+
+        self.add_rule('imm16', ['val16'], lambda x: x[0].val)
+        self.add_rule('imm16', ['imm12'], lambda x: x[0])
+
+        self.add_rule('imm12', ['val12'], lambda x: x[0].val)
+        self.add_rule('imm12', ['imm8'], lambda x: x[0])
+
+        self.add_rule('imm8', ['val8'], lambda x: x[0].val)
+        self.add_rule('imm8', ['imm5'], lambda x: x[0])
+
+        self.add_rule('imm5', ['val5'], lambda x: x[0].val)
+        self.add_rule('imm5', ['imm3'], lambda x: x[0])
+
+        self.add_rule('imm3', ['val3'], lambda x: x[0].val)
+
     def add_keyword(self, kw):
         self.asm_keywords.append(kw)
 
@@ -144,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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/instructionselector.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/msp430/msp430.py	Fri Mar 07 17:10:21 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
@@ -40,16 +39,6 @@
         self.add_keyword('reti')
         self.add_instruction(['reti'], lambda rhs: Reti())
 
-        # Constants:
-        self.add_rule('imm32', ['val32'], lambda x: x[0].val)
-        self.add_rule('imm32', ['imm16'], lambda x: x[0])
-        self.add_rule('imm16', ['val16'], lambda x: x[0].val)
-        self.add_rule('imm16', ['imm8'], lambda x: x[0])
-        self.add_rule('imm8', ['val8'], lambda x: x[0].val)
-        self.add_rule('imm8', ['imm5'], lambda x: x[0])
-        self.add_rule('imm5', ['val5'], lambda x: x[0].val)
-        self.add_rule('imm5', ['imm3'], lambda x: x[0])
-        self.add_rule('imm3', ['val3'], lambda x: x[0].val)
 
 
 msp430target = Msp430Target()
--- a/python/ppci/target/target_list.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/target_list.py	Fri Mar 07 17:10:21 2014 +0100
@@ -1,10 +1,10 @@
 
-from .arm import ArmArmTarget
+from .arm import ArmTarget
 from .thumb import ThumbTarget
 from .msp430.msp430 import msp430target
 
 # Instance:
-arm_target = ArmArmTarget()
+arm_target = ArmTarget()
 thumb_target = ThumbTarget()
 
 target_list = [arm_target, thumb_target]
--- a/python/ppci/target/thumb/armframe.py	Sat Mar 01 16:27:52 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/thumb/armtarget.py	Fri Mar 07 17:10:21 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:
@@ -146,12 +161,4 @@
         self.add_rule('reg8', ['r5'], lambda rhs: R5)
         self.add_rule('reg8', ['r6'], lambda rhs: R6)
         self.add_rule('reg8', ['r7'], lambda rhs: R7)
-        # Constants:
-        self.add_rule('imm32', ['val32'], lambda x: x[0].val)
-        self.add_rule('imm32', ['imm8'], lambda x: x[0])
-        self.add_rule('imm8', ['val8'], lambda x: x[0].val)
-        self.add_rule('imm8', ['imm5'], lambda x: x[0])
-        self.add_rule('imm5', ['val5'], lambda x: x[0].val)
-        self.add_rule('imm5', ['imm3'], lambda x: x[0])
-        self.add_rule('imm3', ['val3'], lambda x: x[0].val)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/target/thumb/frame.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/target/thumb/instructions.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/ppci/tasks.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/python/pyyacc.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/m3_bare/recipe.yaml	Fri Mar 07 17:10:21 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:10:21 2014 +0100
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+export PYTHONPATH=$PYTHONPATH:`pwd`/../python
+
+export TESTEMU=1
+
--- a/test/testarmasm.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testarmasm.py	Fri Mar 07 17:10:21 2014 +0100
@@ -3,160 +3,85 @@
 from ppci.objectfile import ObjectFile
 from asm import Assembler
 from testasm import AsmTestCaseBase
-from ppci.target.target_list import arm_target, thumb_target
+from ppci.target.target_list import arm_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)
-
-    def testMovImm8(self):
-        self.feed('mov r4, 100')
-        self.check('6424')
-
-    @unittest.skip
-    def testMovExt(self):
-        self.feed('mov r3, sp')
-        self.check('')
-
-    def testYield(self):
-        self.feed('yield')
-        self.check('10bf')
-
-    def testPush(self):
-        self.feed('push {r2,r3,lr}')
-        self.check('0cb5')
-
-    def testPop(self):
-        self.feed('pop {r4-r6, pc}')
-        self.check('70bd')
-
-    def testStr5(self):
-        self.feed('str r4, [r1 + 0]')
-        self.check('0c60')
-
-    def testLdr5(self):
-        self.feed('ldr r4, [r0 + 0]')
-        self.check('0468')
-
-    def testLdrSpRel(self):
-        self.feed('ldr r0, [sp + 4]')
-        self.check('0198')
-
-    def testStrSpRel(self):
-        self.feed('str r0, [sp + 4]')
-        self.check('0190')
-
-    def testLdrPcRel(self):
-        self.feed('ldr r7, henkie')
-        self.feed('ldr r6, henkie')
-        self.feed('ldr r1, henkie')
-        self.feed('align 4')
-        self.feed('dcd 1')
-        self.feed('henkie: dcd 2')
-        self.check('024F024E 01490000 01000000 02000000')
-
-    def testBranch(self):
-        self.feed('start: b henkie')
-        self.feed('beq henkie')
-        self.feed('bne henkie')
-        self.feed('henkie: b start')
-        self.feed('eof: b eof')
-        self.check('01e000d0 ffd1fbe7 fee7')
-
-    def testConditions(self):
-        self.feed('blt x')
-        self.feed('bgt x')
-        self.feed('x:')
-        self.check('00dbffdc')
+a = Assembler(arm_target)
 
-    def testBoff(self):
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('henkie:')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.feed('b henkie')
-        self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7')
-
-    def testBl(self):
-        self.feed('bl henkie')
-        self.feed('bl henkie')
-        self.feed('henkie:')
-        self.feed('bl henkie')
-        self.feed('bl henkie')
-        self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff')
-
-    def testCmpRegReg(self):
-        self.feed('cmp r0, r1')
-        self.check('8842')
-
-    def testAddimm3(self):
-        self.feed('add r3, r5, 2')
-        self.feed('add r4, r1, 6')
-        self.check('ab1c8c1d')
-
-    def testSubImm3(self):
-        self.feed('sub r3, r5, 2')
-        self.feed('sub r4, r1, 6')
-        self.check('ab1e8c1f')
-
-    def testLeftShift(self):
-        self.feed('lsl r3, r5')
-        self.check('ab40')
-
-    def testAddSp(self):
-        self.feed('add sp,sp,8')
-        self.feed('add sp,sp,16')
-        self.check('02b004b0')
-
-    def testSubSp(self):
-        self.feed('sub sp,sp,32')
-        self.feed('sub sp,sp,4')
-        self.check('88b081b0')
-
-    def testSequence1(self):
-        self.feed('mov r5, 3')
-        self.feed('add r4, r5, 0')
-        self.feed('loop: add r6, r4, 7')
-        self.feed('cmp r6, 5')
-        self.check('0325 2c1c e61d 052e')
-
-    def testSequence2(self):
-        self.feed('henkie:')
-        self.feed('push {r1,r4,r5}')
-        self.feed('add r5, r2, r4')
-        self.feed('cmp r4, r2')
-        self.feed('ldr r0, [sp + 4]')
-        self.feed('str r3, [sp + 16]')
-        self.feed('pop {r1, r4, r5}')
-        self.feed('lsl r3, r4')
-        self.feed('cmp r3, r5')
-        self.feed('beq henkie')
-        self.feed('bne henkie')
-        self.feed('b henkie')
-        self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7')
-
-
-class AssemblerArmTestCase(AsmTestCaseBase):
+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')
+
+    def testAdd1(self):
+        self.feed('add r9, r7, r2')
+        self.check('029087e0')
+
+    def testSub1(self):
+        self.feed('sub r5, r6, r2')
+        self.check('025046e0')
+
+    def testSub2(self):
+        self.feed('sub r0, r1, 0x80000001')
+        self.check('060141e2')
+
+    def testOrr1(self):
+        self.feed('orr r8, r7, r6')
+        self.check('068087e1')
+
+    def testBranches(self):
+        self.feed('b sjakie')
+        self.feed('ble sjakie')
+        self.feed('bgt sjakie')
+        self.feed('beq sjakie')
+        self.feed('bl sjakie')
+        self.feed('sjakie:')
+        self.feed('b sjakie')
+        self.feed('ble sjakie')
+        self.feed('bgt sjakie')
+        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	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testasm.py	Fri Mar 07 17:10:21 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:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testemulation.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testmsp430asm.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testregalloc.py	Fri Mar 07 17:10:21 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testthumbasm.py	Fri Mar 07 17:10:21 2014 +0100
@@ -0,0 +1,151 @@
+import unittest
+from ppci.outstream import BinaryOutputStream
+from ppci.objectfile import ObjectFile
+from asm import Assembler
+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.ostream = BinaryOutputStream(self.obj)
+        self.ostream.selectSection('.text')
+        self.a = a #
+
+    def testMovImm8(self):
+        self.feed('mov r4, 100')
+        self.check('6424')
+
+    @unittest.skip
+    def testMovExt(self):
+        self.feed('mov r3, sp')
+        self.check('')
+
+    def testYield(self):
+        self.feed('yield')
+        self.check('10bf')
+
+    def testPush(self):
+        self.feed('push {r2,r3,lr}')
+        self.check('0cb5')
+
+    def testPop(self):
+        self.feed('pop {r4-r6, pc}')
+        self.check('70bd')
+
+    def testStr5(self):
+        self.feed('str r4, [r1 + 0]')
+        self.check('0c60')
+
+    def testLdr5(self):
+        self.feed('ldr r4, [r0 + 0]')
+        self.check('0468')
+
+    def testLdrSpRel(self):
+        self.feed('ldr r0, [sp + 4]')
+        self.check('0198')
+
+    def testStrSpRel(self):
+        self.feed('str r0, [sp + 4]')
+        self.check('0190')
+
+    def testLdrPcRel(self):
+        self.feed('ldr r7, henkie')
+        self.feed('ldr r6, henkie')
+        self.feed('ldr r1, henkie')
+        self.feed('align 4')
+        self.feed('dcd 1')
+        self.feed('henkie: dcd 2')
+        self.check('024F024E 01490000 01000000 02000000')
+
+    def testBranch(self):
+        self.feed('start: b henkie')
+        self.feed('beq henkie')
+        self.feed('bne henkie')
+        self.feed('henkie: b start')
+        self.feed('eof: b eof')
+        self.check('01e000d0 ffd1fbe7 fee7')
+
+    def testConditions(self):
+        self.feed('blt x')
+        self.feed('bgt x')
+        self.feed('x:')
+        self.check('00dbffdc')
+
+    def testBoff(self):
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('henkie:')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.feed('b henkie')
+        self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7')
+
+    def testBl(self):
+        self.feed('bl henkie')
+        self.feed('bl henkie')
+        self.feed('henkie:')
+        self.feed('bl henkie')
+        self.feed('bl henkie')
+        self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff')
+
+    def testCmpRegReg(self):
+        self.feed('cmp r0, r1')
+        self.check('8842')
+
+    def testAddimm3(self):
+        self.feed('add r3, r5, 2')
+        self.feed('add r4, r1, 6')
+        self.check('ab1c8c1d')
+
+    def testSubImm3(self):
+        self.feed('sub r3, r5, 2')
+        self.feed('sub r4, r1, 6')
+        self.check('ab1e8c1f')
+
+    def testLeftShift(self):
+        self.feed('lsl r3, r5')
+        self.check('ab40')
+
+    def testAddSp(self):
+        self.feed('add sp,sp,8')
+        self.feed('add sp,sp,16')
+        self.check('02b004b0')
+
+    def testSubSp(self):
+        self.feed('sub sp,sp,32')
+        self.feed('sub sp,sp,4')
+        self.check('88b081b0')
+
+    def testSequence1(self):
+        self.feed('mov r5, 3')
+        self.feed('add r4, r5, 0')
+        self.feed('loop: add r6, r4, 7')
+        self.feed('cmp r6, 5')
+        self.check('0325 2c1c e61d 052e')
+
+    def testSequence2(self):
+        self.feed('henkie:')
+        self.feed('push {r1,r4,r5}')
+        self.feed('add r5, r2, r4')
+        self.feed('cmp r4, r2')
+        self.feed('ldr r0, [sp + 4]')
+        self.feed('str r3, [sp + 16]')
+        self.feed('pop {r1, r4, r5}')
+        self.feed('lsl r3, r4')
+        self.feed('cmp r3, r5')
+        self.feed('beq henkie')
+        self.feed('bne henkie')
+        self.feed('b henkie')
+        self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7')
+
+
--- a/test/testzcc.py	Sat Mar 01 16:27:52 2014 +0100
+++ b/test/testzcc.py	Fri Mar 07 17:10:21 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	Sat Mar 01 16:27:52 2014 +0100
+++ b/util/serve_arm_as.py	Fri Mar 07 17:10:21 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:10:21 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]
+