changeset 354:5477e499b039

Added some sort of string functionality
author Windel Bouwman
date Thu, 13 Mar 2014 18:59:06 +0100
parents b8ad45b3a573
children c2ddc8a36f5e
files kernel/arch/vexpressA9.c3 kernel/kernel.c3 kernel/make.sh kernel/monitor.sh kernel/qemutst.sh python/ppci/buildtasks.py python/ppci/c3/astnodes.py python/ppci/c3/builder.py python/ppci/c3/codegenerator.py python/ppci/c3/grammar.txt python/ppci/c3/parser.py python/ppci/c3/scope.py python/ppci/c3/visitor.py python/ppci/codegen/canon.py python/ppci/ir.py python/ppci/ir2tree.py python/ppci/linker.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/basetarget.py python/pyburg.py test/testarmasm.py test/testc3.py test/testemulation.py util/test_patterns.txt
diffstat 27 files changed, 310 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/kernel/arch/vexpressA9.c3	Sun Mar 09 18:49:10 2014 +0100
+++ b/kernel/arch/vexpressA9.c3	Thu Mar 13 18:59:06 2014 +0100
@@ -2,7 +2,7 @@
 
 function void init()
 {
-    putc(0x65)
+    // putc(65)
 }
 
 function void putc(int c)
--- a/kernel/kernel.c3	Sun Mar 09 18:49:10 2014 +0100
+++ b/kernel/kernel.c3	Thu Mar 13 18:59:06 2014 +0100
@@ -21,26 +21,14 @@
     while(true) {}
 }
 
-function int strlen(string txt)
-{
-
-}
-
-function int getchar(string txt, int index)
-{
-    if (index < strlen(txt))
-    {
-    }
-}
-
 function void print(string txt)
 {
     var int i;
     i = 0;
 
-    while (i < strlen(txt))
+    while (i < txt->len)
     {
-        arch.putc(getchar(txt, i));
+        arch.putc(cast<int>(txt->txt[i]));
         i = i + 1;
     }
 }
--- a/kernel/make.sh	Sun Mar 09 18:49:10 2014 +0100
+++ b/kernel/make.sh	Thu Mar 13 18:59:06 2014 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash
 
-../python/zcc.py recipe thumb.yaml
+# ../python/zcc.py recipe thumb.yaml
 
 ../python/zcc.py --report log.txt recipe arm.yaml
--- a/kernel/monitor.sh	Sun Mar 09 18:49:10 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-socat stdio UNIX-CONNECT:vm.sock
--- a/kernel/qemutst.sh	Sun Mar 09 18:49:10 2014 +0100
+++ b/kernel/qemutst.sh	Thu Mar 13 18:59:06 2014 +0100
@@ -7,8 +7,8 @@
 echo "Trying to run test on stellaris qemu machine"
 
 # -S means halt at start:
-qemu-system-arm -M vexpress-a9 -m 128M -kernel kernel.bin \
-    -monitor unix:vm.sock,server -serial file:output.txt -S -s
+qemu-system-arm -M vexpress-a9 -m 128M -kernel kernel_arm.bin \
+    -serial stdio -s
 
 #sleep 1
 
--- a/python/ppci/buildtasks.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/buildtasks.py	Thu Mar 13 18:59:06 2014 +0100
@@ -57,7 +57,8 @@
 
         for ircode in c3b.build(self.sources, self.includes):
             if not ircode:
-                return
+                # Something went wrong, do not continue the code generation
+                continue
 
             d = {'ircode':ircode}
             self.logger.debug('Verifying code {}'.format(ircode), extra=d)
--- a/python/ppci/c3/astnodes.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/astnodes.py	Thu Mar 13 18:59:06 2014 +0100
@@ -125,6 +125,16 @@
         return 'STRUCT'
 
 
+class ArrayType(Type):
+    """ Array type """
+    def __init__(self, element_type, size):
+        self.element_type = element_type
+        self.size = size
+
+    def __repr__(self):
+        return 'ARRAY {}'.format(self.size)
+
+
 class DefinedType(NamedType):
     """ A named type indicating another type """
     def __init__(self, name, typ, loc):
@@ -225,6 +235,17 @@
         return 'MEMBER {}.{}'.format(self.base, self.field)
 
 
+class Index(Expression):
+    """ Index something, for example an array """
+    def __init__(self, base, i, loc):
+        super().__init__(loc)
+        self.base = base
+        self.i = i
+
+    def __repr__(self):
+        return 'Index {}'.format(self.i)
+
+
 class Unop(Expression):
     """ Operation on one operand """
     def __init__(self, op, a, loc):
--- a/python/ppci/c3/builder.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/builder.py	Thu Mar 13 18:59:06 2014 +0100
@@ -130,4 +130,3 @@
             yield self.cg.gencode(pkg)
         if not all(pkg.ok for pkg in all_pkgs):
             self.ok = False
-            return
--- a/python/ppci/c3/codegenerator.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/codegenerator.py	Thu Mar 13 18:59:06 2014 +0100
@@ -1,4 +1,5 @@
 import logging
+import struct
 from .. import ir
 from .. import irutils
 from . import astnodes as ast
@@ -200,6 +201,8 @@
                 self.emit(ir.Jump(bbfalse))
         else:
             raise NotImplementedError('Unknown cond {}'.format(expr))
+
+        # Check that the condition is a boolean value:
         if not self.equalTypes(expr.typ, self.boolType):
             self.error('Condition must be boolean', expr.loc)
 
@@ -272,6 +275,23 @@
             bt = self.the_type(expr.base.typ)
             offset = ir.Const(bt.fieldOffset(expr.field))
             return ir.Mem(ir.Add(base.e, offset))
+        elif type(expr) is ast.Index:
+            """ Array indexing """
+            base = self.genExprCode(expr.base)
+            idx = self.genExprCode(expr.i)
+            base_typ = self.the_type(expr.base.typ)
+            if not isinstance(base_typ, ast.ArrayType):
+                raise SemanticError('Cannot index non-array type {}'.format(base_typ), expr.base.loc)
+            idx_type = self.the_type(expr.i.typ)
+            if not self.equalTypes(idx_type, self.intType):
+                raise SemanticError('Index must be int not {}'.format(idx_type), expr.i.loc)
+            assert type(base) is ir.Mem
+            element_type = self.the_type(base_typ.element_type)
+            element_size = self.size_of(element_type)
+            expr.typ = base_typ.element_type
+            expr.lvalue = True
+
+            return ir.Mem(ir.Add(base.e, ir.Mul(idx, ir.Const(element_size))))
         elif type(expr) is ast.Literal:
             expr.lvalue = False
             typemap = {int: 'int', float: 'double', bool: 'bool', str:'string'}
@@ -279,7 +299,12 @@
                 expr.typ = self.pkg.scope[typemap[type(expr.val)]]
             else:
                 raise SemanticError('Unknown literal type {}'.format(expr.val), expr.loc)
-            return ir.Const(expr.val)
+            # Construct correct const value:
+            if type(expr.val) is str:
+                cval = struct.pack('<I', len(expr.val)) + expr.val.encode('ascii')
+                return ir.Addr(ir.Const(cval))
+            else:
+                return ir.Const(expr.val)
         elif type(expr) is ast.TypeCast:
             return self.gen_type_cast(expr)
         elif type(expr) is ast.FunctionCall:
@@ -299,6 +324,10 @@
                 isinstance(to_type, ast.PointerType):
             expr.typ = expr.to_type
             return ar
+        elif type(from_type) is ast.BaseType and from_type.name == 'byte' and \
+                type(to_type) is ast.BaseType and to_type.name == 'int':
+            expr.typ = expr.to_type
+            return ar
         else:
             raise SemanticError('Cannot cast {} to {}'
                                 .format(from_type, to_type), expr.loc)
@@ -357,6 +386,8 @@
             return t.bytesize
         elif type(t) is ast.StructureType:
             return sum(self.size_of(mem.typ) for mem in t.mems)
+        elif type(t) is ast.ArrayType:
+            return t.size * self.size_of(t.element_type)
         else:
             raise NotImplementedError(str(t))
 
@@ -395,6 +426,8 @@
                     return False
                 return all(self.equalTypes(am.typ, bm.typ) for am, bm in
                            zip(a.mems, b.mems))
+            elif type(a) is ast.ArrayType:
+                return self.equalTypes(a.element_type, b.element_type)
             else:
                 raise NotImplementedError('{} not implemented'.format(type(a)))
         return False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/c3/grammar.txt	Thu Mar 13 18:59:06 2014 +0100
@@ -0,0 +1,12 @@
+
+
+stmt: if_stmt | while_stmt | for_stmt | assign_stmt | compound_stmt
+
+compound_stmt: '{' stmt ';' stmt ... '}'
+if_stmt: 'if' '(' cond ')' stmt
+assign_stmt: lhs '=' expr
+
+cond:
+
+expr:
+
--- a/python/ppci/c3/parser.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/parser.py	Thu Mar 13 18:59:06 2014 +0100
@@ -1,12 +1,12 @@
 import logging
-from ppci import CompilerError
+from .. import CompilerError
 from .astnodes import Member, Literal, TypeCast, Unop, Binop
 from .astnodes import Assignment, ExpressionStatement, Compound
 from .astnodes import Return, While, If, Empty, For
 from .astnodes import FunctionType, Function, FormalParameter
-from .astnodes import StructureType, DefinedType, PointerType
+from .astnodes import StructureType, DefinedType, PointerType, ArrayType
 from .astnodes import Constant, Variable
-from .astnodes import StructField, Deref
+from .astnodes import StructField, Deref, Index
 from .astnodes import Package
 from .astnodes import Identifier
 from .astnodes import FunctionCall
@@ -105,14 +105,29 @@
         return ids
 
     # Type system
-    def parseTypeSpec(self):
-        # For now, do simple type spec, just parse an ID:
+    def PostFixId(self):
+        pfe = self.PrimaryExpression_Id()
+        while self.Peak in ['.']:
+            if self.hasConsumed('.'):
+                field = self.Consume('ID')
+                pfe = Member(pfe, field.val, field.loc)
+            else:
+                raise Exception()
+        return pfe
+
+    def PrimaryExpression_Id(self):
+        if self.Peak == 'ID':
+            return self.parseDesignator()
+        self.Error('Expected ID, got {0}'.format(self.Peak))
+
+    def parse_type_spec(self):
+        """ Parse type specification """
         if self.Peak == 'struct':
             self.Consume('struct')
             self.Consume('{')
             mems = []
             while self.Peak != '}':
-                mem_t = self.parseTypeSpec()
+                mem_t = self.parse_type_spec()
                 for i in self.parseIdSequence():
                     mems.append(StructField(i.val, mem_t))
                 self.Consume(';')
@@ -122,15 +137,27 @@
             # TODO)
             raise NotImplementedError()
         else:
-            theT = self.PostFixExpression()
-        # Check for pointer suffix:
-        while self.hasConsumed('*'):
-            theT = PointerType(theT)
+            theT = self.PostFixId()
+
+        # Check for pointer or array suffix:
+        while self.Peak in ['*', '[']:
+            if self.hasConsumed('*'):
+                theT = PointerType(theT)
+            elif self.hasConsumed('['):
+                if self.Peak == ']':
+                    size = 0
+                    self.Consume(']')
+                else:
+                    size = self.Expression()
+                    self.Consume(']')
+                theT = ArrayType(theT, size)
+            else:
+                raise Exception()
         return theT
 
     def parseTypeDef(self):
         self.Consume('type')
-        newtype = self.parseTypeSpec()
+        newtype = self.parse_type_spec()
         typename = self.Consume('ID')
         self.Consume(';')
         df = DefinedType(typename.val, newtype, typename.loc)
@@ -139,7 +166,7 @@
     # Variable declarations:
     def parseVarDef(self):
         self.Consume('var')
-        t = self.parseTypeSpec()
+        t = self.parse_type_spec()
         for name in self.parseIdSequence():
             v = Variable(name.val, t)
             v.loc = name.loc
@@ -149,7 +176,7 @@
 
     def parseConstDef(self):
         self.Consume('const')
-        t = self.parseTypeSpec()
+        t = self.parse_type_spec()
         while True:
             name = self.Consume('ID')
             self.Consume('=')
@@ -163,7 +190,7 @@
 
     def parseFunctionDef(self):
         loc = self.Consume('function').loc
-        returntype = self.parseTypeSpec()
+        returntype = self.parse_type_spec()
         fname = self.Consume('ID').val
         f = Function(fname, loc)
         self.addDeclaration(f)
@@ -173,7 +200,7 @@
         parameters = []
         if not self.hasConsumed(')'):
             while True:
-                typ = self.parseTypeSpec()
+                typ = self.parse_type_spec()
                 name = self.Consume('ID')
                 param = FormalParameter(name.val, typ)
                 param.loc = name.loc
@@ -187,7 +214,7 @@
         f.body = self.parseCompound()
         self.currentPart = savePart
 
-    def parseIf(self):
+    def parse_if(self):
         loc = self.Consume('if').loc
         self.Consume('(')
         condition = self.Expression()
@@ -204,7 +231,7 @@
         statements = self.Statement()
         return While(condition, statements, loc)
 
-    def parseFor(self):
+    def parse_for(self):
         loc = self.Consume('for').loc
         self.Consume('(')
         init = self.Statement()
@@ -235,11 +262,11 @@
     def Statement(self):
         # Determine statement type based on the pending token:
         if self.Peak == 'if':
-            return self.parseIf()
+            return self.parse_if()
         elif self.Peak == 'while':
             return self.parseWhile()
         elif self.Peak == 'for':
-            return self.parseFor()
+            return self.parse_for()
         elif self.Peak == '{':
             return self.parseCompound()
         elif self.hasConsumed(';'):
@@ -339,7 +366,7 @@
         if self.Peak == 'cast':
             loc = self.Consume('cast').loc
             self.Consume('<')
-            t = self.parseTypeSpec()
+            t = self.parse_type_spec()
             self.Consume('>')
             self.Consume('(')
             ce = self.Expression()
@@ -363,7 +390,9 @@
         pfe = self.PrimaryExpression()
         while self.Peak in ['[', '.', '->', '(', '++']:
             if self.hasConsumed('['):
-                raise NotImplementedError('Array not yet implemented')
+                i = self.Expression()
+                self.Consume(']')
+                pfe = Index(pfe, i, i.loc)
             elif self.hasConsumed('->'):
                 field = self.Consume('ID')
                 pfe = Deref(pfe, pfe.loc)
@@ -410,3 +439,4 @@
         elif self.Peak == 'ID':
             return self.parseDesignator()
         self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak))
+
--- a/python/ppci/c3/scope.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/scope.py	Thu Mar 13 18:59:06 2014 +0100
@@ -1,4 +1,6 @@
 from .astnodes import Constant, Variable, Function, BaseType, Symbol
+from .astnodes import ArrayType, StructureType, DefinedType, PointerType
+from .astnodes import StructField
 
 
 class Scope:
@@ -72,6 +74,13 @@
     scope.addSymbol(BaseType('double'))
     scope.addSymbol(BaseType('void'))
     scope.addSymbol(BaseType('bool'))
-    scope.addSymbol(BaseType('string'))
-    scope.addSymbol(BaseType('byte'))
+    byteType = BaseType('byte')
+    byteType.bytesize = target.byte_sizes['byte']
+    scope.addSymbol(byteType)
+
+    # Construct string type from others:
+    ln = StructField('len', intType)
+    txt = StructField('txt', ArrayType(byteType, 0))
+    strType = DefinedType('string', PointerType(StructureType([ln, txt])), None)
+    scope.addSymbol(strType)
     return scope
--- a/python/ppci/c3/visitor.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/c3/visitor.py	Thu Mar 13 18:59:06 2014 +0100
@@ -61,6 +61,9 @@
             self.do(node.to_type)
         elif type(node) is Member:
             self.do(node.base)
+        elif type(node) is Index:
+            self.do(node.base)
+            self.do(node.i)
         elif type(node) is Deref:
             self.do(node.ptr)
         elif type(node) is Constant:
@@ -75,6 +78,9 @@
         elif type(node) is StructureType:
             for m in node.mems:
                 self.do(m.typ)
+        elif type(node) is ArrayType:
+            self.do(node.element_type)
+            self.do(node.size)
         elif type(node) is FunctionType:
             for pt in node.parametertypes:
                 self.do(pt)
--- a/python/ppci/codegen/canon.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/codegen/canon.py	Thu Mar 13 18:59:06 2014 +0100
@@ -64,13 +64,16 @@
     elif isinstance(exp, ir.Mem):
         exp.e = rewriteExp(exp.e, frame)
         return exp
+    elif isinstance(exp, ir.Addr):
+        exp.e = rewriteExp(exp.e, frame)
+        return exp
     elif isinstance(exp, ir.Call):
         exp.arguments = [rewriteExp(p, frame) for p in exp.arguments]
         # Rewrite call into eseq:
         t = newTemp()
         return ir.Eseq(ir.Move(t, exp), t)
     else:
-        raise NotImplementedError('NI: {}'.format(exp))
+        raise NotImplementedError('NI: {}, {}'.format(exp, type(exp)))
         
 # The flatten functions pull out seq instructions to the sequence list.
 
@@ -86,6 +89,9 @@
     elif isinstance(exp, ir.Mem):
         exp.e, s = flattenExp(exp.e)
         return exp, s
+    elif isinstance(exp, ir.Addr):
+        exp.e, s = flattenExp(exp.e)
+        return exp, s
     elif isinstance(exp, ir.Eseq):
         s = flattenStmt(exp.stmt)
         exp.e, se = flattenExp(exp.e)
--- a/python/ppci/ir.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/ir.py	Thu Mar 13 18:59:06 2014 +0100
@@ -214,7 +214,7 @@
         self.arguments = arguments
 
     def __repr__(self):
-        args = ', '.join([str(arg) for arg in self.arguments])
+        args = ', '.join(str(arg) for arg in self.arguments)
         return '{}({})'.format(self.f, args)
 
 
@@ -309,6 +309,15 @@
         return '[{}]'.format(self.e)
 
 
+class Addr(Expression):
+    """ Address of label """
+    def __init__(self, e):
+        self.e = e
+
+    def __repr__(self):
+        return '&{}'.format(self.e)
+
+
 class Statement:
     """ Base class for all instructions. """
     @property
--- a/python/ppci/ir2tree.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/ir2tree.py	Thu Mar 13 18:59:06 2014 +0100
@@ -27,14 +27,26 @@
 
 @register(ir.Const)
 def const_to_tree(e):
-    t = Tree('CONSTI32')
-    t.value = e.value
-    return t
+    if type(e.value) is bytes:
+        t = Tree('CONSTDATA')
+        t.value = e.value
+        print(t.value)
+        return t
+    elif type(e.value) is int:
+        t = Tree('CONSTI32')
+        t.value = e.value
+        return t
+    else:
+        raise Exception('{} not implemented'.format(type(e.value)))
 
 @register(ir.Mem)
 def mem_to_tree(e):
     return Tree('MEMI32', makeTree(e.e))
 
+@register(ir.Addr)
+def mem_to_tree(e):
+    return Tree('ADR', makeTree(e.e))
+
 @register(ir.Call)
 def call_to_tree(e):
     t = Tree('CALL')
--- a/python/ppci/linker.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/linker.py	Thu Mar 13 18:59:06 2014 +0100
@@ -103,6 +103,21 @@
     section.data[reloc.offset+1] |= (offset >> 8) & 0xF
     section.data[reloc.offset+0] = offset & 0xFF
 
+@reloc('adr_imm12')
+def apply_adr_imm12(reloc, sym, section, reloc_value):
+    assert sym.value % 4 == 0
+    assert reloc_value % 4 == 0
+    offset = (sym.value - (reloc_value + 8))
+    U = 2
+    if offset < 0:
+        offset = -offset
+        U = 1
+    assert offset < 4096
+    section.data[reloc.offset+2] |= (U << 6) #(rel24 >> 16) & 0xFF
+    section.data[reloc.offset+1] |= (offset >> 8) & 0xF
+    section.data[reloc.offset+0] = offset & 0xFF
+
+
 class Linker:
     """ Merges the sections of several object files and 
         performs relocation """
--- a/python/ppci/target/arm/__init__.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/target/arm/__init__.py	Thu Mar 13 18:59:06 2014 +0100
@@ -4,9 +4,9 @@
 from ..arm.registers import R8, R9, R10, R11, R12, SP, LR, PC
 from ..arm.registers import register_range
 
-from .instructions import Dcd, Mov, Add, Sub, Orr1, Mul, Mov2, Add1
+from .instructions import Dcd, Mov, Add, Sub, Orr1, Mul, Mov2, Add1, Mul1
 from .instructions import B, Bl, Ble, Bgt, Beq, Blt, Cmp, Cmp2
-from .instructions import Push, Pop, Str, Ldr, Ldr3, Str1, Ldr1
+from .instructions import Push, Pop, Str, Ldr, Ldr3, Str1, Ldr1, Adr
 from .selector import ArmInstructionSelector
 from .frame import ArmFrame
 
@@ -20,9 +20,11 @@
         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(Adr, lambda im: Adr(im.dst[0], im.others[0]))
         self.add_lowering(Mov2, lambda im: Mov2(im.dst[0], im.src[0]))
         self.add_lowering(Cmp2, lambda im: Cmp2(im.src[0], im.src[1]))
         self.add_lowering(Add1, lambda im: Add1(im.dst[0], im.src[0], im.src[1]))
+        self.add_lowering(Mul1, lambda im: Mul1(im.dst[0], im.src[0], im.src[1]))
 
     def make_parser(self):
         # Assembly grammar:
@@ -134,6 +136,10 @@
         self.add_instruction(['str', 'reg', ',', '[', 'reg', ',', 'reg', ']'],
             lambda rhs: Str(rhs[1], rhs[4], rhs[6]))
 
+        self.add_keyword('adr')
+        self.add_instruction(['adr', 'reg', ',', 'ID'],
+            lambda rhs: Adr(rhs[1], rhs[3].val))
+
         # Register list grammar:
         self.add_rule('reg_list', ['{', 'reg_list_inner', '}'],
             lambda rhs: rhs[1])
--- a/python/ppci/target/arm/arm.brg	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/target/arm/arm.brg	Thu Mar 13 18:59:06 2014 +0100
@@ -1,18 +1,20 @@
 
-from ppci.target.arm.instructions import Add1, Sub1, Ldr1, Ldr3
+from ppci.target.arm.instructions import Add1, Sub1, Mul1
+from ppci.target.arm.instructions import Ldr1, Ldr3, Adr
 
 %%
 
-%terminal ADDI32 SUBI32 MULI32
+%terminal ADDI32 SUBI32 MULI32 ADR
 %terminal ORI32 SHLI32
-%terminal CONSTI32 MEMI32 REGI32 CALL
+%terminal CONSTI32 CONSTDATA 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: MULI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Mul1, 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 .)
 reg: MEMI32(reg) 2 (. d = self.newTmp(); self.emit(Ldr1, dst=[d], src=[$1], others=[0]); return d .)
 
@@ -20,6 +22,9 @@
 cn: CONSTI32 0 (. return $$.value .)
 
 reg: CONSTI32         3 (. d = self.newTmp(); ln = self.selector.frame.add_constant($$.value); self.emit(Ldr3, dst=[d], others=[ln]); return d .)
+
+reg: ADR(CONSTDATA)   2  (. d = self.newTmp(); ln = self.selector.frame.add_constant($$.children[0].value); self.emit(Adr, dst=[d], others=[ln]); return d .)
+
 reg: REGI32           1 (. return $$.value .)
 
 reg: CALL             1 (. return self.selector.munchCall($$.value) .)
--- a/python/ppci/target/arm/frame.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/target/arm/frame.py	Thu Mar 13 18:59:06 2014 +0100
@@ -52,6 +52,7 @@
         return self.locVars[lvar]
 
     def add_constant(self, value):
+        assert type(value) in [int, bytes]
         lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
         self.constants.append((lab_name, value))
         return lab_name
@@ -83,13 +84,13 @@
         for ln, v in self.constants:
             if isinstance(v, int):
                 post.extend([Label(ln), Dcd(v)])
-            elif isinstance(v, str):
-                post.extend([Label(ln), Dcd(len(v))])
+            elif isinstance(v, bytes):
+                post.append(Label(ln))
                 for c in v:
-                    post.append(Db(ord(c)))
+                    post.append(Db(c))
                 post.append(Alignment(4))   # Align at 4 bytes
             else:
-                raise Exception()
+                raise Exception('Constant of type {} not supported'.format(v))
         return post
 
     def EntryExitGlue3(self):
--- a/python/ppci/target/arm/instructions.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/target/arm/instructions.py	Thu Mar 13 18:59:06 2014 +0100
@@ -173,7 +173,7 @@
     return Mul1(args[0], args[1], args[2])
 
 
-class Mul(ArmInstruction):
+class Mul1(ArmInstruction):
     def __init__(self, rd, rn, rm):
         super().__init__()
         self.rd = rd
@@ -211,18 +211,21 @@
         return self.token.encode()
 
     def __repr__(self):
-        return 'add {}, {}, {}'.format(self.rd, self.rn, self.rm)
+        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)
 
 
 class Add1(OpRegRegReg):
+    mnemonic = 'ADD'
     opcode = 0b0000100
 
 
 class Sub1(OpRegRegReg):
+    mnemonic = 'SUB'
     opcode = 0b0000010
 
 
 class Orr1(OpRegRegReg):
+    mnemonic = 'ORR'
     opcode = 0b0001100
 
 
@@ -245,14 +248,16 @@
         return self.token.encode()
 
     def __repr__(self):
-        return 'add {}, {}, {}'.format(self.rd, self.rn, self.imm)
+        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm)
 
 
 class Add2(OpRegRegImm):
+    mnemonic = 'ADD'
     opcode = 0b0010100
 
 
 class Sub2(OpRegRegImm):
+    mnemonic = 'SUB'
     opcode = 0b0010010
 
 
@@ -393,6 +398,7 @@
         return '{} {}, [{}, {}]'.format(self.mnemonic, self.rt, self.rn, 
                 hex(self.offset))
 
+
 class Str1(LdrStrBase):
     opcode = 0b010
     bit20 = 0
@@ -405,6 +411,27 @@
     mnemonic = 'LDR'
 
 
+class Adr(ArmInstruction):
+    def __init__(self, rd, label):
+        super().__init__()
+        self.rd = rd
+        self.label = label
+
+    def __repr__(self):
+        return 'ADR {}, {}'.format(self.rd, self.label)
+
+    def relocations(self):
+        return [(self.label, 'adr_imm12')]
+
+    def encode(self):
+        self.token.cond = AL
+        self.token[0:12] = 0  # Filled by linker
+        self.token[12:16] = self.rd.num
+        self.token[16:20] = 0b1111
+        self.token[25] = 1
+        return self.token.encode()
+
+
 class Ldr3(ArmInstruction):
     """ Load PC relative constant value
         LDR rt, label
--- a/python/ppci/target/basetarget.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/ppci/target/basetarget.py	Thu Mar 13 18:59:06 2014 +0100
@@ -21,6 +21,9 @@
     def encode(self):
         return bytes()
 
+    def __repr__(self):
+        return 'NOP'
+
 
 class PseudoInstruction(Instruction):
     pass
@@ -84,6 +87,7 @@
         self.desc = desc
         self.registers = []
         self.byte_sizes = {'int' : 4}  # For front end!
+        self.byte_sizes['byte'] = 1
 
         # For lowering:
         self.lower_functions = {}
--- a/python/pyburg.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/python/pyburg.py	Thu Mar 13 18:59:06 2014 +0100
@@ -252,11 +252,12 @@
         # TODO: check for rules fullfilled (by not using 999999)
         self.print('            nts = self.nts({})'.format(rule.nr))
         self.print('            kids = self.kids(tree, {})'.format(rule.nr))
-        self.print('            c = sum(x.state.get_cost(y) for x, y in zip(kids, nts)) + {}'.format(rule.cost))
-        self.print('            tree.state.set_cost("{}", c, {})'.format(rule.non_term, rule.nr))
+        self.print('            if all(x.state.has_goal(y) for x, y in zip(kids, nts)):')
+        self.print('                c = sum(x.state.get_cost(y) for x, y in zip(kids, nts)) + {}'.format(rule.cost))
+        self.print('                tree.state.set_cost("{}", c, {})'.format(rule.non_term, rule.nr))
         for cr in self.system.symbols[rule.non_term].chain_rules:
-            self.print('            # Chain rule: {}'.format(cr))
-            self.print('            tree.state.set_cost("{}", c + {}, {})'.format(cr.non_term, cr.cost, cr.nr))
+            self.print('                # Chain rule: {}'.format(cr))
+            self.print('                tree.state.set_cost("{}", c + {}, {})'.format(cr.non_term, cr.cost, cr.nr))
 
     def emit_state(self):
         """ Emit a function that assigns a new state to a node """
--- a/test/testarmasm.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/test/testarmasm.py	Thu Mar 13 18:59:06 2014 +0100
@@ -95,6 +95,16 @@
         self.feed('mul r4,r5,r2')
         self.check('174045e2 ffffffba 950204e0')
 
+    def testAdr(self):
+        self.feed('adr r5, cval')
+        self.feed('adr r9, cval')
+        self.feed('adr r8, cval')
+        self.feed('cval:')
+        self.feed('adr r11, cval')
+        self.feed('adr r12, cval')
+        self.feed('adr r1, cval')
+        self.check('04508fe2 00908fe2 04804fe2 08b04fe2 0cc04fe2 10104fe2')
+
 
 if __name__ == '__main__':
     unittest.main()
--- a/test/testc3.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/test/testc3.py	Thu Mar 13 18:59:06 2014 +0100
@@ -343,6 +343,45 @@
         """
         self.expectErrors(snippet, [5])
 
+    def testArray(self):
+        snippet = """
+         module testarray;
+         function void t()
+         {
+            var int[100] x;
+            var int a, b;
+            a = 2;
+            b = x[a*2+9 - a] * x[22+12];
+            x[1] = x[2];
+         }
+        """
+        self.expectOK(snippet)
+
+    def testArrayFail(self):
+        snippet = """
+         module testarray;
+         function void t()
+         {
+            var bool c;
+            c = false;
+            var int[100] x;
+            x[1] = x[c];
+         }
+        """
+        self.expectErrors(snippet, [8])
+
+    def testArrayFail2(self):
+        snippet = """
+         module testarray;
+         function void t()
+         {
+            var int c;
+            var int x;
+            c = x[2];
+         }
+        """
+        self.expectErrors(snippet, [7])
+
     def testStructCall(self):
         snippet = """
          module teststruct1;
--- a/test/testemulation.py	Sun Mar 09 18:49:10 2014 +0100
+++ b/test/testemulation.py	Thu Mar 13 18:59:06 2014 +0100
@@ -80,7 +80,7 @@
         recipe = os.path.join(testdir, '..', 'kernel', 'arm.yaml')
         self.buildRecipe(recipe)
         data = self.runQemu('../kernel/kernel_arm.bin', machine='vexpress-a9')
-        self.assertEqual('e', data[0])
+        self.assertEqual('Welcome to lcfos!', data)
 
 
 if __name__ == '__main__':
--- a/util/test_patterns.txt	Sun Mar 09 18:49:10 2014 +0100
+++ b/util/test_patterns.txt	Thu Mar 13 18:59:06 2014 +0100
@@ -28,3 +28,12 @@
 ===
 cmp r4, r11
 cmp r5, #0x50000
+===
+adr r5, cval
+adr r9, cval
+adr r8, cval
+cval:
+adr r11, cval
+adr r12, cval
+adr r1, cval
+pop {r2}