# HG changeset patch # User Windel Bouwman # Date 1373912131 -7200 # Node ID 8786811a5a59b845221d343adec8b51e5dba6e85 # Parent ff40407c024016991b62539a872487cfb5dbedc3 Fix pcrel diff -r ff40407c0240 -r 8786811a5a59 python/asm.py --- 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__': diff -r ff40407c0240 -r 8786811a5a59 python/codegen.py --- 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 diff -r ff40407c0240 -r 8786811a5a59 python/codegenarm.py --- 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: diff -r ff40407c0240 -r 8786811a5a59 python/cortexm3.py --- 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): diff -r ff40407c0240 -r 8786811a5a59 python/outstream.py --- 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 + diff -r ff40407c0240 -r 8786811a5a59 python/target.py --- 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: diff -r ff40407c0240 -r 8786811a5a59 python/testasm.py --- 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')