# HG changeset patch # User Windel Bouwman # Date 1393684831 -3600 # Node ID 86b02c98a717bd0bafc2fb46c2d06de18703abe1 # Parent 4d204f6f7d4e5ce74b30c913a8827b3039d53805 Moved target directory diff -r 4d204f6f7d4e -r 86b02c98a717 python/outstream.py --- a/python/outstream.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -import binascii -from target import Instruction, DebugInfo, Alignment -from ppci.objectfile import ObjectFile - -""" - The output stream is a stream of instructions that can be output - to a file or binary or hexfile. -""" - - -class OutputStream: - def emit(self, item): - raise NotImplementedError('Abstract base class') - - def selectSection(self, sname): - raise NotImplementedError('Abstract base class') - - -class OutputStreamWriter: - def __init__(self, extra_indent=''): - self.extra_indent = extra_indent - - def dump(self, stream, f): - for s in sorted(stream.sections.keys()): - # print('.section '+ s) - self.dumpSection(stream.sections[s], f) - - def dumpSection(self, s, f): - for i in s.instructions: - if type(i) is DebugInfo: - continue - addr = i.address - insword = i.encode() - assert type(insword) is bytes - insword = binascii.hexlify(bytes(reversed(insword))).decode('ascii') - asm = str(i) - if len(insword) == 0: - print(' {}'.format(asm), file=f) - else: - print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f) - - -class BinaryOutputStream(OutputStream): - """ Output stream that writes to object file """ - def __init__(self, obj_file): - super().__init__() - self.obj_file = obj_file - - def emit(self, item): - """ Encode instruction and add symbol and relocation information """ - assert isinstance(item, Instruction), str(item) + str(type(item)) - assert self.currentSection - section = self.currentSection - address = self.currentSection.Size - b = item.encode() - syms = item.symbols() - relocs = item.relocations() - section.add_data(b) - for sym in syms: - self.obj_file.add_symbol(sym, address, section.name) - for sym, typ in relocs: - self.obj_file.add_relocation(sym, address, typ, section.name) - # Special case for align, TODO do this different? - if type(item) is Alignment: - while section.Size % item.align != 0: - section.add_data(bytes([0])) - - def selectSection(self, sname): - self.currentSection = self.obj_file.get_section(sname) - - -class DummyOutputStream(OutputStream): - def emit(self, item): - pass - - def selectSection(self, sname): - pass diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/assembler.py --- a/python/ppci/assembler.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/assembler.py Sat Mar 01 15:40:31 2014 +0100 @@ -2,7 +2,7 @@ import re import pyyacc from . import Token, CompilerError, SourceLocation -from target import Target, Label +from .target import Target, Label from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber @@ -10,7 +10,7 @@ assert value < (2**31) assert value >= 0 t = 'val32' - for n in [8, 5, 3]: + for n in [16, 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', 'val8', 'val5', 'val3'] + pyyacc.EOF, 'val32', 'val16', 'val8', 'val5', 'val3'] tokens2.extend(kws) self.kws = kws g = pyyacc.Grammar(tokens2) @@ -132,7 +132,7 @@ g.start_symbol = 'asmline' self.emit = emit self.p = g.generate_parser() - print('length of table:', len(self.p.action_table)) + # print('length of table:', len(self.p.action_table)) # Parser handlers: def p_ins_1(self, opc, ops): diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/buildtasks.py --- a/python/ppci/buildtasks.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/buildtasks.py Sat Mar 01 15:40:31 2014 +0100 @@ -15,7 +15,7 @@ from .assembler import Assembler from .objectfile import ObjectFile from .linker import Linker -import outstream +from .outstream import BinaryOutputStream class BuildTask(Task): @@ -32,7 +32,7 @@ super().__init__('Assemble') self.source = source self.output = output_object - self.ostream = outstream.BinaryOutputStream(self.output) + self.ostream = BinaryOutputStream(self.output) self.assembler = Assembler(target, self.ostream) def run(self): @@ -74,7 +74,7 @@ # Code generation: d = {'ircode':ircode} self.logger.debug('Starting code generation for {}'.format(ircode), extra=d) - o = outstream.BinaryOutputStream(self.output) + o = BinaryOutputStream(self.output) cg.generate(ircode, o) if not c3b.ok: diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/codegen/codegen.py --- a/python/ppci/codegen/codegen.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/codegen/codegen.py Sat Mar 01 15:40:31 2014 +0100 @@ -1,6 +1,6 @@ from .. import ir from ..irutils import Verifier -from target import Target +from ..target import Target from ppci import CompilerError from .canon import make as canonicalize from .registerallocator import RegisterAllocator diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/irmach.py --- a/python/ppci/irmach.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/irmach.py Sat Mar 01 15:40:31 2014 +0100 @@ -7,7 +7,7 @@ Instructions are selected and scheduled at this stage. """ -from target import Instruction +from .target import Instruction class Frame: @@ -38,7 +38,7 @@ abstraction of machine instructions. """ def __init__(self, cls, ops=(), src=(), dst=(), jumps=(), others=(), ismove=False): - assert type(cls) is type or isinstance(cls, Instruction) + assert type(cls) is type or isinstance(cls, Instruction), str(cls) self.assem = cls self.ops = tuple(ops) self.src = tuple(src) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/objectfile.py --- a/python/ppci/objectfile.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/objectfile.py Sat Mar 01 15:40:31 2014 +0100 @@ -17,6 +17,8 @@ class Relocation: + """ Represents a relocation entry. A relocation always has a symbol to refer to + and a relocation type """ def __init__(self, sym, offset, typ, section): self.sym = sym self.offset = offset @@ -64,6 +66,7 @@ return sym def add_relocation(self, sym_name, offset, typ, section): + assert type(sym_name) is str, str(sym_name) assert section in self.sections reloc = Relocation(sym_name, offset, typ, section) self.relocations.append(reloc) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/outstream.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/outstream.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,77 @@ +import binascii +from ppci.target import Instruction, DebugInfo, Alignment +from ppci.objectfile import ObjectFile + +""" + The output stream is a stream of instructions that can be output + to a file or binary or hexfile. +""" + + +class OutputStream: + def emit(self, item): + raise NotImplementedError('Abstract base class') + + def selectSection(self, sname): + raise NotImplementedError('Abstract base class') + + +class OutputStreamWriter: + def __init__(self, extra_indent=''): + self.extra_indent = extra_indent + + def dump(self, stream, f): + for s in sorted(stream.sections.keys()): + # print('.section '+ s) + self.dumpSection(stream.sections[s], f) + + def dumpSection(self, s, f): + for i in s.instructions: + if type(i) is DebugInfo: + continue + addr = i.address + insword = i.encode() + assert type(insword) is bytes + insword = binascii.hexlify(bytes(reversed(insword))).decode('ascii') + asm = str(i) + if len(insword) == 0: + print(' {}'.format(asm), file=f) + else: + print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f) + + +class BinaryOutputStream(OutputStream): + """ Output stream that writes to object file """ + def __init__(self, obj_file): + super().__init__() + self.obj_file = obj_file + + def emit(self, item): + """ Encode instruction and add symbol and relocation information """ + assert isinstance(item, Instruction), str(item) + str(type(item)) + assert self.currentSection + section = self.currentSection + address = self.currentSection.Size + b = item.encode() + syms = item.symbols() + relocs = item.relocations() + section.add_data(b) + for sym in syms: + self.obj_file.add_symbol(sym, address, section.name) + for sym, typ in relocs: + self.obj_file.add_relocation(sym, address, typ, section.name) + # Special case for align, TODO do this different? + if type(item) is Alignment: + while section.Size % item.align != 0: + section.add_data(bytes([0])) + + def selectSection(self, sname): + self.currentSection = self.obj_file.get_section(sname) + + +class DummyOutputStream(OutputStream): + def emit(self, item): + pass + + def selectSection(self, sname): + pass diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/recipe.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/recipe.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,71 @@ +import os +import yaml + +from .buildtasks import Compile, Assemble, Link +from .objectfile import ObjectFile +from .target.target_list import target_list + + +targets = {t.name: t for t in target_list} +targetnames = list(targets.keys()) + +class RecipeLoader: + """ Loads a recipe into a runner from a dictionary or file """ + def __init__(self): + self.directive_handlers = {} + for a in dir(self): + if a.startswith('handle_'): + f = getattr(self, a) + self.directive_handlers[a[7:]] = f + + def load_file(self, recipe_file, runner): + """ Loads a recipe dictionary into a task runner """ + self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) + with open(recipe_file, 'r') as f: + recipe = yaml.load(f) + self.runner = runner + self.load_dict(recipe) + + def relpath(self, filename): + return os.path.join(self.recipe_dir, filename) + + def openfile(self, filename): + return open(self.relpath(filename), 'r') + + def handle_compile(self, value): + sources = [self.openfile(s) for s in value['sources']] + includes = [self.openfile(i) for i in value['includes']] + target = targets[value['machine']] + output = ObjectFile() + task = Compile(sources, includes, target, output) + self.runner.add_task(task) + return task + + def handle_assemble(self, value): + asm_src = self.openfile(value['source']) + target = targets[value['machine']] + output = ObjectFile() + task = Assemble(asm_src, target, output) + self.runner.add_task(task) + return task + + def handle_link(self, value): + inputs = value['inputs'] + objs = [] + for i in inputs: + task = self.load_dict(i) + objs.append(task.output) + layout = value['layout'] + output = self.relpath(value['output']) + self.runner.add_task(Link(objs, layout, output)) + + def handle_apps(self, value): + for a in value: + self.load_dict(a) + + def load_dict(self, recipe): + for command, value in recipe.items(): + return self.directive_handlers[command](value) + + + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/report.py --- a/python/ppci/report.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/report.py Sat Mar 01 15:40:31 2014 +0100 @@ -2,7 +2,7 @@ import logging import io -import outstream +from . import outstream from .c3 import AstPrinter from . import logformat from .irutils import Writer diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/__init__.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment +from .basetarget import Imm32, DebugInfo + + +class SimpleTarget(Target): + def __init__(self): + super().__init__('SimpleTarget') diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/arm/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/arm/__init__.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,42 @@ + +from ..basetarget import Target +from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC +from ..arm.registers import register_range + +from .instructions import Mov + +class ArmArmTarget(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') + self.add_keyword('r3') + self.add_keyword('r4') + self.add_keyword('r5') + self.add_keyword('r6') + self.add_keyword('r7') + + self.add_rule('reg', ['r0'], lambda rhs: R0) + self.add_rule('reg', ['r1'], lambda rhs: R1) + self.add_rule('reg', ['r2'], lambda rhs: R2) + self.add_rule('reg', ['r3'], lambda rhs: R3) + self.add_rule('reg', ['r4'], lambda rhs: R4) + 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_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) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/arm/armv7.lidl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/arm/armv7.lidl Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,36 @@ + +# This file specifies the encoding of the arm instruction set. + +fields { + word16 16 { + opcode 15:12 + top2 15:14 + top6 15:10 + data_opcode 9..6 + opB 11:9 + Rm 8:6 + Rn 5:3 + Rt 2:0 + } +} + +patterns { + add = 0 + sub, mul = 1..2 + [r1, r2, r3, r4, r5] is todo = 1..5 + [STR, STRH, STRB, LDRSB, LDR, LDRH, LDRB, LDRSH] is opcode = 0b0101 & opB = {0 to 7} + + EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = 0..14 + [AND, EOR, LSL, LSR, ASR, ADC, SBC, ROR, TST, RSB, CMP, CMN, ORR, MUL, BIC, MVN] is 0..15 + + memop is STR | STRH | STRB | LDRSB | LDR | LDR | LDRH | LDRB | LDRSH +} + + +constructors +{ + alu rs1, reg_or_imm, rd + memop Rt, [Rn, Rm] is memop & Rt & Rn & Rm +} + + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/arm/instructions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/arm/instructions.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,37 @@ + + +from ..basetarget import Instruction + +from .token import ArmToken +from .registers import R0, SP + + +# Instructions: + +class ArmInstruction(Instruction): + def __init__(self): + self.token = ArmToken() + + +class Mov(ArmInstruction): + """ Mov Rd, imm16 """ + def __init__(self, reg, imm): + super().__init__() + self.reg = reg + self.imm = imm + + def encode(self): + self.token[0:12] = self.imm + self.token[12:16] = self.reg.num + self.token[16:20] = 0 + self.token[20] = 0 + self.token[21:28] = 0b0011101 + self.token.cond = 0xE # Always! + return self.token.encode() + + def relocations(self): + return [] + + def __repr__(self): + return 'DCD 0x{0:X}'.format(self.expr) + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/arm/registers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/arm/registers.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,49 @@ + +from ..basetarget import Register + +class ArmRegister(Register): + def __init__(self, num, name): + super().__init__(name) + self.num = num + + def __repr__(self): + return self.name + + +class Reg8Op(ArmRegister): + pass + + +def get_register(n): + for x in registers: + if x.num == n: + return x + raise Exception('No register found with this number') + +def register_range(a, b): + """ Return set of registers from a to b """ + assert a.num < b.num + return {get_register(n) for n in range(a.num, b.num + 1)} + + +R0 = Reg8Op(0, 'r0') +R1 = Reg8Op(1, 'r1') +R2 = Reg8Op(2, 'r2') +R3 = Reg8Op(3, 'r3') +R4 = Reg8Op(4, 'r4') +R5 = Reg8Op(5, 'r5') +R6 = Reg8Op(6, 'r6') +R7 = Reg8Op(7, 'r7') +R8 = ArmRegister(8, 'r8') +R9 = ArmRegister(9, 'r9') +R10 = ArmRegister(10, 'r10') +R11 = ArmRegister(11, 'r11') +R12 = ArmRegister(12, 'r12') + +# Other registers: +# TODO +SP = ArmRegister(13, 'sp') +LR = ArmRegister(14, 'lr') +PC = ArmRegister(15, 'pc') + +registers = [R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC] diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/arm/token.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/arm/token.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,12 @@ + +from ..token import Token, u32, bit_range + + +class ArmToken(Token): + def __init__(self): + super().__init__(32) + + cond = bit_range(28, 32) + + def encode(self): + return u32(self.bit_value) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/basetarget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/basetarget.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,154 @@ +from ppci.asmnodes import ASymbol, AInstruction, ANumber +from ppci import CompilerError + +""" + Base classes for defining a target +""" + +# Machine code interface: +class Operand: + """ Single machine operand """ + pass + +# standard immediates: + +class ImmBase: + def __init__(self, imm): + assert type(imm) is int + assert imm < self.Max() + self.imm = imm + + @classmethod + def Max(cls): + return 2**cls.bits + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < cls.Max(): + return cls(vop.number) + + +class Imm3(ImmBase): + bits = 3 + + +class Imm7(ImmBase): + bits = 7 + + +class Imm8(ImmBase): + bits = 8 + + +class Imm32(ImmBase): + bits = 32 + + +class Instruction: + """ Base instruction class """ + def encode(self): + return bytes() + + def relocations(self): + return [] + + def symbols(self): + return [] + + +class Nop(Instruction): + """ Instruction that does nothing and has zero size """ + def encode(self): + return bytes() + + +class PseudoInstruction(Instruction): + pass + + +class Label(PseudoInstruction): + def __init__(self, name): + self.name = name + + def __repr__(self): + return '{}:'.format(self.name) + + def symbols(self): + return [self.name] + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + name = vop.name + return cls(name) + + +class Comment(PseudoInstruction): + def __init__(self, txt): + self.txt = txt + + def encode(self): + return bytes() + + def __repr__(self): + return '; {}'.format(self.txt) + + +class Alignment(PseudoInstruction): + def __init__(self, a): + self.align = a + + def __repr__(self): + return 'ALIGN({})'.format(self.align) + + def encode(self): + pad = [] + # TODO + address = 0 + while (address % self.align) != 0: + address += 1 + pad.append(0) + return bytes(pad) + + +class DebugInfo(PseudoInstruction): + def __init__(self, i): + self.info = i + + def __repr__(self): + return 'DebugInfo: {}'.format(self.info) + + +class Register(Operand): + def __init__(self, name): + self.name = name + + +class Target: + def __init__(self, name, desc=''): + self.name = name + self.desc = desc + self.registers = [] + self.byte_sizes = {'int' : 4} # For front end! + + # For assembler: + self.assembler_rules = [] + self.asm_keywords = [] + + def add_keyword(self, kw): + self.asm_keywords.append(kw) + + def add_instruction(self, rhs, f): + self.add_rule('instruction', rhs, f) + + def add_rule(self, lhs, rhs, f): + self.assembler_rules.append((lhs, rhs, f)) + + def instruction(self, cls): + """ Decorator function that registers an instruction to this target """ + self.addInstruction(cls) + return cls + + def addInstruction(self, i): + pass + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/instructionselector.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/instructionselector.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,60 @@ +from ppci import ir +from ppci import irmach +from ppci.irmach import AbstractInstruction as makeIns +from .basetarget import Label + +def genTemps(): + n = 900 + while True: + yield ir.Temp('t{}'.format(n)) + n = n + 1 + + +class InstructionSelector: + """ + Base instruction selector. This class must be overridden by + backends. + """ + def __init__(self): + self.temps = genTemps() + + def newTmp(self): + return self.temps.__next__() + + + def munchFunction(self, f, frame): + # Entry point for instruction selection + assert isinstance(f, ir.Function) + self.targets = {} + # Enter a frame per function: + self.frame = frame + # First define labels: + for bb in f.Blocks: + itgt = makeIns(Label(ir.label_name(bb))) + self.targets[bb] = itgt + # Generate code for all blocks: + for bb in f.Blocks: + self.emit2(self.targets[bb]) + for i in bb.Instructions: + self.munchStm(i) + self.munchStm(ir.Move(self.frame.rv, f.return_value)) + + def move(self, dst, src): + raise NotImplementedError('Not target implemented') + + def emit(self, *args, **kwargs): + """ Abstract instruction emitter """ + i = makeIns(*args, **kwargs) + return self.emit2(i) + + def emit2(self, i): + self.frame.instructions.append(i) + return i + + def munchStm(self, s): + """ Implement this in the target specific back-end """ + raise NotImplementedError() + + def munchExpr(self, e): + """ Implement this in the target specific back-end """ + raise NotImplementedError() diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/msp430/instructions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/msp430/instructions.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,211 @@ + +from ..basetarget import Register, Instruction, Target +from ..token import Token, u16, bit_range +from .registers import Msp430Register + + +class Msp430Token(Token): + def __init__(self): + super().__init__(16) + + condition = bit_range(10, 13) + opcode = bit_range(12, 16) + register = bit_range(0, 4) + destination = bit_range(0, 4) + source = bit_range(8, 12) + bw = bit_range(6, 7) # TODO: actually a single bit! + Ad = bit_range(7, 8) # TODO: actually a single bit! + As = bit_range(4, 6) + + def encode(self): + return u16(self.bit_value) + +REGISTER_MODE = 1 +SYMBOLIC_MODE = 3 +ABSOLUTE_MODE = 4 +#TODO: add more modes! +IMMEDIATE_MODE = 7 + +class Msp430Operand: + pass + +class Msp430DestinationOperand(Msp430Operand): + def __init__(self, param): + if isinstance(param, Msp430Register): + self.reg = param.num + self.Ad = 0 + else: + raise Exception() + + +class Msp430SourceOperand(Msp430Operand): + def __init__(self, param): + if isinstance(param, Msp430Register): + self.reg = param.num + self.As = 0 + self.extra_bytes = bytes() + elif isinstance(param, int): + self.reg = 0 + self.As = 3 + self.extra_bytes = u16(param) + else: + raise Exception() + + +class Msp430Instruction(Instruction): + b = 0 + def __init__(self): + self.token = Msp430Token() + + +class Reti(Msp430Instruction): + def encode(self): + self.token[0:16] = 0x1300 + return self.token.encode() + + +######################### +# Jump instructions: +######################### + +class JumpInstruction(Msp430Instruction): + def __init__(self, target): + super().__init__() + self.target = target + + def encode(self): + self.token.condition = self.condition + self.token.offset = 0 + self.token[13] = 1 + return self.token.encode() + + def relocations(self): + return [(self.target, 'msp_reloc')] + + +class Jnz(JumpInstruction): + condition = 0 + + +class Jz(JumpInstruction): + condition = 1 + + +class Jnc(JumpInstruction): + condition = 2 + + +class Jc(JumpInstruction): + condition = 3 + + +class Jn(JumpInstruction): + condition = 4 + + +class Jge(JumpInstruction): + condition = 5 + + +class Jl(JumpInstruction): + condition = 6 + + +class Jmp(JumpInstruction): + condition = 7 + + +######################### +# Single operand arithmatic: +######################### + + +class OneOpArith(Msp430Instruction): + def __init__(self, op1): + self.op1 = op1 + + def encode(self): + # TODO: + bits[15:10] = '00100' + h1 = (self.opcode << 4) + return pack_ins(h1) + + +def oneOpIns(mne, opc): + """ Helper function to define a one operand arithmetic instruction """ + members = {'opcode': opc} + ins_cls = type(mne + '_ins', (OneOpArith,), members) + + +oneOpIns('rrc', 0) +oneOpIns('swpb', 1) +oneOpIns('rra', 2) +oneOpIns('sxt', 3) +oneOpIns('push', 4) +oneOpIns('call', 5) + + +######################### +# Two operand arithmatic instructions: +######################### + + +class TwoOpArith(Msp430Instruction): + def __init__(self, src, dst): + super().__init__() + self.src = Msp430SourceOperand(src) + self.dst = Msp430DestinationOperand(dst) + + def encode(self): + """ + Smart things have been done by MSP430 designers. + As (2 bits) is the source addressing mode selector. + Ad (1 bit) is the destination adressing mode selector. + For the source there are 7 different addressing mode. + For the destination there are 4. + The trick is to use also the register to distuingish the + different modes. + """ + # TODO: Make memory also possible + self.token.bw = self.b # When b=1, the operation is byte mode + self.token.As = self.src.As + self.token.Ad = self.dst.Ad + self.token.destination = self.dst.reg + self.token.source = self.src.reg + self.token.opcode = self.opcode + return self.token.encode() + self.src.extra_bytes + + +def twoOpIns(mne, opc): + """ Helper function to define a two operand arithmetic instruction """ + members = {'opcode': opc} + ins_cls = type(mne + '_ins', (TwoOpArith,), members) + + +class Mov(TwoOpArith): + """ Moves the source to the destination """ + opcode = 4 + + +# This is equivalent to the helper function twoOpIns: +class Add(TwoOpArith): + """ Adds the source to the destination """ + mnemonic = 'add' + opcode = 5 + + +twoOpIns('addc', 6) +twoOpIns('subc', 7) +twoOpIns('sub', 8) + + +class Cmp(TwoOpArith): + opcode = 9 + + +twoOpIns('dadd', 10) +twoOpIns('bit', 11) +twoOpIns('bic', 12) +twoOpIns('bis', 13) +twoOpIns('xor', 14) +twoOpIns('and', 15) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/msp430/msp430.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/msp430/msp430.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,67 @@ +import struct +import types +from ..basetarget import Register, Instruction, Target +from ppci.asmnodes import ASymbol, ANumber +from ppci import CompilerError +from .registers import r10, r11, r12, r13, r14, r15 +from .instructions import Reti, Mov, Add + +# Create the target class (singleton): + +class Msp430Target(Target): + def __init__(self): + super().__init__('msp430') + + # Registers: + self.add_keyword('r10') + self.add_keyword('r11') + self.add_keyword('r12') + self.add_keyword('r13') + self.add_keyword('r14') + self.add_keyword('r15') + 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_rule('reg', ['r13'], lambda rhs: r13) + self.add_rule('reg', ['r14'], lambda rhs: r14) + self.add_rule('reg', ['r15'], lambda rhs: r15) + + # Instructions rules: + self.add_keyword('mov') + self.add_instruction(['mov', 'reg', ',', 'reg'], + lambda rhs: Mov(rhs[1], rhs[3])) + self.add_instruction(['mov', 'imm16', ',', 'reg'], + lambda rhs: Mov(rhs[1], rhs[3])) + + self.add_keyword('add') + self.add_instruction(['add', 'reg', ',', 'reg'], + lambda rhs: Add(rhs[1], rhs[3])) + + 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() + + +# Target description for the MSP430 processor + + +msp430target.registers.append(r10) +msp430target.registers.append(r11) +msp430target.registers.append(r12) +msp430target.registers.append(r13) +msp430target.registers.append(r14) +msp430target.registers.append(r15) + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/msp430/registers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/msp430/registers.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,18 @@ + +from ..basetarget import Register + +class Msp430Register(Register): + def __init__(self, num, name): + super().__init__(name) + self.num = num + +# 8 bit registers: +PCB = Msp430Register(0, 'r0') +rpc = PCB +r10 = Msp430Register(10, 'r10') +r11 = Msp430Register(11, 'r11') +r12 = Msp430Register(12, 'r12') +r13 = Msp430Register(13, 'r13') +r14 = Msp430Register(14, 'r14') +r15 = Msp430Register(15, 'r15') + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/target_list.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/target_list.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,10 @@ + +from .arm import ArmArmTarget +from .thumb import ThumbTarget +from .msp430.msp430 import msp430target + +# Instance: +arm_target = ArmArmTarget() +thumb_target = ThumbTarget() + +target_list = [arm_target, thumb_target] diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/__init__.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,4 @@ + + +from .armtarget import ThumbTarget + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/arm.brg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/arm.brg Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,31 @@ + +from ppci.target.thumb.instructions import Orr, Lsl, Str2, Ldr2, Ldr3 +from ppci.target.thumb.instructions import B, Bl, Bgt, Blt, Beq, Bne +from ppci.target.thumb.instructions import Mov2, Mov3, Sub3 +from ppci.target.thumb.instructions import Add3, Sub, Cmp, Sub2, Add2, Mul + +%% + +%terminal ADDI32 SUBI32 MULI32 +%terminal ORI32 SHLI32 +%terminal CONSTI32 MEMI32 REGI32 CALL +%terminal MOVI32 + +%% + + +reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add3, dst=[d], src=[$1, $2]); return d .) +reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub3, dst=[d], src=[$1, $2]); return d .) +reg: ORI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Orr, dst=[], src=[d, $2]); return d .) +reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Lsl, dst=[], src=[d, $2]); return d .) +reg: MULI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Mul, dst=[d], src=[$2, d]); return d .) + +reg: CONSTI32 3 (. d = self.newTmp(); ln = self.selector.frame.addConstant($$.value); self.emit(Ldr3, dst=[d], others=[ln]); return d .) +reg: MEMI32(reg) 4 (. d = self.newTmp(); self.emit(Ldr2, dst=[d], src=[$1], others=[0]); return d .) +reg: REGI32 1 (. return $$.value .) +reg: CALL 1 (. return self.selector.munchCall($$.value) .) + + +stmt: MOVI32(MEMI32(addr), reg) 3 (. self.emit(Str2, src=[$1, $2]) .) + +addr: reg 2 (. .) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/armframe.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/armframe.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,96 @@ +from ... import ir +from ..basetarget import Label, Alignment +from ...irmach import makeIns, Frame +from .instructions import Dcd, AddSp, SubSp, Push, Pop, Mov2 +from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP + + +class ArmFrame(Frame): + """ Arm specific frame for functions. """ + def __init__(self, name): + # We use r7 as frame pointer. + super().__init__(name) + self.regs = [R0, R1, R2, R3, R4, R5, R6] + self.rv = ir.Temp('special_RV') + self.p1 = ir.Temp('special_P1') + self.p2 = ir.Temp('special_P2') + self.p3 = ir.Temp('special_P3') + self.p4 = ir.Temp('special_P4') + self.fp = ir.Temp('special_FP') + # Pre-colored registers: + self.tempMap = {} + self.tempMap[self.rv] = R0 + self.tempMap[self.p1] = R1 + self.tempMap[self.p2] = R2 + self.tempMap[self.p3] = R3 + self.tempMap[self.p4] = R4 + self.tempMap[self.fp] = R7 + self.locVars = {} + self.parMap = {} + # Literal pool: + self.constants = [] + + def argLoc(self, pos): + """ + Gets the function parameter location in IR-code format. + """ + if pos == 0: + return self.p1 + elif pos == 1: + return self.p2 + elif pos == 2: + return self.p3 + elif pos == 3: + return self.p4 + else: + raise NotImplementedError('No more than 4 parameters implemented') + + def allocVar(self, lvar): + if lvar not in self.locVars: + self.locVars[lvar] = self.stacksize + self.stacksize = self.stacksize + 4 + return self.locVars[lvar] + + def addConstant(self, value): + lab_name = '{}_literal_{}'.format(self.name, len(self.constants)) + self.constants.append((lab_name, value)) + return lab_name + + def prologue(self): + """ Returns prologue instruction sequence """ + pre = [ + Label(self.name), # Label indication function + Push({LR, R7}) + ] + if self.stacksize > 0: + pre.append(SubSp(self.stacksize)) # Reserve stack space + pre += [ + Mov2(R7, SP) # Setup frame pointer + ] + return pre + + def epilogue(self): + """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """ + post = [] + if self.stacksize > 0: + post.append(AddSp(self.stacksize)) + post += [ + Pop({PC, R7}), + Alignment(4) # Align at 4 bytes + ] + # Add constant literals: + for ln, v in self.constants: + post.extend([Label(ln), Dcd(v)]) + return post + + def EntryExitGlue3(self): + """ + Add code for the prologue and the epilogue. Add a label, the + return instruction and the stack pointer adjustment for the frame. + """ + for index, ins in enumerate(self.prologue()): + self.instructions.insert(index, makeIns(ins)) + + # Postfix code: + for ins in self.epilogue(): + self.instructions.append(makeIns(ins)) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/arminstructionselector.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/arminstructionselector.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,92 @@ +from ... import ir, same_dir +from ppci.irmach import AbstractInstruction as makeIns +from ppci.ir2tree import makeTree +import pyburg +from ..basetarget import Nop +from ..instructionselector import InstructionSelector +from .instructions import Orr, Lsl, Str2, Ldr2, Ldr3 +from .instructions import B, Bl, Bgt, Blt, Beq, Bne +from .instructions import Mov2, Mov3 +from .instructions import Cmp, Sub2, Mul + +# Import BURG spec for arm: +spec_file = same_dir(__file__, 'arm.brg') +arm_matcher = pyburg.load_as_module(spec_file) + + +class ArmMatcher(arm_matcher.Matcher): + """ Matcher that derives from a burg spec generated matcher """ + def __init__(self, selector): + super().__init__() + self.newTmp = selector.newTmp + self.emit = selector.emit + self.selector = selector + + +class ArmInstructionSelector(InstructionSelector): + """ Instruction selector for the arm architecture """ + def __init__(self): + super().__init__() + self.matcher = ArmMatcher(self) + + def munchExpr(self, e): + # Use BURG system here: + t = makeTree(e) + return self.matcher.gen(t) + + def munchCall(self, e): + """ Generate code for call sequence """ + # Move arguments into proper locations: + reguses = [] + for i, a in enumerate(e.arguments): + loc = self.frame.argLoc(i) + m = ir.Move(loc, a) + self.munchStm(m) + if isinstance(loc, ir.Temp): + reguses.append(loc) + self.emit(Bl(e.f), src=reguses, dst=[self.frame.rv]) + d = self.newTmp() + self.move(d, self.frame.rv) + return d + + def munchStm(self, s): + if isinstance(s, ir.Terminator): + pass + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \ + isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \ + isinstance(s.dst.e.b, ir.Const): + a = self.munchExpr(s.dst.e.a) + val = self.munchExpr(s.src) + c = s.dst.e.b.value + self.emit(Str2, others=[c], src=[a, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): + memloc = self.munchExpr(s.dst.e) + val = self.munchExpr(s.src) + self.emit(Str2, others=[0], src=[memloc, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): + val = self.munchExpr(s.src) + dreg = s.dst + self.move(dreg, val) + elif isinstance(s, ir.Exp): + # Generate expression code and discard the result. + x = self.munchExpr(s.e) + self.emit(Nop(), src=[x]) + elif isinstance(s, ir.Jump): + tgt = self.targets[s.target] + self.emit(B(ir.label_name(s.target)), jumps=[tgt]) + elif isinstance(s, ir.CJump): + a = self.munchExpr(s.a) + b = self.munchExpr(s.b) + self.emit(Cmp, src=[a, b]) + ntgt = self.targets[s.lab_no] + ytgt = self.targets[s.lab_yes] + jmp_ins = makeIns(B(ir.label_name(s.lab_no)), jumps=[ntgt]) + opnames = {'<': Blt, '>':Bgt, '==':Beq, '!=':Bne} + op = opnames[s.cond](ir.label_name(s.lab_yes)) + self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough + self.emit2(jmp_ins) + else: + raise NotImplementedError('Stmt --> {}'.format(s)) + + def move(self, dst, src): + self.emit(Mov2, src=[src], dst=[dst], ismove=True) diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/armtarget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/armtarget.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,157 @@ +import struct +from ..basetarget import Register, Instruction, Target, Label, Alignment +from ..basetarget import Imm32, Imm8, Imm7, Imm3 +from .instructions import Add2, Sub, Add3, Cmp, Lsl, Orr, Add, Cmp2 +from .instructions import Dcd, Pop, Push, Yield, Mov2, Mov3 +from .instructions import B, Bl, Bne, Beq, Blt, Bgt +from .instructions import Ldr, Str2, Ldr2, Str1, Ldr1 + +from .armframe import ArmFrame +from .arminstructionselector import ArmInstructionSelector +from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC +from ..arm.registers import register_range + + +""" ARM target description. """ + +# TODO: encode this in DSL (domain specific language) +# TBD: is this required? +# TODO: make a difference between armv7 and armv5? + +thumb_assembly_rules = [] +def add_rule(rhs, f): + thumb_assembly_rules.append(('instruction', rhs, f)) + + +class ThumbTarget(Target): + def __init__(self): + super().__init__('thumb') + self.ins_sel = ArmInstructionSelector() + self.FrameClass = ArmFrame + self.add_rules() + + def add_rules(self): + + # Add instructions: + self.add_keyword('dcd') + self.add_instruction(['dcd', 'imm32'], lambda rhs: Dcd(rhs[1])) + + self.add_keyword('mov') + self.add_instruction(['mov', 'reg8', ',', 'reg8'], + lambda rhs: Mov2(rhs[1], rhs[3])) + + self.add_instruction(['mov', 'reg8', ',', 'imm8'], + lambda rhs: Mov3(rhs[1], rhs[3])) + + self.add_keyword('add') + self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'imm3'], + lambda rhs: Add2(rhs[1], rhs[3], rhs[5])) + + self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'reg8'], + lambda rhs: Add3(rhs[1], rhs[3], rhs[5])) + + self.add_keyword('sub') + self.add_instruction(['sub', 'reg8', ',', 'reg8', ',', 'imm3'], + lambda rhs: Sub(rhs[1], rhs[3], rhs[5])) + + self.add_instruction(['sub', 'sp', ',', 'sp', ',', 'imm8'], + lambda rhs: Sub(SP, SP, rhs[5])) + + self.add_instruction(['add', 'sp', ',', 'sp', ',', 'imm8'], + lambda rhs: Add(SP, SP, rhs[5])) + + self.add_keyword('cmp') + self.add_instruction(['cmp', 'reg8', ',', 'reg8'], + lambda rhs: Cmp(rhs[1], rhs[3])) + self.add_instruction(['cmp', 'reg8', ',', 'imm8'], + lambda rhs: Cmp2(rhs[1], rhs[3])) + + self.add_keyword('lsl') + self.add_instruction(['lsl', 'reg8', ',', 'reg8'], + lambda rhs: Lsl(rhs[1], rhs[3])) + + self.add_keyword('str') + self.add_instruction(['str', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], + lambda rhs: Str2(rhs[1], rhs[4], rhs[6])) + + self.add_keyword('ldr') + self.add_instruction(['ldr', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], + lambda rhs: Ldr2(rhs[1], rhs[4], rhs[6])) + + self.add_instruction(['str', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], + lambda rhs: Str1(rhs[1], rhs[6])) + + self.add_instruction(['ldr', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], + lambda rhs: Ldr1(rhs[1], rhs[6])) + + self.add_keyword('pop') + self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1])) + self.add_keyword('push') + self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1])) + + self.add_keyword('yield') + self.add_instruction(['yield'], lambda rhs: Yield()) + + self.add_keyword('b') + self.add_keyword('bl') + self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val)) + self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val)) + self.add_keyword('beq') + self.add_keyword('bne') + self.add_keyword('blt') + self.add_keyword('bgt') + self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val)) + self.add_instruction(['bne', 'ID'], lambda rhs: Bne(rhs[1].val)) + self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val)) + self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val)) + + self.add_keyword('align') + self.add_instruction(['align', 'imm8'], lambda rhs: Alignment(rhs[1])) + + self.add_instruction(['ldr', 'reg8', ',', 'ID'], + lambda rhs: Ldr(rhs[1], rhs[3].val)) + + # Additional rules: + + # Register list grammar: + self.add_rule('reg_list', ['{', 'reg_list_inner', '}'], + lambda rhs: rhs[1]) + self.add_rule('reg_list_inner', ['reg_or_range'], + lambda rhs: rhs[0]) + self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'], + lambda rhs: rhs[0] | rhs[2]) + self.add_rule('reg_or_range', ['reg8'], lambda rhs: {rhs[0]}) + self.add_rule('reg_or_range', ['lr'], lambda rhs: {LR}) + self.add_rule('reg_or_range', ['pc'], lambda rhs: {PC}) + + self.add_rule('reg_or_range', ['reg8', '-', 'reg8'], + lambda rhs: register_range(rhs[0], rhs[2])) + + self.add_keyword('r0') + self.add_keyword('r1') + self.add_keyword('r2') + self.add_keyword('r3') + self.add_keyword('r4') + self.add_keyword('r5') + self.add_keyword('r6') + self.add_keyword('r7') + self.add_keyword('sp') + self.add_keyword('lr') + self.add_keyword('pc') + self.add_rule('reg8', ['r0'], lambda rhs: R0) + self.add_rule('reg8', ['r1'], lambda rhs: R1) + self.add_rule('reg8', ['r2'], lambda rhs: R2) + self.add_rule('reg8', ['r3'], lambda rhs: R3) + self.add_rule('reg8', ['r4'], lambda rhs: R4) + 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) + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/armtoken.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/armtoken.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,12 @@ + +from ..token import Token, u16, bit_range + +class ThumbToken(Token): + def __init__(self): + super().__init__(16) + + rd = bit_range(0, 3) + + def encode(self): + return u16(self.bit_value) + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/thumb/instructions.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/thumb/instructions.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,536 @@ +from ..basetarget import Register, Instruction, Target, Label +from ..basetarget import Imm32, Imm8, Imm7, Imm3 +from ..token import u16, u32 +from .armtoken import ThumbToken +from ..arm.registers import R0, ArmRegister, SP + + +# Instructions: + +class ThumbInstruction(Instruction): + pass + + +class Dcd(ThumbInstruction): + def __init__(self, expr): + if isinstance(expr, Imm32): + self.expr = expr.imm + self.label = None + elif isinstance(expr, int): + self.expr = expr + self.label = None + else: + raise NotImplementedError() + + def encode(self): + return u32(self.expr) + + def relocations(self): + return [] + + def __repr__(self): + return 'DCD 0x{0:X}'.format(self.expr) + + +class nop_ins(ThumbInstruction): + def encode(self): + return bytes() + + def __repr__(self): + return 'NOP' + + +# Memory related + +class LS_imm5_base(ThumbInstruction): + """ ??? Rt, [Rn, imm5] """ + def __init__(self, rt, rn, imm5): + assert imm5 % 4 == 0 + self.imm5 = imm5 >> 2 + self.rn = rn + self.rt = rt + assert self.rn.num < 8 + assert self.rt.num < 8 + self.token = ThumbToken() + + def encode(self): + Rn = self.rn.num + Rt = self.rt.num + imm5 = self.imm5 + self.token[0:3] = Rt + self.token[3:6] = Rn + self.token[6:11] = imm5 + self.token[11:16] = self.opcode + return self.token.encode() + + def __repr__(self): + mnemonic = "???" + return '{} {}, [{}, {}]'.format(mnemonic, self.rt, self.rn, self.imm5) + + +class Str2(LS_imm5_base): + opcode = 0xC + + @classmethod + def fromim(cls, im): + return cls(im.src[1], im.src[0], im.others[0]) + + +class Ldr2(LS_imm5_base): + opcode = 0xD + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0], im.others[0]) + +class ls_sp_base_imm8(ThumbInstruction): + def __init__(self, rt, offset): + self.rt = rt + self.offset = offset + + def encode(self): + rt = self.rt.num + assert rt < 8 + imm8 = self.offset >> 2 + assert imm8 < 256 + h = (self.opcode << 8) | (rt << 8) | imm8 + return u16(h) + + def __repr__(self): + mnemonic = self.__class__.__name__ + return '{} {}, [sp,#{}]'.format(mnemonic, self.rt, self.offset) + +def align(x, m): + while ((x % m) != 0): + x = x + 1 + return x + +def Ldr(*args): + if len(args) == 2 and isinstance(args[0], ArmRegister) \ + and isinstance(args[1], str): + return Ldr3(*args) + else: + raise Exception() + + +class Ldr3(ThumbInstruction): + """ ldr Rt, LABEL, load value from pc relative position """ + mnemonic = 'ldr' + def __init__(self, rt, label): + self.rt = rt + self.label = label + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.others[0]) + + def relocations(self): + return [(self.label, 'lit_add_8')] + + def encode(self): + rt = self.rt.num + assert rt < 8 + imm8 = 0 + h = (0x9 << 11) | (rt << 8) | imm8 + return u16(h) + + def __repr__(self): + return 'LDR {}, {}'.format(self.rt, self.label) + + +class Ldr1(ls_sp_base_imm8): + """ ldr Rt, [SP, imm8] """ + opcode = 0x98 + + +class Str1(ls_sp_base_imm8): + """ str Rt, [SP, imm8] """ + opcode = 0x90 + + +class Mov3(ThumbInstruction): + """ mov Rd, imm8, move immediate value into register """ + opcode = 4 # 00100 Rd(3) imm8 + def __init__(self, rd, imm): + assert imm < 256 + self.imm = imm + self.rd = rd + self.token = ThumbToken() + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.others[0]) + + def encode(self): + rd = self.rd.num + self.token[8:11] = rd + self.token[0:8] = self.imm + self.token[11:16] = self.opcode + return self.token.encode() + + def __repr__(self): + return 'MOV {}, {}'.format(self.rd, self.imm) + + + +# Arithmatics: + + + +class regregimm3_base(ThumbInstruction): + def __init__(self, rd, rn, imm3): + self.rd = rd + self.rn = rn + assert imm3 < 8 + self.imm3 = imm3 + self.token = ThumbToken() + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0], im.others[0]) + + def encode(self): + rd = self.rd.num + self.token[0:3] = rd + self.token[3:6] = self.rn.num + self.token[6:9] = self.imm3 + self.token[9:16] = self.opcode + return self.token.encode() + + def __repr__(self): + mnemonic = self.__class__.__name__ + return '{} {}, {}, {}'.format(mnemonic, self.rd, self.rn, self.imm3) + + + +class Add2(regregimm3_base): + """ add Rd, Rn, imm3 """ + opcode = 0b0001110 + + +class Sub2(regregimm3_base): + """ sub Rd, Rn, imm3 """ + opcode = 0b0001111 + + +def Sub(*args): + if len(args) == 3 and args[0] is SP and args[1] is SP and \ + isinstance(args[2], int) and args[2] < 256: + return SubSp(args[2]) + elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ + isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ + args[2] < 8: + return Sub2(args[0], args[1], args[2]) + else: + raise Exception() + + +def Add(*args): + if len(args) == 3 and args[0] is SP and args[1] is SP and \ + isinstance(args[2], int) and args[2] < 256: + return AddSp(args[2]) + elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ + isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ + args[2] < 8: + return Add2(args[0], args[1], args[2]) + else: + raise Exception() + + +class regregreg_base(ThumbInstruction): + """ ??? Rd, Rn, Rm """ + def __init__(self, rd, rn, rm): + self.rd = rd + self.rn = rn + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0], im.src[1]) + + def encode(self): + at = ThumbToken() + at.rd = self.rd.num + rn = self.rn.num + rm = self.rm.num + at[3:6] = rn + at[6:9] = rm + at[9:16] = self.opcode + return at.encode() + + def __repr__(self): + return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) + + +class Add3(regregreg_base): + mnemonic = 'ADD' + opcode = 0b0001100 + + +class Sub3(regregreg_base): + mnemonic = 'SUB' + opcode = 0b0001101 + + +class Mov2(ThumbInstruction): + """ mov rd, rm """ + mnemonic = 'MOV' + def __init__(self, rd, rm): + self.rd = rd + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.dst[0], im.src[0]) + + def encode(self): + at = ThumbToken() + at.rd = self.rd.num & 0x7 + D = (self.rd.num >> 3) & 0x1 + Rm = self.rm.num + opcode = 0b01000110 + at[8:16] = opcode + at[3:7] = Rm + at[7] = D + return at.encode() + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) + + +class Mul(ThumbInstruction): + """ mul Rn, Rdm """ + mnemonic = 'MUL' + def __init__(self, rn, rdm): + self.rn = rn + self.rdm = rdm + + @classmethod + def fromim(cls, im): + assert im.src[1] is im.dst[0] + return cls(im.src[0], im.dst[0]) + + def encode(self): + at = ThumbToken() + rn = self.rn.num + at.rd = self.rdm.num + opcode = 0b0100001101 + #h = (opcode << 6) | (rn << 3) | rdm + at[6:16] = opcode + at[3:6] = rn + return at.encode() + + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) + + +class regreg_base(ThumbInstruction): + """ ??? Rdn, Rm """ + def __init__(self, rdn, rm): + self.rdn = rdn + self.rm = rm + + @classmethod + def fromim(cls, im): + return cls(im.src[0], im.src[1]) + + def encode(self): + at = ThumbToken() + at.rd = self.rdn.num + rm = self.rm.num + at[3:6] = rm + at[6:16] = self.opcode + return at.encode() + + def __repr__(self): + mnemonic = self.__class__.__name__ + return '{} {}, {}'.format(mnemonic, self.rdn, self.rm) + + +class movregreg_ins(regreg_base): + """ mov Rd, Rm (reg8 operands) """ + opcode = 0 + + +class And(regreg_base): + opcode = 0b0100000000 + + +class Orr(regreg_base): + opcode = 0b0100001100 + + +class Cmp(regreg_base): + opcode = 0b0100001010 + + +class Lsl(regreg_base): + opcode = 0b0100000010 + + +class Cmp2(ThumbInstruction): + """ cmp Rn, imm8 """ + opcode = 5 # 00101 + def __init__(self, rn, imm): + self.rn = rn + self.imm = imm + + def encode(self): + at = ThumbToken() + at[0:8] = self.imm + at[8:11] = self.rn.num + at[11:16] = self.opcode + return at.encode() + + +# Jumping: + +class jumpBase_ins(ThumbInstruction): + def __init__(self, target_label): + assert type(target_label) is str + self.target = target_label + self.offset = 0 + + def __repr__(self): + mnemonic = self.__class__.__name__ + return '{} {}'.format(mnemonic, self.target) + + +class B(jumpBase_ins): + def encode(self): + h = (0b11100 << 11) | 0 + # | 1 # 1 to enable thumb mode + return u16(h) + + def relocations(self): + return [(self.target, 'wrap_new11')] + +class Bl(jumpBase_ins): + def encode(self): + imm11 = 0 + imm10 = 0 + j1 = 1 # TODO: what do these mean? + j2 = 1 + s = 0 + h1 = (0b11110 << 11) | (s << 10) | imm10 + h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 + return u16(h1) + u16(h2) + + def relocations(self): + return [(self.target, 'bl_imm11_imm10')] + + +class cond_base_ins(jumpBase_ins): + def encode(self): + imm8 = 0 + h = (0b1101 << 12) | (self.cond << 8) | imm8 + return u16(h) + + def relocations(self): + return [(self.target, 'rel8')] + + +class cond_base_ins_long(jumpBase_ins): + """ Encoding T3 """ + def encode(self): + j1 = 1 # TODO: what do these mean? + j2 = 1 + h1 = (0b11110 << 11) | (self.cond << 6) + h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) + return u16(h1) + u16(h2) + + def relocations(self): + return [(self.target, 'b_imm11_imm6')] + + +class Beq(cond_base_ins): + cond = 0 + + +class Bne(cond_base_ins): + cond = 1 + + +class Blt(cond_base_ins): + cond = 0b1011 + + +class Bgt(cond_base_ins): + cond = 0b1100 + + +class Push(ThumbInstruction): + def __init__(self, regs): + assert type(regs) is set + self.regs = regs + + def __repr__(self): + return 'Push {{{}}}'.format(self.regs) + + def encode(self): + at = ThumbToken() + for n in register_numbers(self.regs): + if n < 8: + at[n] = 1 + elif n == 14: + at[8] = 1 + else: + raise NotImplementedError('not implemented for {}'.format(n)) + at[9:16] = 0x5a + return at.encode() + + + +def register_numbers(regs): + for r in regs: + yield r.num + +class Pop(ThumbInstruction): + def __init__(self, regs): + assert type(regs) is set + self.regs = regs + self.token = ThumbToken() + + def __repr__(self): + return 'Pop {{{}}}'.format(self.regs) + + def encode(self): + for n in register_numbers(self.regs): + if n < 8: + self.token[n] = 1 + elif n == 15: + self.token[8] = 1 + else: + raise NotImplementedError('not implemented for this register') + self.token[9:16] = 0x5E + return self.token.encode() + + + +class Yield(ThumbInstruction): + def encode(self): + return u16(0xbf10) + +# misc: + +# add/sub SP: +class addspsp_base(ThumbInstruction): + def __init__(self, imm7): + self.imm7 = imm7 + assert self.imm7 % 4 == 0 + self.imm7 >>= 2 + + def encode(self): + return u16((self.opcode << 7) | self.imm7) + + def __repr__(self): + mnemonic = self.__class__.__name__ + return '{} sp, sp, {}'.format(mnemonic, self.imm7 << 2) + + +class AddSp(addspsp_base): + opcode = 0b101100000 + + +class SubSp(addspsp_base): + opcode = 0b101100001 diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/token.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/token.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,56 @@ + +import struct + +def u16(h): + return struct.pack('':'jg', '<':'jl', '==':'je'} + if i.cond in jmps: + j = jmps[i.cond] + self.emit('{0} {1}'.format(j, i.lab1.name)) + else: + raise NotImplementedError('condition {0}'.format(i.cond)) + self.emit('jmp {0}'.format(i.lab2.name)) + elif type(i) is ir.Branch: + self.emit('jmp {0}'.format(i.target.name)) + elif type(i) is ir.Alloc: + pass + else: + raise NotImplementedError('{0}'.format(i)) + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/target/x86/x86_2.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/target/x86/x86_2.py Sat Mar 01 15:40:31 2014 +0100 @@ -0,0 +1,356 @@ +""" + X86 target descriptions and encodings. + +""" + +from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef + + +modrm = {'rax': 0, 'rbx': 1} + +# Table 3.1 of the intel manual: +# use REX.W on the table below: +regs64 = {'rax': 0,'rcx':1,'rdx':2,'rbx':3,'rsp':4,'rbp':5,'rsi':6,'rdi':7,'r8':0,'r9':1,'r10':2,'r11':3,'r12':4,'r13':5,'r14':6,'r15':7} +regs32 = {'eax': 0, 'ecx':1, 'edx':2, 'ebx': 3, 'esp': 4, 'ebp': 5, 'esi':6, 'edi':7} +regs8 = {'al':0,'cl':1,'dl':2,'bl':3,'ah':4,'ch':5,'dh':6,'bh':7} + +# Calculation of the rexb bit: +rexbit = {'rax': 0, 'rcx':0, 'rdx':0, 'rbx': 0, 'rsp': 0, 'rbp': 0, 'rsi':0, 'rdi':0,'r8':1,'r9':1,'r10':1,'r11':1,'r12':1,'r13':1,'r14':1,'r15':1} + +# Helper functions: +def imm64(x): + """ represent 64 bits integer in little endian 8 bytes""" + if x < 0: + x = x + (1 << 64) + x = x & 0xFFFFFFFFFFFFFFFF + return [ (x >> (p*8)) & 0xFF for p in range(8) ] + +def imm32(x): + """ represent 32 bits integer in little endian 4 bytes""" + if x < 0: + x = x + (1 << 32) + x = x & 0xFFFFFFFF + return [ (x >> (p*8)) & 0xFF for p in range(4) ] + +def imm8(x): + if x < 0: + x = x + (1 << 8) + x = x & 0xFF + return [ x ] + +def modrm(mod=0, rm=0, reg=0): + """ Construct the modrm byte from its components """ + assert(mod <= 3) + assert(rm <= 7) + assert(reg <= 7) + return (mod << 6) | (reg << 3) | rm + +def rex(w=0, r=0, x=0, b=0): + """ Create a REX prefix byte """ + assert(w <= 1) + assert(r <= 1) + assert(x <= 1) + assert(b <= 1) + return 0x40 | (w<<3) | (r<<2) | (x<<1) | b + +def sib(ss=0, index=0, base=0): + assert(ss <= 3) + assert(index <= 7) + assert(base <= 7) + return (ss << 6) | (index << 3) | base + +tttn = {'L':0xc,'G':0xf,'NE':0x5,'GE':0xd,'LE':0xe, 'E':0x4} + +# Actual instructions: +def nearjump(distance, condition=None): + """ jmp imm32 """ + lim = (1<<30) + if abs(distance) > lim: + Error('near jump cannot jump over more than {0} bytes'.format(lim)) + if condition: + if distance < 0: + distance -= 6 # Skip own instruction + opcode = 0x80 | tttn[condition] # Jcc imm32 + return [0x0F, opcode] + imm32(distance) + else: + if distance < 0: + distance -= 5 # Skip own instruction + return [ 0xE9 ] + imm32(distance) + +def shortjump(distance, condition=None): + """ jmp imm8 """ + lim = 118 + if abs(distance) > lim: + Error('short jump cannot jump over more than {0} bytes'.format(lim)) + if distance < 0: + distance -= 2 # Skip own instruction + if condition: + opcode = 0x70 | tttn[condition] # Jcc rel8 + else: + opcode = 0xeb # jmp rel8 + return [opcode] + imm8(distance) + +# Helper that determines jump type: +def reljump(distance): + if abs(distance) < 110: + return shortjump(distance) + else: + return nearjump(distance) + +def push(reg): + if reg in regs64: + if rexbit[reg] == 1: + return [0x41, 0x50 + regs64[reg]] + else: + return [0x50 + regs64[reg]] + else: + Error('push for {0} not implemented'.format(reg)) + +def pop(reg): + if reg in regs64: + if rexbit[reg] == 1: + rexprefix = rex(b=1) + opcode = 0x58 + regs64[reg] + return [rexprefix, opcode] + else: + opcode = 0x58 + regs64[reg] + return [ opcode ] + else: + Error('pop for {0} not implemented'.format(reg)) + +def INT(number): + opcode = 0xcd + return [opcode] + imm8(number) + +def syscall(): + return [0x0F, 0x05] + +def call(distance): + if type(distance) is int: + return [0xe8]+imm32(distance) + elif type(distance) is str and distance in regs64: + reg = distance + opcode = 0xFF # 0xFF /2 == call r/m64 + mod_rm = modrm(mod=3, reg=2, rm=regs64[reg]) + if rexbit[reg] == 1: + rexprefix = rex(b=rexbit[reg]) + return [rexprefix, opcode, mod_rm] + else: + return [opcode, mod_rm] + else: + Error('Cannot call to {0}'.format(distance)) + +def ret(): + return [ 0xc3 ] + +def increg64(reg): + assert(reg in regs64) + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xff + mod_rm = modrm(mod=3, rm=regs64[reg]) + return [rexprefix, opcode, mod_rm] + +def prepost8(r8, rm8): + assert(r8 in regs8) + pre = [] + if type(rm8) is list: + # TODO: merge mem access with prepost for 64 bits + if len(rm8) == 1: + base, = rm8 + if type(base) is str and base in regs64: + assert(not base in ['rbp', 'rsp', 'r12', 'r13']) + mod_rm = modrm(mod=0, rm=regs64[base], reg=regs8[r8]) + if rexbit[base] == 1: + pre.append(rex(b=1)) + post = [mod_rm] + else: + Error('One arg of type {0} not implemented'.format(base)) + elif len(rm8) == 2: + base, offset = rm8 + assert(type(offset) is int) + assert(base in regs64) + + if base == 'rsp' or base == 'r12': + Error('Cannot use rsp or r12 as base yet') + if rexbit[base] == 1: + pre.append( rex(b=1) ) + mod_rm = modrm(mod=1, rm=regs64[base], reg=regs8[r8]) + post = [mod_rm] + imm8(offset) + else: + Error('not supporting prepost8 with list len {0}'.format(len(rm8))) + else: + Error('Not supporting move with reg8 {0}'.format(r8)) + return pre, post + +def prepost(r64, rm64): + assert(r64 in regs64) + if type(rm64) is list: + if len(rm64) == 3: + base, index, disp = rm64 + assert(base in regs64) + assert(index in regs64) + assert(type(disp) is int) + # Assert that no special cases are used: + # TODO: swap base and index to avoid special cases + # TODO: exploit special cases and make better code + assert(index != 'rsp') + + rexprefix = rex(w=1, r=rexbit[r64], x=rexbit[index], b=rexbit[base]) + # mod=1 and rm=4 indicates a SIB byte: [--][--]+imm8 + mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) + si_b = sib(ss=0, index=regs64[index], base=regs64[base]) + return [rexprefix], [mod_rm, si_b] + imm8(disp) + elif len(rm64) == 2: + base, offset = rm64 + assert(type(offset) is int) + if base == 'RIP': + # RIP pointer relative addressing mode! + rexprefix = rex(w=1, r=rexbit[r64]) + mod_rm = modrm(mod=0, rm=5, reg=regs64[r64]) + return [rexprefix], [mod_rm] + imm32(offset) + else: + assert(base in regs64) + + if base == 'rsp' or base == 'r12': + # extended function that uses SIB byte + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) + # rm=4 indicates a SIB byte follows + mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) + # index=4 indicates that index is not used + si_b = sib(ss=0, index=4, base=regs64[base]) + return [rexprefix], [mod_rm, si_b] + imm8(offset) + else: + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) + mod_rm = modrm(mod=1, rm=regs64[base], reg=regs64[r64]) + return [rexprefix], [mod_rm] + imm8(offset) + elif len(rm64) == 1: + offset = rm64[0] + if type(offset) is int: + rexprefix = rex(w=1, r=rexbit[r64]) + mod_rm = modrm(mod=0, rm=4,reg=regs64[r64]) + si_b = sib(ss=0, index=4,base=5) # 0x25 + return [rexprefix], [mod_rm, si_b] + imm32(offset) + else: + Error('Memory reference of type {0} not implemented'.format(offset)) + else: + Error('Memory reference not implemented') + elif rm64 in regs64: + rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[rm64]) + mod_rm = modrm(3, rm=regs64[rm64], reg=regs64[r64]) + return [rexprefix], [mod_rm] + +def leareg64(rega, m): + opcode = 0x8d # lea r64, m + pre, post = prepost(rega, m) + return pre + [opcode] + post + +def mov(rega, regb): + if type(regb) is int: + pre = [rex(w=1, b=rexbit[rega])] + opcode = 0xb8 + regs64[rega] + post = imm64(regb) + elif type(regb) is str: + if regb in regs64: + opcode = 0x89 # mov r/m64, r64 + pre, post = prepost(regb, rega) + elif regb in regs8: + opcode = 0x88 # mov r/m8, r8 + pre, post = prepost8(regb, rega) + else: + Error('Unknown register {0}'.format(regb)) + elif type(rega) is str: + if rega in regs64: + opcode = 0x8b # mov r64, r/m64 + pre, post = prepost(rega, regb) + else: + Error('Unknown register {0}'.format(rega)) + else: + Error('Move of this kind {0}, {1} not implemented'.format(rega, regb)) + return pre + [opcode] + post + +def xorreg64(rega, regb): + rexprefix = rex(w=1, r=rexbit[regb], b=rexbit[rega]) + opcode = 0x31 # XOR r/m64, r64 + # Alternative is 0x33 XOR r64, r/m64 + mod_rm = modrm(3, rm=regs64[rega], reg=regs64[regb]) + return [rexprefix, opcode, mod_rm] + +# integer arithmatic: +def addreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x01 # ADD r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + if regb < 100: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # add r/m, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=0) + return [rexprefix, opcode, mod_rm]+imm8(regb) + elif regb < (1<<31): + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x81 # add r/m64, imm32 + mod_rm = modrm(3, rm=regs64[rega], reg=0) + return [rexprefix, opcode, mod_rm]+imm32(regb) + else: + Error('Constant value too large!') + else: + Error('unknown second operand!'.format(regb)) + +def subreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x29 # SUB r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + if regb < 100: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # sub r/m, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=5) + return [rexprefix, opcode, mod_rm]+imm8(regb) + elif regb < (1<<31): + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x81 # sub r/m64, imm32 + mod_rm = modrm(3, rm=regs64[rega], reg=5) + return [rexprefix, opcode, mod_rm]+imm32(regb) + else: + Error('Constant value too large!') + + else: + Error('unknown second operand!'.format(regb)) + +def idivreg64(reg): + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xf7 # IDIV r/m64 + mod_rm = modrm(3, rm=regs64[reg], reg=7) + return [rexprefix, opcode, mod_rm] + +def imulreg64_rax(reg): + rexprefix = rex(w=1, b=rexbit[reg]) + opcode = 0xf7 # IMUL r/m64 + mod_rm = modrm(3, rm=regs64[reg], reg=5) + return [rexprefix, opcode, mod_rm] + +def imulreg64(rega, regb): + pre, post = prepost(rega, regb) + opcode = 0x0f # IMUL r64, r/m64 + opcode2 = 0xaf + return pre + [opcode, opcode2] + post + +def cmpreg64(rega, regb): + if regb in regs64: + pre, post = prepost(regb, rega) + opcode = 0x39 # CMP r/m64, r64 + return pre + [opcode] + post + elif type(regb) is int: + rexprefix = rex(w=1, b=rexbit[rega]) + opcode = 0x83 # CMP r/m64, imm8 + mod_rm = modrm(3, rm=regs64[rega], reg=7) + return [rexprefix, opcode, mod_rm] + imm8(regb) + + else: + Error('not implemented cmp64') + +# Mapping that maps string names to the right functions: +opcodes = {'mov':(mov,2), 'lea':(leareg64,2), 'int':(INT,1), 'syscall':(syscall,0)} + diff -r 4d204f6f7d4e -r 86b02c98a717 python/ppci/tasks.py --- a/python/ppci/tasks.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/ppci/tasks.py Sat Mar 01 15:40:31 2014 +0100 @@ -1,3 +1,7 @@ +""" + This module defines tasks and a runner for these tasks. Tasks can + have dependencies and it can be determined if they need to be run. +""" import logging @@ -9,31 +13,49 @@ """ Task that can run, and depend on other tasks """ def __init__(self, name): self.name = name - self.subtasks = [] self.completed = False - self.dependencies = [] + self.dependencies = set() self.duration = 1 def run(self): raise NotImplementedError("Implement this abstract method!") def fire(self): + """ Wrapper around run that marks the task as done """ assert all(t.completed for t in self.dependencies) self.run() self.completed = True - def addSubTask(self, tsk): - self.subtasks.append(tsk) - return tsk + def add_dependency(self, task): + """ Add another task as a dependency for this task """ + if task is self: + raise TaskError('Can not add dependency on task itself!') + if self in task.down_stream_tasks: + raise TaskError('Can not introduce circular task') + self.dependencies.add(task) + return task - def addDependency(self, task): - self.dependencies.append(task) - return task + @property + def down_stream_tasks(self): + """ Return a set of all tasks that follow this task """ + # TODO: is this upstream or downstream??? + cdst = list(dep.down_stream_tasks for dep in self.dependencies) + cdst.append(self.dependencies) + return set.union(*cdst) + + def __gt__(self, other): + return other in self.down_stream_tasks def __repr__(self): return 'Task "{}"'.format(self.name) +class EmptyTask(Task): + """ Basic task that does nothing """ + def run(self): + pass + + class TaskRunner: """ Basic task runner that can run some tasks in sequence """ def __init__(self): @@ -48,6 +70,10 @@ return sum(t.duration for t in self.task_list) def run_tasks(self): + # First sort tasks: + self.task_list.sort() + + # Run tasks: passed_time = 0.0 total_time = self.total_duration try: @@ -56,7 +82,7 @@ t.fire() passed_time += t.duration except TaskError as e: - print('Error: {}'.format(e)) + self.logger.error(str(e.msg)) return 1 self.report_progress(1, 'OK') return 0 diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/__init__.py --- a/python/target/__init__.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment -from .basetarget import Imm32, DebugInfo - - -class SimpleTarget(Target): - def __init__(self): - super().__init__('SimpleTarget') diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/arm.brg --- a/python/target/arm.brg Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ - -from target.basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop -from target.arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3 -from target.arminstructions import B, Bl, Bgt, Blt, Beq, Bne -from target.arminstructions import Mov2, Mov3 -from target.arminstructions import Add3, Sub, Cmp, Sub2, Add2, Mul -from ppci import ir - -%% - -%terminal ADDI32 SUBI32 MULI32 -%terminal ORI32 SHLI32 -%terminal CONSTI32 MEMI32 REGI32 CALL -%terminal MOVI32 - -%% - - -reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add3, dst=[d], src=[$1, $2]); return d .) -reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub, dst=[d], src=[$1, $2]); return d .) -reg: ORI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Orr, dst=[], src=[d, $2]); return d .) -reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Lsl, dst=[], src=[d, $2]); return d .) -reg: MULI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Mul, dst=[d], src=[$2, d]); return d .) - -reg: CONSTI32 3 (. d = self.newTmp(); ln = LabelRef(self.selector.frame.addConstant($$.value)); self.emit(Ldr3, dst=[d], others=[ln]); return d .) -reg: MEMI32(reg) 4 (. d = self.newTmp(); self.emit(Ldr2, dst=[d], src=[$1], others=[0]); return d .) -reg: REGI32 1 (. return $$.value .) -reg: CALL 1 (. return self.selector.munchCall($$.value) .) - - -stmt: MOVI32(MEMI32(addr), reg) 3 (. self.emit(Str2, src=[$1, $2]) .) - -addr: reg 2 (. .) diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/armframe.py --- a/python/target/armframe.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -from ppci import ir -from .basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop -from .basetarget import Imm7 -from ppci.irmach import makeIns, Frame -from .arminstructions import Dcd, AddSp, SubSp, Push, Pop, Mov2 -from .armregisters import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP - - -class ArmFrame(Frame): - """ Arm specific frame for functions. """ - def __init__(self, name): - # We use r7 as frame pointer. - super().__init__(name) - self.regs = [R0, R1, R2, R3, R4, R5, R6] - self.rv = ir.Temp('special_RV') - self.p1 = ir.Temp('special_P1') - self.p2 = ir.Temp('special_P2') - self.p3 = ir.Temp('special_P3') - self.p4 = ir.Temp('special_P4') - self.fp = ir.Temp('special_FP') - # Pre-colored registers: - self.tempMap = {} - self.tempMap[self.rv] = R0 - self.tempMap[self.p1] = R1 - self.tempMap[self.p2] = R2 - self.tempMap[self.p3] = R3 - self.tempMap[self.p4] = R4 - self.tempMap[self.fp] = R7 - self.locVars = {} - self.parMap = {} - # Literal pool: - self.constants = [] - - def argLoc(self, pos): - """ - Gets the function parameter location in IR-code format. - """ - if pos == 0: - return self.p1 - elif pos == 1: - return self.p2 - elif pos == 2: - return self.p3 - elif pos == 3: - return self.p4 - else: - raise NotImplementedError('No more than 4 parameters implemented') - - def allocVar(self, lvar): - if lvar not in self.locVars: - self.locVars[lvar] = self.stacksize - self.stacksize = self.stacksize + 4 - return self.locVars[lvar] - - def addConstant(self, value): - lab_name = '{}_literal_{}'.format(self.name, len(self.constants)) - self.constants.append((lab_name, value)) - return lab_name - - def prologue(self): - """ Returns prologue instruction sequence """ - pre = [ - Label(self.name), # Label indication function - Push({LR, R7}) - ] - if self.stacksize > 0: - pre.append(SubSp(self.stacksize)) # Reserve stack space - pre += [ - Mov2(R7, SP) # Setup frame pointer - ] - return pre - - def epilogue(self): - """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """ - post = [] - if self.stacksize > 0: - post.append(AddSp(self.stacksize)) - post += [ - Pop({PC, R7}), - Alignment(4) # Align at 4 bytes - ] - # Add constant literals: - for ln, v in self.constants: - post.extend([Label(ln), Dcd(v)]) - return post - - def EntryExitGlue3(self): - """ - Add code for the prologue and the epilogue. Add a label, the - return instruction and the stack pointer adjustment for the frame. - """ - for index, ins in enumerate(self.prologue()): - self.instructions.insert(index, makeIns(ins)) - - # Postfix code: - for ins in self.epilogue(): - self.instructions.append(makeIns(ins)) diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/arminstructions.py --- a/python/target/arminstructions.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,576 +0,0 @@ -import struct -from ppci.asmnodes import ASymbol, AInstruction, ANumber, AUnop, ABinop -from .basetarget import Register, Instruction, Target, Label, LabelRef -from .basetarget import Imm32, Imm8, Imm7, Imm3 - -from .armtoken import ThumbToken, ArmToken -from .armregisters import R0, ArmRegister, SP - - - -def u16(h): - return struct.pack('> 2 - self.rn = rn - self.rt = rt - assert self.rn.num < 8 - assert self.rt.num < 8 - self.token = ThumbToken() - - def encode(self): - Rn = self.rn.num - Rt = self.rt.num - imm5 = self.imm5 - self.token[0:3] = Rt - self.token[3:6] = Rn - self.token[6:11] = imm5 - self.token[11:16] = self.opcode - return self.token.encode() - - def __repr__(self): - mnemonic = "???" - return '{} {}, [{}, {}]'.format(mnemonic, self.rt, self.rn, self.imm5) - - -class Str2(LS_imm5_base): - opcode = 0xC - - @classmethod - def fromim(cls, im): - return cls(im.src[1], im.src[0], im.others[0]) - - -class Ldr2(LS_imm5_base): - opcode = 0xD - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.others[0]) - -class ls_sp_base_imm8(ThumbInstruction): - def __init__(self, rt, offset): - self.rt = rt - self.offset = offset - - def encode(self): - rt = self.rt.num - assert rt < 8 - imm8 = self.offset >> 2 - assert imm8 < 256 - h = (self.opcode << 8) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - mnemonic = self.__class__.__name__ - return '{} {}, [sp,#{}]'.format(mnemonic, self.rt, self.offset) - -def align(x, m): - while ((x % m) != 0): - x = x + 1 - return x - -def Ldr(*args): - if len(args) == 2 and isinstance(args[0], ArmRegister) \ - and isinstance(args[1], str): - return Ldr3(*args) - else: - raise Exception() - - -class Ldr3(ThumbInstruction): - """ ldr Rt, LABEL, load value from pc relative position """ - mnemonic = 'ldr' - def __init__(self, rt, label): - self.rt = rt - self.label = label - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def relocations(self): - return [(self.label, 'lit_add_8')] - - def encode(self): - rt = self.rt.num - assert rt < 8 - imm8 = 0 - h = (0x9 << 11) | (rt << 8) | imm8 - return u16(h) - - def __repr__(self): - return 'LDR {}, {}'.format(self.rt, self.label) - - -class Ldr1(ls_sp_base_imm8): - """ ldr Rt, [SP, imm8] """ - opcode = 0x98 - - -class Str1(ls_sp_base_imm8): - """ str Rt, [SP, imm8] """ - opcode = 0x90 - - -class Mov3(ThumbInstruction): - """ mov Rd, imm8, move immediate value into register """ - opcode = 4 # 00100 Rd(3) imm8 - def __init__(self, rd, imm): - assert imm < 256 - self.imm = imm - self.rd = rd - self.token = ThumbToken() - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.others[0]) - - def encode(self): - rd = self.rd.num - self.token[8:11] = rd - self.token[0:8] = self.imm - self.token[11:16] = self.opcode - return self.token.encode() - - def __repr__(self): - return 'MOV {}, {}'.format(self.rd, self.imm) - - - -# Arithmatics: - - - -class regregimm3_base(ThumbInstruction): - def __init__(self, rd, rn, imm3): - self.rd = rd - self.rn = rn - assert imm3 < 8 - self.imm3 = imm3 - self.token = ThumbToken() - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.others[0]) - - def encode(self): - rd = self.rd.num - self.token[0:3] = rd - self.token[3:6] = self.rn.num - self.token[6:9] = self.imm3 - self.token[9:16] = self.opcode - return self.token.encode() - - def __repr__(self): - mnemonic = self.__class__.__name__ - return '{} {}, {}, {}'.format(mnemonic, self.rd, self.rn, self.imm3) - - - -class Add2(regregimm3_base): - """ add Rd, Rn, imm3 """ - opcode = 0b0001110 - - -class Sub2(regregimm3_base): - """ sub Rd, Rn, imm3 """ - opcode = 0b0001111 - - -def Sub(*args): - if len(args) == 3 and args[0] is SP and args[1] is SP and \ - isinstance(args[2], int) and args[2] < 256: - return SubSp(args[2]) - elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ - isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ - args[2] < 8: - return Sub2(args[0], args[1], args[2]) - else: - raise Exception() - -class regregreg_base(ThumbInstruction): - """ ??? Rd, Rn, Rm """ - def __init__(self, rd, rn, rm): - self.rd = rd - self.rn = rn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0], im.src[1]) - - def encode(self): - at = ThumbToken() - at.rd = self.rd.num - rn = self.rn.num - rm = self.rm.num - at[3:6] = rn - at[6:9] = rm - at[9:16] = self.opcode - return at.encode() - - def __repr__(self): - return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) - - -class Add3(regregreg_base): - mnemonic = 'ADD' - opcode = 0b0001100 - - -class Sub3(regregreg_base): - mnemonic = 'SUB' - opcode = 0b0001101 - - -class Mov2(ThumbInstruction): - """ mov rd, rm """ - mnemonic = 'MOV' - def __init__(self, rd, rm): - self.rd = rd - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.dst[0], im.src[0]) - - def encode(self): - at = ThumbToken() - at.rd = self.rd.num & 0x7 - D = (self.rd.num >> 3) & 0x1 - Rm = self.rm.num - opcode = 0b01000110 - at[8:16] = opcode - at[3:7] = Rm - at[7] = D - return at.encode() - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) - - -class Mul(ThumbInstruction): - """ mul Rn, Rdm """ - mnemonic = 'MUL' - def __init__(self, rn, rdm): - self.rn = rn - self.rdm = rdm - - @classmethod - def fromim(cls, im): - assert im.src[1] is im.dst[0] - return cls(im.src[0], im.dst[0]) - - def encode(self): - at = ThumbToken() - rn = self.rn.num - at.rd = self.rdm.num - opcode = 0b0100001101 - #h = (opcode << 6) | (rn << 3) | rdm - at[6:16] = opcode - at[3:6] = rn - return at.encode() - - def __repr__(self): - return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) - - -class regreg_base(ThumbInstruction): - """ ??? Rdn, Rm """ - def __init__(self, rdn, rm): - self.rdn = rdn - self.rm = rm - - @classmethod - def fromim(cls, im): - return cls(im.src[0], im.src[1]) - - def encode(self): - at = ThumbToken() - at.rd = self.rdn.num - rm = self.rm.num - at[3:6] = rm - at[6:16] = self.opcode - return at.encode() - - def __repr__(self): - mnemonic = self.__class__.__name__ - return '{} {}, {}'.format(mnemonic, self.rdn, self.rm) - - -class movregreg_ins(regreg_base): - """ mov Rd, Rm (reg8 operands) """ - opcode = 0 - - -class And(regreg_base): - opcode = 0b0100000000 - - -class Orr(regreg_base): - opcode = 0b0100001100 - - -class Cmp(regreg_base): - opcode = 0b0100001010 - - -class Lsl(regreg_base): - opcode = 0b0100000010 - - -class cmpregimm8_ins(ThumbInstruction): - """ cmp Rn, imm8 """ - opcode = 5 # 00101 - def __init__(self, rn, imm): - self.rn = rn - self.imm = imm - - def encode(self): - at = ThumbToken() - at[0:8] = self.imm.imm - at[8:11] = self.rn.num - at[11:16] = self.opcode - return at.encode() - - -# Jumping: - -class jumpBase_ins(ThumbInstruction): - def __init__(self, target_label): - self.target = target_label - self.offset = 0 - - def __repr__(self): - mnemonic = self.__class__.__name__ - return '{} {}'.format(mnemonic, self.target) - - -class B(jumpBase_ins): - def encode(self): - h = (0b11100 << 11) | 0 - # | 1 # 1 to enable thumb mode - return u16(h) - - def relocations(self): - return [(self.target, 'wrap_new11')] - -class Bl(jumpBase_ins): - def encode(self): - imm11 = 0 - imm10 = 0 - j1 = 1 # TODO: what do these mean? - j2 = 1 - s = 0 - h1 = (0b11110 << 11) | (s << 10) | imm10 - h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 - return u16(h1) + u16(h2) - - def relocations(self): - return [(self.target, 'bl_imm11_imm10')] - - -class cond_base_ins(jumpBase_ins): - def encode(self): - imm8 = 0 - h = (0b1101 << 12) | (self.cond << 8) | imm8 - return u16(h) - - def relocations(self): - return [(self.target, 'rel8')] - - -class cond_base_ins_long(jumpBase_ins): - """ Encoding T3 """ - def encode(self): - j1 = 1 # TODO: what do these mean? - j2 = 1 - h1 = (0b11110 << 11) | (self.cond << 6) - h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) - return u16(h1) + u16(h2) - - def relocations(self): - return [(self.target, 'b_imm11_imm6')] - - -class Beq(cond_base_ins): - cond = 0 - - -class Bne(cond_base_ins): - cond = 1 - - -class Blt(cond_base_ins): - cond = 0b1011 - - -class Bgt(cond_base_ins): - cond = 0b1100 - - -class Push(ThumbInstruction): - def __init__(self, regs): - assert type(regs) is set - self.regs = regs - - def __repr__(self): - return 'Push {{{}}}'.format(self.regs) - - def encode(self): - at = ThumbToken() - for n in register_numbers(self.regs): - if n < 8: - at[n] = 1 - elif n == 14: - at[8] = 1 - else: - raise NotImplementedError('not implemented for {}'.format(n)) - at[9:16] = 0x5a - return at.encode() - - - -def register_numbers(regs): - for r in regs: - yield r.num - -class Pop(ThumbInstruction): - def __init__(self, regs): - assert type(regs) is set - self.regs = regs - self.token = ThumbToken() - - def __repr__(self): - return 'Pop {{{}}}'.format(self.regs) - - def encode(self): - for n in register_numbers(self.regs): - if n < 8: - self.token[n] = 1 - elif n == 15: - self.token[8] = 1 - else: - raise NotImplementedError('not implemented for this register') - self.token[9:16] = 0x5E - return self.token.encode() - - - -class Yield(ThumbInstruction): - def encode(self): - return u16(0xbf10) - -# misc: - -# add/sub SP: -class addspsp_base(ThumbInstruction): - def __init__(self, imm7): - self.imm7 = imm7 - assert self.imm7 % 4 == 0 - self.imm7 >>= 2 - - def encode(self): - return u16((self.opcode << 7) | self.imm7) - - def __repr__(self): - mnemonic = self.__class__.__name__ - return '{} sp, sp, {}'.format(mnemonic, self.imm7 << 2) - - -class AddSp(addspsp_base): - opcode = 0b101100000 - - -class SubSp(addspsp_base): - opcode = 0b101100001 diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/arminstructionselector.py --- a/python/target/arminstructionselector.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -import os -from ppci import ir, same_dir -from ppci.irmach import AbstractInstruction as makeIns -from ppci.ir2tree import makeTree -import pyburg -from .basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop -from .instructionselector import InstructionSelector -from .arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3 -from .arminstructions import B, Bl, Bgt, Blt, Beq, Bne -from .arminstructions import Mov2, Mov3 -from .arminstructions import Cmp, Sub2, Mul -from .basetarget import Imm8, Imm7, Imm3 - -# Import BURG spec for arm: -spec_file = same_dir(__file__, 'arm.brg') -arm_matcher = pyburg.load_as_module(spec_file) - - -class ArmMatcher(arm_matcher.Matcher): - """ Matcher that derives from a burg spec generated matcher """ - def __init__(self, selector): - super().__init__() - self.newTmp = selector.newTmp - self.emit = selector.emit - self.selector = selector - - -class ArmInstructionSelector(InstructionSelector): - """ Instruction selector for the arm architecture """ - def __init__(self): - super().__init__() - self.matcher = ArmMatcher(self) - - def munchExpr(self, e): - # Use BURG system here: - t = makeTree(e) - return self.matcher.gen(t) - - def munchCall(self, e): - """ Generate code for call sequence """ - # Move arguments into proper locations: - reguses = [] - for i, a in enumerate(e.arguments): - loc = self.frame.argLoc(i) - m = ir.Move(loc, a) - self.munchStm(m) - if isinstance(loc, ir.Temp): - reguses.append(loc) - self.emit(Bl(LabelRef(e.f)), src=reguses, dst=[self.frame.rv]) - d = self.newTmp() - self.move(d, self.frame.rv) - return d - - def munchStm(self, s): - if isinstance(s, ir.Terminator): - pass - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \ - isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \ - isinstance(s.dst.e.b, ir.Const): - a = self.munchExpr(s.dst.e.a) - val = self.munchExpr(s.src) - c = s.dst.e.b.value - self.emit(Str2, others=[c], src=[a, val]) - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): - memloc = self.munchExpr(s.dst.e) - val = self.munchExpr(s.src) - self.emit(Str2, others=[0], src=[memloc, val]) - elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): - val = self.munchExpr(s.src) - dreg = s.dst - self.move(dreg, val) - elif isinstance(s, ir.Exp): - # Generate expression code and discard the result. - x = self.munchExpr(s.e) - self.emit(Nop(), src=[x]) - elif isinstance(s, ir.Jump): - tgt = self.targets[s.target] - self.emit(B(LabelRef(ir.label_name(s.target))), jumps=[tgt]) - elif isinstance(s, ir.CJump): - a = self.munchExpr(s.a) - b = self.munchExpr(s.b) - self.emit(Cmp, src=[a, b]) - ntgt = self.targets[s.lab_no] - ytgt = self.targets[s.lab_yes] - jmp_ins = makeIns(B(LabelRef(ir.label_name(s.lab_no))), jumps=[ntgt]) - opnames = {'<': Blt, '>':Bgt, '==':Beq, '!=':Bne} - op = opnames[s.cond](LabelRef(ir.label_name(s.lab_yes))) - self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough - self.emit2(jmp_ins) - else: - raise NotImplementedError('Stmt --> {}'.format(s)) - - def move(self, dst, src): - self.emit(Mov2, src=[src], dst=[dst], ismove=True) diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/armregisters.py --- a/python/target/armregisters.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ - -from .basetarget import Register - -class ArmRegister(Register): - def __init__(self, num, name): - super().__init__(name) - self.num = num - - def __repr__(self): - return self.name - - -class Reg8Op(ArmRegister): - pass - - -class Reg16Op(ArmRegister): - pass - -def get_register(n): - for x in registers: - if x.num == n: - return x - raise Exception() - -def register_range(a, b): - """ Return set of registers from a to b """ - assert a.num < b.num - return {get_register(n) for n in range(a.num, b.num + 1)} - - -R0 = Reg8Op(0, 'r0') -R1 = Reg8Op(1, 'r1') -R2 = Reg8Op(2, 'r2') -R3 = Reg8Op(3, 'r3') -R4 = Reg8Op(4, 'r4') -R5 = Reg8Op(5, 'r5') -R6 = Reg8Op(6, 'r6') -R7 = Reg8Op(7, 'r7') -R8 = Reg8Op(8, 'r8') -R9 = Reg8Op(9, 'r9') -R10 = Reg8Op(10, 'r10') -R11 = Reg8Op(11, 'r11') -R12 = Reg8Op(12, 'r12') - -# Other registers: -# TODO -SP = ArmRegister(13, 'sp') -LR = ArmRegister(14, 'lr') -PC = ArmRegister(15, 'pc') - -registers = [R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC] diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/armtarget.py --- a/python/target/armtarget.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -import struct -from .basetarget import Register, Instruction, Target, Label, Alignment -from .basetarget import Imm32, Imm8, Imm7, Imm3 -from .arminstructions import Add2, Sub, Add3, Cmp, Lsl, Orr -from .arminstructions import Dcd, Pop, Push, Yield, Mov2, Mov3 -from .arminstructions import B, Bl, Bne, Beq, Blt, Bgt -from .arminstructions import Ldr, Str2, Ldr2, Str1, Ldr1 - -from .armframe import ArmFrame -from .arminstructionselector import ArmInstructionSelector -from .armregisters import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC -from .armregisters import register_range - - -""" ARM target description. """ - -# TODO: encode this in DSL (domain specific language) -# TBD: is this required? -# TODO: make a difference between armv7 and armv5? - -thumb_assembly_rules = [] -def add_rule(rhs, f): - thumb_assembly_rules.append(('instruction', rhs, f)) - - -class ThumbTarget(Target): - def __init__(self): - super().__init__('thumb') - self.ins_sel = ArmInstructionSelector() - self.FrameClass = ArmFrame - self.add_rules() - - def add_rules(self): - - # Add instructions: - self.add_keyword('dcd') - self.add_instruction(['dcd', 'imm32'], lambda rhs: Dcd(rhs[1])) - - self.add_keyword('mov') - self.add_instruction(['mov', 'reg8', ',', 'reg8'], - lambda rhs: Mov2(rhs[1], rhs[3])) - - self.add_instruction(['mov', 'reg8', ',', 'imm8'], - lambda rhs: Mov3(rhs[1], rhs[3])) - - self.add_keyword('add') - self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'imm3'], - lambda rhs: Add2(rhs[1], rhs[3], rhs[5])) - - self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'reg8'], - lambda rhs: Add3(rhs[1], rhs[3], rhs[5])) - - self.add_keyword('sub') - self.add_instruction(['sub', 'reg8', ',', 'reg8', ',', 'imm3'], - lambda rhs: Sub(rhs[1], rhs[3], rhs[5])) - - self.add_instruction(['sub', 'sp', ',', 'sp', ',', 'imm8'], - lambda rhs: Sub(SP, SP, rhs[5])) - - self.add_instruction(['add', 'sp', ',', 'sp', ',', 'imm8'], - lambda rhs: Sub(SP, SP, rhs[5])) - - self.add_keyword('cmp') - self.add_instruction(['cmp', 'reg8', ',', 'reg8'], - lambda rhs: Cmp(rhs[1], rhs[3])) - - self.add_keyword('lsl') - self.add_instruction(['lsl', 'reg8', ',', 'reg8'], - lambda rhs: Lsl(rhs[1], rhs[3])) - - self.add_keyword('str') - self.add_instruction(['str', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], - lambda rhs: Str2(rhs[1], rhs[4], rhs[6])) - - self.add_keyword('ldr') - self.add_instruction(['ldr', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'], - lambda rhs: Ldr2(rhs[1], rhs[4], rhs[6])) - - self.add_instruction(['str', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], - lambda rhs: Str1(rhs[1], rhs[6])) - - self.add_instruction(['ldr', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'], - lambda rhs: Ldr1(rhs[1], rhs[6])) - - self.add_keyword('pop') - self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1])) - self.add_keyword('push') - self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1])) - - self.add_keyword('yield') - self.add_instruction(['yield'], lambda rhs: Yield()) - - self.add_keyword('b') - self.add_keyword('bl') - self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val)) - self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val)) - self.add_keyword('beq') - self.add_keyword('bne') - self.add_keyword('blt') - self.add_keyword('bgt') - self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val)) - self.add_instruction(['bne', 'ID'], lambda rhs: Bne(rhs[1].val)) - self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val)) - self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val)) - - self.add_keyword('align') - self.add_instruction(['align', 'imm8'], lambda rhs: Alignment(rhs[1])) - - self.add_instruction(['ldr', 'reg8', ',', 'ID'], - lambda rhs: Ldr(rhs[1], rhs[3].val)) - - # Additional rules: - - # Register list grammar: - self.add_rule('reg_list', ['{', 'reg_list_inner', '}'], - lambda rhs: rhs[1]) - self.add_rule('reg_list_inner', ['reg_or_range'], - lambda rhs: rhs[0]) - self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'], - lambda rhs: rhs[0] | rhs[2]) - self.add_rule('reg_or_range', ['reg8'], lambda rhs: {rhs[0]}) - self.add_rule('reg_or_range', ['lr'], lambda rhs: {LR}) - self.add_rule('reg_or_range', ['pc'], lambda rhs: {PC}) - - self.add_rule('reg_or_range', ['reg8', '-', 'reg8'], - lambda rhs: register_range(rhs[0], rhs[2])) - - self.add_keyword('r0') - self.add_keyword('r1') - self.add_keyword('r2') - self.add_keyword('r3') - self.add_keyword('r4') - self.add_keyword('r5') - self.add_keyword('r6') - self.add_keyword('r7') - self.add_keyword('sp') - self.add_keyword('lr') - self.add_keyword('pc') - self.add_rule('reg8', ['r0'], lambda rhs: R0) - self.add_rule('reg8', ['r1'], lambda rhs: R1) - self.add_rule('reg8', ['r2'], lambda rhs: R2) - self.add_rule('reg8', ['r3'], lambda rhs: R3) - self.add_rule('reg8', ['r4'], lambda rhs: R4) - 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) - - - -class ArmArmTarget(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') - self.add_keyword('r3') - self.add_keyword('r4') - self.add_keyword('r5') - - self.add_rule('reg', ['r0'], lambda rhs: R0) - self.add_rule('reg', ['r1'], lambda rhs: R1) - self.add_rule('reg', ['r2'], lambda rhs: R2) - self.add_rule('reg', ['r3'], lambda rhs: R3) - self.add_rule('reg', ['r4'], lambda rhs: R4) - self.add_rule('reg', ['r5'], lambda rhs: R5) - - - self.add_instruction(['mov', 'reg', ',', 'imm8'], - lambda rhs: Yield()) - - 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) diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/armtoken.py --- a/python/target/armtoken.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ - -import struct - -def u16(h): - return struct.pack('':'jg', '<':'jl', '==':'je'} - if i.cond in jmps: - j = jmps[i.cond] - self.emit('{0} {1}'.format(j, i.lab1.name)) - else: - raise NotImplementedError('condition {0}'.format(i.cond)) - self.emit('jmp {0}'.format(i.lab2.name)) - elif type(i) is ir.Branch: - self.emit('jmp {0}'.format(i.target.name)) - elif type(i) is ir.Alloc: - pass - else: - raise NotImplementedError('{0}'.format(i)) - diff -r 4d204f6f7d4e -r 86b02c98a717 python/target/x86_2.py --- a/python/target/x86_2.py Fri Feb 28 18:07:14 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -""" - X86 target descriptions and encodings. - -""" - -from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef - - -modrm = {'rax': 0, 'rbx': 1} - -# Table 3.1 of the intel manual: -# use REX.W on the table below: -regs64 = {'rax': 0,'rcx':1,'rdx':2,'rbx':3,'rsp':4,'rbp':5,'rsi':6,'rdi':7,'r8':0,'r9':1,'r10':2,'r11':3,'r12':4,'r13':5,'r14':6,'r15':7} -regs32 = {'eax': 0, 'ecx':1, 'edx':2, 'ebx': 3, 'esp': 4, 'ebp': 5, 'esi':6, 'edi':7} -regs8 = {'al':0,'cl':1,'dl':2,'bl':3,'ah':4,'ch':5,'dh':6,'bh':7} - -# Calculation of the rexb bit: -rexbit = {'rax': 0, 'rcx':0, 'rdx':0, 'rbx': 0, 'rsp': 0, 'rbp': 0, 'rsi':0, 'rdi':0,'r8':1,'r9':1,'r10':1,'r11':1,'r12':1,'r13':1,'r14':1,'r15':1} - -# Helper functions: -def imm64(x): - """ represent 64 bits integer in little endian 8 bytes""" - if x < 0: - x = x + (1 << 64) - x = x & 0xFFFFFFFFFFFFFFFF - return [ (x >> (p*8)) & 0xFF for p in range(8) ] - -def imm32(x): - """ represent 32 bits integer in little endian 4 bytes""" - if x < 0: - x = x + (1 << 32) - x = x & 0xFFFFFFFF - return [ (x >> (p*8)) & 0xFF for p in range(4) ] - -def imm8(x): - if x < 0: - x = x + (1 << 8) - x = x & 0xFF - return [ x ] - -def modrm(mod=0, rm=0, reg=0): - """ Construct the modrm byte from its components """ - assert(mod <= 3) - assert(rm <= 7) - assert(reg <= 7) - return (mod << 6) | (reg << 3) | rm - -def rex(w=0, r=0, x=0, b=0): - """ Create a REX prefix byte """ - assert(w <= 1) - assert(r <= 1) - assert(x <= 1) - assert(b <= 1) - return 0x40 | (w<<3) | (r<<2) | (x<<1) | b - -def sib(ss=0, index=0, base=0): - assert(ss <= 3) - assert(index <= 7) - assert(base <= 7) - return (ss << 6) | (index << 3) | base - -tttn = {'L':0xc,'G':0xf,'NE':0x5,'GE':0xd,'LE':0xe, 'E':0x4} - -# Actual instructions: -def nearjump(distance, condition=None): - """ jmp imm32 """ - lim = (1<<30) - if abs(distance) > lim: - Error('near jump cannot jump over more than {0} bytes'.format(lim)) - if condition: - if distance < 0: - distance -= 6 # Skip own instruction - opcode = 0x80 | tttn[condition] # Jcc imm32 - return [0x0F, opcode] + imm32(distance) - else: - if distance < 0: - distance -= 5 # Skip own instruction - return [ 0xE9 ] + imm32(distance) - -def shortjump(distance, condition=None): - """ jmp imm8 """ - lim = 118 - if abs(distance) > lim: - Error('short jump cannot jump over more than {0} bytes'.format(lim)) - if distance < 0: - distance -= 2 # Skip own instruction - if condition: - opcode = 0x70 | tttn[condition] # Jcc rel8 - else: - opcode = 0xeb # jmp rel8 - return [opcode] + imm8(distance) - -# Helper that determines jump type: -def reljump(distance): - if abs(distance) < 110: - return shortjump(distance) - else: - return nearjump(distance) - -def push(reg): - if reg in regs64: - if rexbit[reg] == 1: - return [0x41, 0x50 + regs64[reg]] - else: - return [0x50 + regs64[reg]] - else: - Error('push for {0} not implemented'.format(reg)) - -def pop(reg): - if reg in regs64: - if rexbit[reg] == 1: - rexprefix = rex(b=1) - opcode = 0x58 + regs64[reg] - return [rexprefix, opcode] - else: - opcode = 0x58 + regs64[reg] - return [ opcode ] - else: - Error('pop for {0} not implemented'.format(reg)) - -def INT(number): - opcode = 0xcd - return [opcode] + imm8(number) - -def syscall(): - return [0x0F, 0x05] - -def call(distance): - if type(distance) is int: - return [0xe8]+imm32(distance) - elif type(distance) is str and distance in regs64: - reg = distance - opcode = 0xFF # 0xFF /2 == call r/m64 - mod_rm = modrm(mod=3, reg=2, rm=regs64[reg]) - if rexbit[reg] == 1: - rexprefix = rex(b=rexbit[reg]) - return [rexprefix, opcode, mod_rm] - else: - return [opcode, mod_rm] - else: - Error('Cannot call to {0}'.format(distance)) - -def ret(): - return [ 0xc3 ] - -def increg64(reg): - assert(reg in regs64) - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xff - mod_rm = modrm(mod=3, rm=regs64[reg]) - return [rexprefix, opcode, mod_rm] - -def prepost8(r8, rm8): - assert(r8 in regs8) - pre = [] - if type(rm8) is list: - # TODO: merge mem access with prepost for 64 bits - if len(rm8) == 1: - base, = rm8 - if type(base) is str and base in regs64: - assert(not base in ['rbp', 'rsp', 'r12', 'r13']) - mod_rm = modrm(mod=0, rm=regs64[base], reg=regs8[r8]) - if rexbit[base] == 1: - pre.append(rex(b=1)) - post = [mod_rm] - else: - Error('One arg of type {0} not implemented'.format(base)) - elif len(rm8) == 2: - base, offset = rm8 - assert(type(offset) is int) - assert(base in regs64) - - if base == 'rsp' or base == 'r12': - Error('Cannot use rsp or r12 as base yet') - if rexbit[base] == 1: - pre.append( rex(b=1) ) - mod_rm = modrm(mod=1, rm=regs64[base], reg=regs8[r8]) - post = [mod_rm] + imm8(offset) - else: - Error('not supporting prepost8 with list len {0}'.format(len(rm8))) - else: - Error('Not supporting move with reg8 {0}'.format(r8)) - return pre, post - -def prepost(r64, rm64): - assert(r64 in regs64) - if type(rm64) is list: - if len(rm64) == 3: - base, index, disp = rm64 - assert(base in regs64) - assert(index in regs64) - assert(type(disp) is int) - # Assert that no special cases are used: - # TODO: swap base and index to avoid special cases - # TODO: exploit special cases and make better code - assert(index != 'rsp') - - rexprefix = rex(w=1, r=rexbit[r64], x=rexbit[index], b=rexbit[base]) - # mod=1 and rm=4 indicates a SIB byte: [--][--]+imm8 - mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) - si_b = sib(ss=0, index=regs64[index], base=regs64[base]) - return [rexprefix], [mod_rm, si_b] + imm8(disp) - elif len(rm64) == 2: - base, offset = rm64 - assert(type(offset) is int) - if base == 'RIP': - # RIP pointer relative addressing mode! - rexprefix = rex(w=1, r=rexbit[r64]) - mod_rm = modrm(mod=0, rm=5, reg=regs64[r64]) - return [rexprefix], [mod_rm] + imm32(offset) - else: - assert(base in regs64) - - if base == 'rsp' or base == 'r12': - # extended function that uses SIB byte - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) - # rm=4 indicates a SIB byte follows - mod_rm = modrm(mod=1, rm=4, reg=regs64[r64]) - # index=4 indicates that index is not used - si_b = sib(ss=0, index=4, base=regs64[base]) - return [rexprefix], [mod_rm, si_b] + imm8(offset) - else: - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base]) - mod_rm = modrm(mod=1, rm=regs64[base], reg=regs64[r64]) - return [rexprefix], [mod_rm] + imm8(offset) - elif len(rm64) == 1: - offset = rm64[0] - if type(offset) is int: - rexprefix = rex(w=1, r=rexbit[r64]) - mod_rm = modrm(mod=0, rm=4,reg=regs64[r64]) - si_b = sib(ss=0, index=4,base=5) # 0x25 - return [rexprefix], [mod_rm, si_b] + imm32(offset) - else: - Error('Memory reference of type {0} not implemented'.format(offset)) - else: - Error('Memory reference not implemented') - elif rm64 in regs64: - rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[rm64]) - mod_rm = modrm(3, rm=regs64[rm64], reg=regs64[r64]) - return [rexprefix], [mod_rm] - -def leareg64(rega, m): - opcode = 0x8d # lea r64, m - pre, post = prepost(rega, m) - return pre + [opcode] + post - -def mov(rega, regb): - if type(regb) is int: - pre = [rex(w=1, b=rexbit[rega])] - opcode = 0xb8 + regs64[rega] - post = imm64(regb) - elif type(regb) is str: - if regb in regs64: - opcode = 0x89 # mov r/m64, r64 - pre, post = prepost(regb, rega) - elif regb in regs8: - opcode = 0x88 # mov r/m8, r8 - pre, post = prepost8(regb, rega) - else: - Error('Unknown register {0}'.format(regb)) - elif type(rega) is str: - if rega in regs64: - opcode = 0x8b # mov r64, r/m64 - pre, post = prepost(rega, regb) - else: - Error('Unknown register {0}'.format(rega)) - else: - Error('Move of this kind {0}, {1} not implemented'.format(rega, regb)) - return pre + [opcode] + post - -def xorreg64(rega, regb): - rexprefix = rex(w=1, r=rexbit[regb], b=rexbit[rega]) - opcode = 0x31 # XOR r/m64, r64 - # Alternative is 0x33 XOR r64, r/m64 - mod_rm = modrm(3, rm=regs64[rega], reg=regs64[regb]) - return [rexprefix, opcode, mod_rm] - -# integer arithmatic: -def addreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x01 # ADD r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - if regb < 100: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # add r/m, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=0) - return [rexprefix, opcode, mod_rm]+imm8(regb) - elif regb < (1<<31): - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x81 # add r/m64, imm32 - mod_rm = modrm(3, rm=regs64[rega], reg=0) - return [rexprefix, opcode, mod_rm]+imm32(regb) - else: - Error('Constant value too large!') - else: - Error('unknown second operand!'.format(regb)) - -def subreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x29 # SUB r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - if regb < 100: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # sub r/m, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=5) - return [rexprefix, opcode, mod_rm]+imm8(regb) - elif regb < (1<<31): - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x81 # sub r/m64, imm32 - mod_rm = modrm(3, rm=regs64[rega], reg=5) - return [rexprefix, opcode, mod_rm]+imm32(regb) - else: - Error('Constant value too large!') - - else: - Error('unknown second operand!'.format(regb)) - -def idivreg64(reg): - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xf7 # IDIV r/m64 - mod_rm = modrm(3, rm=regs64[reg], reg=7) - return [rexprefix, opcode, mod_rm] - -def imulreg64_rax(reg): - rexprefix = rex(w=1, b=rexbit[reg]) - opcode = 0xf7 # IMUL r/m64 - mod_rm = modrm(3, rm=regs64[reg], reg=5) - return [rexprefix, opcode, mod_rm] - -def imulreg64(rega, regb): - pre, post = prepost(rega, regb) - opcode = 0x0f # IMUL r64, r/m64 - opcode2 = 0xaf - return pre + [opcode, opcode2] + post - -def cmpreg64(rega, regb): - if regb in regs64: - pre, post = prepost(regb, rega) - opcode = 0x39 # CMP r/m64, r64 - return pre + [opcode] + post - elif type(regb) is int: - rexprefix = rex(w=1, b=rexbit[rega]) - opcode = 0x83 # CMP r/m64, imm8 - mod_rm = modrm(3, rm=regs64[rega], reg=7) - return [rexprefix, opcode, mod_rm] + imm8(regb) - - else: - Error('not implemented cmp64') - -# Mapping that maps string names to the right functions: -opcodes = {'mov':(mov,2), 'lea':(leareg64,2), 'int':(INT,1), 'syscall':(syscall,0)} - diff -r 4d204f6f7d4e -r 86b02c98a717 python/yacc.py --- a/python/yacc.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/yacc.py Sat Mar 01 15:40:31 2014 +0100 @@ -286,6 +286,7 @@ exec(ob.getvalue(), parser_mod.__dict__) return parser_mod + def main(args): src = args.source.read() args.source.close() diff -r 4d204f6f7d4e -r 86b02c98a717 python/zcc.py --- a/python/zcc.py Fri Feb 28 18:07:14 2014 +0100 +++ b/python/zcc.py Sat Mar 01 15:40:31 2014 +0100 @@ -4,13 +4,13 @@ import os import argparse import logging -import yaml from ppci.buildtasks import Compile, Assemble, Link from ppci.tasks import TaskRunner from ppci.report import RstFormatter from ppci.objectfile import ObjectFile -from target.target_list import target_list +from ppci.target.target_list import target_list +from ppci.recipe import RecipeLoader import ppci @@ -51,64 +51,6 @@ return parser -class RecipeLoader: - """ Loads a recipe into a runner from a dictionary or file """ - def __init__(self): - self.directive_handlers = {} - for a in dir(self): - if a.startswith('handle_'): - f = getattr(self, a) - self.directive_handlers[a[7:]] = f - - def load_file(self, recipe_file, runner): - """ Loads a recipe dictionary into a task runner """ - self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) - with open(recipe_file, 'r') as f: - recipe = yaml.load(f) - self.runner = runner - self.load_dict(recipe) - - def relpath(self, filename): - return os.path.join(self.recipe_dir, filename) - - def openfile(self, filename): - return open(self.relpath(filename), 'r') - - def handle_compile(self, value): - sources = [self.openfile(s) for s in value['sources']] - includes = [self.openfile(i) for i in value['includes']] - target = targets[value['machine']] - output = ObjectFile() - task = Compile(sources, includes, target, output) - self.runner.add_task(task) - return task - - def handle_assemble(self, value): - asm_src = self.openfile(value['source']) - target = targets[value['machine']] - output = ObjectFile() - task = Assemble(asm_src, target, output) - self.runner.add_task(task) - return task - - def handle_link(self, value): - inputs = value['inputs'] - objs = [] - for i in inputs: - task = self.load_dict(i) - objs.append(task.output) - layout = value['layout'] - output = self.relpath(value['output']) - self.runner.add_task(Link(objs, layout, output)) - - def handle_apps(self, value): - for a in value: - self.load_dict(a) - - def load_dict(self, recipe): - for command, value in recipe.items(): - return self.directive_handlers[command](value) - def main(args): # Configure some logging: diff -r 4d204f6f7d4e -r 86b02c98a717 test/testarmasm.py --- a/test/testarmasm.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testarmasm.py Sat Mar 01 15:40:31 2014 +0100 @@ -1,16 +1,16 @@ import unittest -import outstream +from ppci.outstream import BinaryOutputStream from ppci.objectfile import ObjectFile from asm import Assembler from testasm import AsmTestCaseBase -from target.target_list import arm_target, thumb_target +from ppci.target.target_list import arm_target, thumb_target class ThumbAssemblerTestCase(AsmTestCaseBase): def setUp(self): self.t = thumb_target self.obj = ObjectFile() - self.o = outstream.BinaryOutputStream(self.obj) + self.o = BinaryOutputStream(self.obj) self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o) @@ -153,7 +153,7 @@ def setUp(self): self.t = arm_target self.obj = ObjectFile() - self.o = outstream.BinaryOutputStream(self.obj) + self.o = BinaryOutputStream(self.obj) self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o) diff -r 4d204f6f7d4e -r 86b02c98a717 test/testasm.py --- a/test/testasm.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testasm.py Sat Mar 01 15:40:31 2014 +0100 @@ -6,8 +6,8 @@ from ppci.assembler import tokenize, Assembler, Lexer from ppci.objectfile import ObjectFile from ppci.linker import Linker -import outstream -from target import Label +from ppci.outstream import BinaryOutputStream +from ppci.target.basetarget import Label class AssemblerLexingCase(unittest.TestCase): @@ -96,7 +96,7 @@ class OustreamTestCase(unittest.TestCase): def test1(self): obj = ObjectFile() - o = outstream.BinaryOutputStream(obj) + o = BinaryOutputStream(obj) o.selectSection('.text') o.emit(Label('a')) self.assertSequenceEqual(bytes(), obj.get_section('.text').data) diff -r 4d204f6f7d4e -r 86b02c98a717 test/testbintools.py --- a/test/testbintools.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testbintools.py Sat Mar 01 15:40:31 2014 +0100 @@ -1,9 +1,37 @@ import unittest import sys -from target.arminstructions import ArmToken +from ppci.target.arm.token import ArmToken from ppci.linker import Linker from ppci.objectfile import ObjectFile from ppci import CompilerError +from ppci.tasks import EmptyTask, TaskRunner, TaskError + + +class TaskTestCase(unittest.TestCase): + def testCircular(self): + t1 = EmptyTask('t1') + t2 = EmptyTask('t2') + t1.add_dependency(t2) + with self.assertRaises(TaskError): + t2.add_dependency(t1) + + def testCircularDeeper(self): + t1 = EmptyTask('t1') + t2 = EmptyTask('t2') + t3 = EmptyTask('t3') + t1.add_dependency(t2) + t2.add_dependency(t3) + with self.assertRaises(TaskError): + t3.add_dependency(t1) + + def testSort(self): + t1 = EmptyTask('t1') + t2 = EmptyTask('t2') + runner = TaskRunner() + t1.add_dependency(t2) + runner.add_task(t1) + runner.add_task(t2) + runner.run_tasks() class TokenTestCase(unittest.TestCase): diff -r 4d204f6f7d4e -r 86b02c98a717 test/testc3.py --- a/test/testc3.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testc3.py Sat Mar 01 15:40:31 2014 +0100 @@ -1,8 +1,8 @@ -from ppci.c3 import Builder, Lexer -from target import SimpleTarget -import ppci import unittest import io +from ppci.c3 import Builder, Lexer +from ppci.target import SimpleTarget +import ppci class testLexer(unittest.TestCase): diff -r 4d204f6f7d4e -r 86b02c98a717 test/testcg.py --- a/test/testcg.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testcg.py Sat Mar 01 15:40:31 2014 +0100 @@ -2,8 +2,8 @@ import ppci from ppci.codegen import CodeGenerator from ppci import ir -from target.target_list import thumb_target -import outstream +from ppci.target.target_list import thumb_target +from ppci.outstream import BinaryOutputStream def genTestFunction(): @@ -18,7 +18,7 @@ self.cg = CodeGenerator(thumb_target) def testFunction(self): - s = outstream.BinaryOutputStream(ppci.objectfile.ObjectFile()) + s = BinaryOutputStream(ppci.objectfile.ObjectFile()) m, f, bb = genTestFunction() bb.addInstruction(ir.Exp(ir.Const(123))) bb.addInstruction(ir.Jump(f.epiloog)) @@ -28,7 +28,7 @@ class testArmCodeGeneration(unittest.TestCase): def testStack(self): - s = outstream.BinaryOutputStream(ppci.objectfile.ObjectFile()) + s = BinaryOutputStream(ppci.objectfile.ObjectFile()) cg = CodeGenerator(thumb_target) m, f, bb = genTestFunction() bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22))) diff -r 4d204f6f7d4e -r 86b02c98a717 test/testgraph.py --- a/test/testgraph.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testgraph.py Sat Mar 01 15:40:31 2014 +0100 @@ -6,7 +6,7 @@ from ppci.codegen.flowgraph import FlowGraph from ppci import ir from ppci.irmach import AbstractInstruction as AI -from target import Nop +from ppci.target import Nop class GraphTestCase(unittest.TestCase): diff -r 4d204f6f7d4e -r 86b02c98a717 test/testir.py --- a/test/testir.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testir.py Sat Mar 01 15:40:31 2014 +0100 @@ -83,6 +83,7 @@ v1 = ir.Const(0) v3 = ir.Add(v1, ir.Const(0)) + class TestWriter(unittest.TestCase): def testWrite(self): writer = irutils.Writer() @@ -106,7 +107,7 @@ m = reader.read(f) self.assertTrue(m) #print(m) - + if __name__ == '__main__': unittest.main() diff -r 4d204f6f7d4e -r 86b02c98a717 test/testmsp430asm.py --- a/test/testmsp430asm.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testmsp430asm.py Sat Mar 01 15:40:31 2014 +0100 @@ -4,17 +4,17 @@ from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber from ppci.assembler import tokenize, Assembler from ppci.objectfile import ObjectFile -import outstream -from target import Label -from target.target_list import msp430target +from ppci.outstream import BinaryOutputStream +from ppci.target import Label +from ppci.target.target_list import msp430target from testasm import AsmTestCaseBase -class AssemblerMSP430TestCase(AsmTestCaseBase): +class Msp430AssemblerTestCase(AsmTestCaseBase): def setUp(self): self.t = msp430target self.obj = ObjectFile() - self.o = outstream.BinaryOutputStream(self.obj) + self.o = BinaryOutputStream(self.obj) self.o.selectSection('.text') self.a = Assembler(target=self.t, stream=self.o) @@ -34,10 +34,6 @@ self.feed("reti") self.check('0013') - def testMSPinstructionCount(self): - """ Check that there are 27 instructions """ - self.assertEqual(27, len(self.t.instructions)) - if __name__ == '__main__': unittest.main() diff -r 4d204f6f7d4e -r 86b02c98a717 test/testregalloc.py --- a/test/testregalloc.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testregalloc.py Sat Mar 01 15:40:31 2014 +0100 @@ -4,7 +4,7 @@ from ppci.irmach import makeIns, Frame from ppci.codegen.registerallocator import RegisterAllocator from ppci import ir -from target import Nop +from ppci.target import Nop class RegAllocTestCase(unittest.TestCase): diff -r 4d204f6f7d4e -r 86b02c98a717 test/testzcc.py --- a/test/testzcc.py Fri Feb 28 18:07:14 2014 +0100 +++ b/test/testzcc.py Sat Mar 01 15:40:31 2014 +0100 @@ -6,7 +6,7 @@ from ppci.objectfile import ObjectFile import ppci import io -import target +from ppci.target import target_list # Store testdir for safe switch back to directory: testdir = os.path.dirname(os.path.abspath(__file__)) @@ -102,7 +102,7 @@ """ f = io.StringIO(src) out = ObjectFile() - tg = target.target_list.armtarget + tg = target_list.armtarget tr = ppci.tasks.TaskRunner() tr.add_task(ppci.buildtasks.Compile([f], [], tg, out)) tr.run_tasks()