changeset 345:b4882ff0ed06

Added more arm isa tests
author Windel Bouwman
date Sun, 02 Mar 2014 17:12:08 +0100
parents 1378c4b027a0
children 3bb7dcfe5529
files python/ppci/assembler.py python/ppci/linker.py python/ppci/target/arm/__init__.py python/ppci/target/arm/instructions.py python/ppci/target/arm/token.py python/ppci/target/basetarget.py python/ppci/target/msp430/msp430.py python/ppci/target/target_list.py python/ppci/target/thumb/armtarget.py test/testarmasm.py test/testthumbasm.py
diffstat 11 files changed, 430 insertions(+), 180 deletions(-) [+]
line wrap: on
line diff
--- a/python/ppci/assembler.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/assembler.py	Sun Mar 02 17:12:08 2014 +0100
@@ -7,10 +7,10 @@
 
 
 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 +100,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)
--- a/python/ppci/linker.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/linker.py	Sun Mar 02 17:12:08 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/target/arm/__init__.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/target/arm/__init__.py	Sun Mar 02 17:12:08 2014 +0100
@@ -1,16 +1,16 @@
 
 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 Mov, Add, Sub, Orr1, B, Bl, Ble, Bgt, Beq
 
-class ArmArmTarget(Target):
+class ArmTarget(Target):
     def __init__(self):
         super().__init__('arm_arm')
 
         # Assembly grammar:
-        self.add_keyword('mov')
         self.add_keyword('r0')
         self.add_keyword('r1')
         self.add_keyword('r2')
@@ -19,6 +19,11 @@
         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_rule('reg', ['r0'], lambda rhs: R0)
         self.add_rule('reg', ['r1'], lambda rhs: R1)
@@ -28,15 +33,45 @@
         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_keyword('mov')
         self.add_instruction(['mov', 'reg', ',', 'imm8'],
                 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('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('bl')
+        self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val))
--- a/python/ppci/target/arm/instructions.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/target/arm/instructions.py	Sun Mar 02 17:12:08 2014 +0100
@@ -3,8 +3,41 @@
 from ..basetarget import Instruction
 
 from .token import ArmToken
-from .registers import R0, SP
+from .registers import R0, SP, ArmRegister
+
+# Helpers:
+
+def rotate_right(v, n):
+    """ bit-wise Rotate right n times """
+    mask = (2**n) - 1
+    mask_bits = v & mask
+    return (v >> n) | (mask_bits << (32 - n))
+
+def rotate_left(v, n):
+    assert n >= 0
+    assert n < 32
+    return rotate_right(v, 32 - n)
 
+masks = [rotate_right(0xFF, i * 2) for i in range(16)]
+#0x000000FF,
+#0xC000007F,
+#0xF000000F,
+#0xFC000003,
+#0xFF000000, # 4
+
+assert masks[4] == 0xFF000000, hex(masks[4])
+
+def encode_imm32(v):
+    """ Bundle 32 bit value into 4 bits rotation and 8 bits value
+     """
+    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:
 
@@ -22,7 +55,7 @@
 
     def encode(self):
         self.token[0:12] = self.imm
-        self.token[12:16] = self.reg.num
+        self.token.Rd = self.reg.num
         self.token[16:20] = 0
         self.token[20] = 0
         self.token[21:28] = 0b0011101
@@ -33,5 +66,129 @@
         return []
 
     def __repr__(self):
-        return 'DCD 0x{0:X}'.format(self.expr)
+        return 'Mov {}, {}'.format(self.reg, self.imm)
+
+
+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()
+
+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')]
+
+
+class BranchBase(BranchBaseRoot):
+    opcode = 0b1010
+
+class BranchLinkBase(BranchBaseRoot):
+    opcode = 0b1011
+
+class Bl(BranchLinkBase):
+    cond = 0xE
+
+class B(BranchBase):
+    cond = 0xE
+
+class Beq(BranchBase):
+    cond = 0x0
+
+class Bgt(BranchBase):
+    cond = 0xC
+
+class Ble(BranchBase):
+    cond = 0xD
+
+
--- a/python/ppci/target/arm/token.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/target/arm/token.py	Sun Mar 02 17:12:08 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:32:27 2014 +0100
+++ b/python/ppci/target/basetarget.py	Sun Mar 02 17:12:08 2014 +0100
@@ -135,6 +135,24 @@
         self.assembler_rules = []
         self.asm_keywords = []
 
+        # 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)
 
--- a/python/ppci/target/msp430/msp430.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/target/msp430/msp430.py	Sun Mar 02 17:12:08 2014 +0100
@@ -40,16 +40,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:32:27 2014 +0100
+++ b/python/ppci/target/target_list.py	Sun Mar 02 17:12:08 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/armtarget.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/python/ppci/target/thumb/armtarget.py	Sun Mar 02 17:12:08 2014 +0100
@@ -146,12 +146,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)
 
--- a/test/testarmasm.py	Sat Mar 01 16:32:27 2014 +0100
+++ b/test/testarmasm.py	Sun Mar 02 17:12:08 2014 +0100
@@ -3,152 +3,11 @@
 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')
-
-    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
@@ -160,3 +19,37 @@
     def testMovImm(self):
         self.feed('mov r4, 100')
         self.check('6440a0e3')
+
+    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')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testthumbasm.py	Sun Mar 02 17:12:08 2014 +0100
@@ -0,0 +1,150 @@
+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
+
+
+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')
+
+    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')
+
+