changeset 236:8786811a5a59

Fix pcrel
author Windel Bouwman
date Mon, 15 Jul 2013 20:15:31 +0200
parents ff40407c0240
children 81752b0f85a5
files python/asm.py python/codegen.py python/codegenarm.py python/cortexm3.py python/outstream.py python/target.py python/testasm.py
diffstat 7 files changed, 91 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/python/asm.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/asm.py	Mon Jul 15 20:15:31 2013 +0200
@@ -1,7 +1,7 @@
 import re, argparse
 import pyyacc
 from ppci import Token, CompilerError, SourceLocation
-from target import Target
+from target import Target, Label
 from asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber
 
 def tokenize(s):
@@ -141,22 +141,19 @@
 asmParser = Parser()
 
 class Assembler:
-    def __init__(self, target=None):
+    def __init__(self, target=None, stream=None):
         self.target = target
+        self.stream = stream
         self.restart()
         self.p = asmParser
 
     # Top level interface:
     def restart(self):
-        self.output = []
-        self.binout = bytearray()
-        self.current_section = '.text'
+        self.stack = []
 
     def emit(self, a):
         """ Emit a parsed instruction """
-        self.output.append(a)
-        # Determine the bit pattern from a lookup table:
-        # TODO
+        self.stack.append(a)
 
     def parse_line(self, line):
         """ Parse line into asm AST """
@@ -167,7 +164,6 @@
         """ Assemble this source snippet """
         for line in asmsrc.split('\n'):
             self.assemble_line(line)
-        self.back_patch()
 
     def assemble_line(self, line):
         """ 
@@ -182,18 +178,16 @@
         # TODO
         if not self.target:
             raise CompilerError('Cannot assemble without target')
-        while self.output:
-            vi = self.output.pop(0)
+        while self.stack:
+            vi = self.stack.pop(0)
             if type(vi) is AInstruction:
-                ri = self.target.mapInstruction(vi)
-                b = ri.encode()
-                assert type(b) is bytes
-                self.binout.extend(b)
-
-    def back_patch(self):
-        """ Fix references to earlier labels """
-        pass
-        #self.output.backpatch()
+                mi = self.target.mapInstruction(vi)
+            elif type(vi) is ALabel:
+                mi = Label(vi.name)
+            else:
+                raise NotImplementedError('{}'.format(vi))
+            if self.stream:
+                self.stream.emit(mi)
 
 
 if __name__ == '__main__':
--- a/python/codegen.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/codegen.py	Mon Jul 15 20:15:31 2013 +0200
@@ -21,11 +21,10 @@
             print('TODO')
         for f in ircode.Functions:
             for bb in f.BasicBlocks:
-                print(bb)
                 for ins in bb.Instructions:
                     # Instruction selection:
-                    print(ins)
                     #mi = self.tryMap(ins)
+                    pass
         return obj
                         
 
--- a/python/codegenarm.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/codegenarm.py	Mon Jul 15 20:15:31 2013 +0200
@@ -16,7 +16,6 @@
 
     def generate(self, ircode):
         assert isinstance(ircode, ir.Module)
-        print('ARM code generation')
         self.outs.selectSection('data')
 
         for gvar in ircode.Variables:
--- a/python/cortexm3.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/cortexm3.py	Mon Jul 15 20:15:31 2013 +0200
@@ -263,6 +263,11 @@
     def __repr__(self):
         return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset)
 
+def align(x, m):
+    while ((x % m) != 0):
+        x = x + 1
+    return x
+
 @armtarget.instruction
 class ldr_pcrel(ArmInstruction):
     """ ldr Rt, [PC, imm8], store value into memory """
@@ -276,8 +281,8 @@
 
     def resolve(self, f):
         la = f(self.label.name)
-        print(la)
-        self.offset = (la - self.address) + 4
+        sa = align(self.address + 2, 4)
+        self.offset = (la - sa)
         if self.offset < 0:
             self.offset = 0
 
@@ -288,7 +293,6 @@
         assert imm8 < 256
         assert imm8 >= 0
         h = (0x9 << 11) | (rt << 8) | imm8
-        print(hex(h))
         return u16(h)
 
     def __repr__(self):
--- a/python/outstream.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/outstream.py	Mon Jul 15 20:15:31 2013 +0200
@@ -48,6 +48,7 @@
 
     def dump(self):
         self.backpatch()
+        self.backpatch()
         for s in sorted(self.sections.keys()):
             self.dumpSection(s)
 
@@ -71,3 +72,23 @@
     def dump(self):
         pass
 
+    @property
+    def Data(self):
+        d = self.dump()
+        return bytes(d)
+
+    def dump(self):
+        self.backpatch()
+        self.backpatch()
+        section = list(self.sections.keys())[0]
+        return self.dumpSection(section)
+
+    def dumpSection(self, s):
+        d = bytearray()
+        for i in self.sections[s]:
+            addr = i.address
+            insword = i.encode()
+            assert type(insword) is bytes
+            d.extend(insword)
+        return d
+
--- a/python/target.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/target.py	Mon Jul 15 20:15:31 2013 +0200
@@ -152,6 +152,9 @@
         """ Map ast tree to real instruction for this target """
 
         # map to real operands:
+        if vi.mnemonic.upper() == 'ALIGN' and len(vi.operands) == 1:
+            if type(vi.operands[0]) == ANumber:
+                return Alignment(vi.operands[0].number)
 
         # look for a suitable instruction
         for ic in self.instructions:
--- a/python/testasm.py	Mon Jul 15 17:20:37 2013 +0200
+++ b/python/testasm.py	Mon Jul 15 20:15:31 2013 +0200
@@ -6,6 +6,8 @@
 from asm import tokenize, Assembler
 import msp430
 import cortexm3 as arm
+import outstream
+from target import Label
 
 class AssemblerLexingCase(unittest.TestCase):
     """ Tests the assemblers lexer """
@@ -42,39 +44,39 @@
         asmline = 'lab1: mov rax, rbx'
         self.a.parse_line(asmline)
 
+    def expectTree(self, asmline, stack):
+        self.a.parse_line(asmline)
+        self.assertSequenceEqual(stack, self.a.stack)
+
     def testParse2(self):
         asmline = 'a: mov rax, [rbx + 2]'
-        self.a.parse_line(asmline)
         output = []
         output.append(ALabel('a'))
         output.append(AInstruction('mov', [ASymbol('rax'), AUnop('[]', ASymbol('rbx') + ANumber(2))]))
-        self.assertSequenceEqual(output, self.a.output)
+        self.expectTree(asmline, output)
 
     def testParse3(self):
         # A label must be optional:
         asmline = 'mov rax, 1'
-        self.a.parse_line(asmline)
         output = [AInstruction('mov', [ASymbol('rax'), ANumber(1)])]
-        self.assertSequenceEqual(output, self.a.output)
+        self.expectTree(asmline, output)
 
     def testParse4(self):
         # Test 3 operands:
         asmline = 'add rax, [4*rbx + 22], rcx'
-        self.a.parse_line(asmline)
         ops = []
         ops.append(ASymbol('rax'))
         ops.append(AUnop('[]', ANumber(4) * ASymbol('rbx') + ANumber(22)))
         ops.append(ASymbol('rcx'))
         output = [AInstruction('add', ops)]
-        self.assertSequenceEqual(output, self.a.output)
+        self.expectTree(asmline, output)
 
     def testParse5(self):
         # An instruction must be optional:
         asmline = 'lab1:'
-        self.a.parse_line(asmline)
         output = []
         output.append(ALabel('lab1'))
-        self.assertSequenceEqual(output, self.a.output)
+        self.expectTree(asmline, output)
 
     def testParse6(self):
         # A line can be empty
@@ -99,10 +101,29 @@
         # Compare with nasm output:
         nasmbytes = [0x48, 0x89, 0xd8, 0x48, 0x31, 0xd9, 0x48, 0xff, 0xc1]
 
-class AssemblerMSP430TestCase(unittest.TestCase):
+
+class OustreamTestCase(unittest.TestCase):
+    def test1(self):
+        o = outstream.BinOutputStream()
+        o.selectSection('.text')
+        o.emit(Label('a'))
+        self.assertSequenceEqual(bytes(), o.Data)
+
+
+class AsmTestCaseBase(unittest.TestCase):
+    def feed(self, line):
+        self.a.assemble(line)
+
+    def check(self, hexstr):
+        self.assertSequenceEqual(bytes.fromhex(hexstr), self.o.Data)
+
+
+class AssemblerMSP430TestCase(AsmTestCaseBase):
     def setUp(self):
         self.t = msp430.msp430target
-        self.a = Assembler(target=self.t)
+        self.o = outstream.BinOutputStream()
+        self.o.selectSection('.text')
+        self.a = Assembler(target=self.t, stream=self.o)
 
     def testMapMovInstruction(self):
         i = AInstruction('mov', [ASymbol('r14'), ASymbol('r15')])
@@ -125,39 +146,35 @@
 
     def testMov(self):
         line1 = "mov r14, r15"
-        self.a.assemble_line(line1)
-        self.assertEqual(bytes([0x0F, 0x4E]), self.a.binout)
+        self.feed(line1)
+        self.check('0F4E')
 
     def testMov1337(self):
         line1 = "mov 0x1337, r12"
-        self.a.assemble_line(line1)
-        self.assertEqual(bytes.fromhex('3C403713'), self.a.binout)
+        self.feed(line1)
+        self.check('3C403713')
 
     def testAdd(self):
         line1 = "add r15, r13"
-        self.a.assemble_line(line1)
-        self.assertEqual(bytes.fromhex('0D5F'), self.a.binout)
+        self.feed(line1)
+        self.check('0D5F')
 
     def testReti(self):
         line1 = "reti"
-        self.a.assemble_line(line1)
-        self.assertEqual(bytes([0x0, 0x13]), self.a.binout)
+        self.feed(line1)
+        self.check('0013')
 
     def testMSPinstructionCount(self):
         """ Check that there are 27 instructions """
         self.assertEqual(27, len(self.t.instructions))
 
 
-class AssemblerARMTestCase(unittest.TestCase):
+class AssemblerARMTestCase(AsmTestCaseBase):
     def setUp(self):
         self.t = arm.armtarget
-        self.a = Assembler(target=self.t)
-
-    def feed(self, line):
-        self.a.assemble(line)
-
-    def check(self, hexstr):
-        self.assertSequenceEqual(bytes.fromhex(hexstr), self.a.binout)
+        self.o = outstream.BinOutputStream()
+        self.o.selectSection('.text')
+        self.a = Assembler(target=self.t, stream=self.o)
 
     def testMapOperand(self):
         pass
@@ -196,9 +213,10 @@
 
     def testLdrPcRel(self):
         self.feed('ldr r1, henkie')
+        self.feed('align 4')
         self.feed('dcd 1')
         self.feed('henkie: dcd 2')
-        self.check('04490100000002000000')
+        self.check('014900000100000002000000')
 
     def testCmpRegReg(self):
         self.feed('cmp r0, r1')