view python/target.py @ 242:c94965418684

Added tag burnchain for changeset ce6d390043a7
author Windel Bouwman
date Mon, 22 Jul 2013 22:56:51 +0200
parents 8786811a5a59
children e41e4109addd
line wrap: on
line source

from 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 Imm8:
    def __init__(self, imm):
        assert imm < 256
        self.imm = imm

    @classmethod
    def Create(cls, vop):
        if type(vop) is ANumber and vop.number < 256:
            return cls(vop.number)

class Imm3:
    def __init__(self, imm):
        assert imm < 8
        assert type(imm) is int
        self.imm = imm

    @classmethod
    def Create(cls, vop):
        if type(vop) is ANumber and vop.number < 8:
            return cls(vop.number)

class Imm32:
    def __init__(self, imm):
        assert imm < 2**32
        assert type(imm) is int
        self.imm = imm

    @classmethod
    def Create(cls, vop):
        if type(vop) is ANumber and vop.number < 2**32:
            return cls(vop.number)


class LabelRef:
    def __init__(self, name):
        self.name = name

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            return cls(vop.name)

class Instruction:
    def encode(self):
        raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self)))
    def resolve(self, f):
        pass


class PseudoInstruction(Instruction):
    pass


class Label(PseudoInstruction):
    def __init__(self, name):
        self.name = name
        self.address = 0

    def __repr__(self):
        return '{}:'.format(self.name)

    def encode(self):
        return bytes()

    @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 = []
        address = self.address
        while (address % self.align) != 0:
            address += 1
            pad.append(0)
        return bytes(pad)


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.instructions = []

    def instruction(self, cls):
        """ Decorator function that registers an instruction to this target """
        self.addInstruction(cls)
        return cls

    def check(self):
        """ Check target """
        for i in self.instructions:
            assert hasattr(i, 'mnemonic')
            assert hasattr(i, 'operands'), str(i)
            assert type(i.mnemonic) is str
            assert type(i.operands) is tuple, str(i)

    def addInstruction(self, ins_class):
        self.instructions.append(ins_class)

    def mapOperand(self, operand):
        """ Try to map an operand to a target type """
        if type(operand) is ASymbol:
            # Try to map to register:
            regs = {}
            for r in self.registers:
                regs[r.name] = r
            if operand.name in regs:
                return regs[operand.name]
        raise CompilerError('Cannot map {0}'.format(operand))

    def mapInstruction(self, vi):
        assert type(vi) is AInstruction
        """ Map ast tree to real instruction for this target """

        # map to real operands:
        if vi.mnemonic.upper() == 'ALIGN' and len(vi.operands) == 1:
            if type(vi.operands[0]) == ANumber:
                return Alignment(vi.operands[0].number)

        # look for a suitable instruction
        for ic in self.instructions:
            if ic.mnemonic.upper() == vi.mnemonic.upper() and len(ic.operands) == len(vi.operands):
                # Try to map operands to the correct operand types:
                rops = [roptype.Create(vop) for roptype, vop in zip(ic.operands, vi.operands)]

                # Check if we succeeded:
                optypes = tuple(map(type, rops))
                if ic.operands == optypes:
                    return ic(*rops)
        raise CompilerError('No suitable instruction found for "{0}"'.format(vi))