# HG changeset patch # User Windel Bouwman # Date 1370624397 -7200 # Node ID a690473b79e2f1a14852e455a4dd1f5924338150 # Parent 33d50727a23c067b74ed742cd7b8f24e47ef5e0b Added msp430 target diff -r 33d50727a23c -r a690473b79e2 python/asm.py --- a/python/asm.py Sat Jun 01 13:11:22 2013 +0200 +++ b/python/asm.py Fri Jun 07 18:59:57 2013 +0200 @@ -1,10 +1,7 @@ import re, sys, argparse import pyyacc from ppci import Token, CompilerError, SourceLocation - - -# Generic assembler: -keywords = ['global', 'db'] +from target import Target def tokenize(s): """ @@ -34,13 +31,8 @@ if typ == 'NEWLINE': line_start = pos line += 1 - elif typ == 'COMMENTS': - pass elif typ != 'SKIP': - if typ == 'ID': - if val in keywords: - typ = val - elif typ == 'LEESTEKEN': + if typ == 'LEESTEKEN': typ = val elif typ == 'NUMBER': val = int(val) @@ -122,12 +114,14 @@ class ANumber(AExpression): def __init__(self, n): + assert type(n) is int self.n = n def __repr__(self): return '{0}'.format(self.n) class Assembler: - def __init__(self): + def __init__(self, target=None): + self.target = target self.output = [] # Construct a parser given a grammar: ident = lambda x: x # Identity helper function @@ -174,9 +168,6 @@ return ops def p_mem_op(self, brace_open, exp, brace_close): return AUnop('[]', exp) - def handle_ins(self, id0, operands): - ins = AInstruction(id0) - self.emit(ins) def p_label(self, lname, cn): lab = ALabel(lname) self.emit(lab) @@ -189,6 +180,9 @@ return ANumber(n) # Top level interface: + def restart(self): + pass + def emit(self, a): """ Emit a parsed instruction """ self.output.append(a) @@ -217,7 +211,12 @@ def assemble_aast(self): """ Assemble a parsed asm line """ - pass + # TODO + if not self.target: + raise CompilerError('Cannot assemble without target') + while self.output: + i = self.output.pop(0) + self.target.createInstruction(i) def back_patch(self): """ Fix references to earlier labels """ diff -r 33d50727a23c -r a690473b79e2 python/msp430.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/msp430.py Fri Jun 07 18:59:57 2013 +0200 @@ -0,0 +1,32 @@ +from target import Register, Instruction, Target + +# Target description for the MSP430 processor + +class MSP430Reg(Register): + def __init__(self, num, name): + super().__init__(name) + self.num = num + +# 8 bit variants: +PCB = MSP430Reg(0, 'r0') +R14B = MSP430Reg(14, 'r14') +R15B = MSP430Reg(15, 'r15') + +# .. etc + +#GR8 = RegisterClass((PCB, R15B)) + +class TwoOpArith(Instruction): + def __init__(self, opc, name): + super().__init__(opc) + self.name = name + +mov_ins = TwoOpArith(4, 'mov') +add_ins = TwoOpArith(5, 'add') + +class MSP430(Target): + def __init__(self): + self.registers = [PCB, R14B, R15B] + self.instructions = [mov_ins, add_ins] + + diff -r 33d50727a23c -r a690473b79e2 python/target.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/target.py Fri Jun 07 18:59:57 2013 +0200 @@ -0,0 +1,26 @@ + +""" + Base classes for defining a target +""" + +# Machine code interface: +class Operand: + """ Single machine operand """ + pass + +class Register(Operand): + def __init__(self, name): + self.name = name + +class Instruction: + def __init__(self, opcode): + self.opcode = opcode + +class Target: + def __init__(self): + self.instructions = [] + def createInstruction(self, vi): + pass + pass + + diff -r 33d50727a23c -r a690473b79e2 python/testasm.py --- a/python/testasm.py Sat Jun 01 13:11:22 2013 +0200 +++ b/python/testasm.py Fri Jun 07 18:59:57 2013 +0200 @@ -1,8 +1,9 @@ #!/usr/bin/python -import unittest +import unittest, cProfile import ppci from asm import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber, tokenize, Assembler +import msp430 class AssemblerLexingCase(unittest.TestCase): """ Tests the assemblers lexer """ @@ -32,56 +33,50 @@ """ Tests the assembler parts """ + def setUp(self): + self.a = Assembler() def testParse(self): asmline = 'lab1: mov rax, rbx' - a = Assembler() - a.parse_line(asmline) + self.a.parse_line(asmline) def testParse2(self): asmline = 'a: mov rax, [rbx + 2]' - a = Assembler() - a.parse_line(asmline) + self.a.parse_line(asmline) output = [] output.append(ALabel('a')) output.append(AInstruction('mov', [ASymbol('rax'), AUnop('[]', ASymbol('rbx') + ANumber(2))])) - self.assertSequenceEqual(output, a.output) + self.assertSequenceEqual(output, self.a.output) def testParse3(self): # A label must be optional: asmline = 'mov rax, 1' - a = Assembler() - a.parse_line(asmline) - output = [] - output.append(AInstruction('mov', [ASymbol('rax'), ANumber(1)])) - self.assertSequenceEqual(output, a.output) + self.a.parse_line(asmline) + output = [AInstruction('mov', [ASymbol('rax'), ANumber(1)])] + self.assertSequenceEqual(output, self.a.output) def testParse4(self): # Test 3 operands: asmline = 'add rax, [4*rbx + 22], rcx' - a = Assembler() - a.parse_line(asmline) - output = [] + self.a.parse_line(asmline) ops = [] ops.append(ASymbol('rax')) ops.append(AUnop('[]', ANumber(4) * ASymbol('rbx') + ANumber(22))) ops.append(ASymbol('rcx')) - output.append(AInstruction('add', ops)) - self.assertSequenceEqual(output, a.output) + output = [AInstruction('add', ops)] + self.assertSequenceEqual(output, self.a.output) def testParse5(self): # An instruction must be optional: asmline = 'lab1:' - a = Assembler() - a.parse_line(asmline) + self.a.parse_line(asmline) output = [] output.append(ALabel('lab1')) - self.assertSequenceEqual(output, a.output) + self.assertSequenceEqual(output, self.a.output) def testParse6(self): # A line can be empty - a = Assembler() - a.parse_line('') + self.a.parse_line('') class AssemblerOtherTestCase(unittest.TestCase): def testX86(self): @@ -96,6 +91,20 @@ # Compare with nasm output: nasmbytes = [0x48, 0x89, 0xd8, 0x48, 0x31, 0xd9, 0x48, 0xff, 0xc1] +class AssemblerOtherTestCase(unittest.TestCase): + def setUp(self): + self.a = Assembler(target=msp430.MSP430()) + + def testMov(self): + line1 = "mov r14, r15" + self.a.assemble_line(line1) + + def testAdd(self): + line1 = "addw r14, r15" + self.a.assemble_line(line1) + + if __name__ == '__main__': + # cProfile.run('unittest.main()') unittest.main()