view python/outstream.py @ 331:a78b41ff6ad2

Added better recipe files
author Windel Bouwman
date Fri, 07 Feb 2014 12:39:59 +0100
parents 56e6ff84f646
children 582a1aaa3983
line wrap: on
line source

import binascii
from target import Instruction, Label, DebugInfo

"""
 The output stream is a stream of instructions that can be output
 to a file or binary or hexfile.
"""


class Section:
    def __init__(self):
        self.address = 0
        self.instructions = []

    def emit(self, item):
        assert isinstance(item, Instruction)
        self.instructions.append(item)

    def to_bytes(self):
        d = bytearray()
        for i in self.instructions:
            addr = i.address
            insword = i.encode()
            assert type(insword) is bytes
            d.extend(insword)
        return bytes(d)

    @property
    def Size(self):
        return len(self.to_bytes())

    def debugInfos(self):
        di = [i for i in self.instructions if isinstance(i, DebugInfo)]
        return di


class OutputStream:
    def __init__(self):
        self.sections = {}
        self.currentSection = None

    def emit(self, item):
        assert self.currentSection
        self.currentSection.emit(item)

    def selectSection(self, sname):
        self.currentSection = self.getSection(sname)

    def getLabelAddress(self, lname):
        assert isinstance(lname, str)
        for s in self.sections.values():
            for i in s.instructions:
                if type(i) is Label:
                    if i.name == lname:
                        return i.address
        return 0

    def getSection(self, name):
        if not name in self.sections:
            self.sections[name] = Section()
        return self.sections[name]

    def backpatch(self):
        """ Fixup references to other parts in the assembler """
        for s in self.sections.values():
            address = s.address
            for i in s.instructions:
                i.address = address
                i.resolve(self.getLabelAddress)
                bts = i.encode()
                address += len(bts)

class OutputStreamWriter:
    def __init__(self, extra_indent=''):
        self.extra_indent = extra_indent

    def dump(self, stream, f):
        stream.backpatch()
        stream.backpatch()
        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 TextOutputStream(OutputStream):
    pass


class BinOutputStream(OutputStream):

    @property
    def Data(self):
        d = self.dump()
        return bytes(d)

    def dump(self):
        self.backpatch()
        self.backpatch()
        section = self.sections[list(self.sections.keys())[0]]
        return section.to_bytes()