view python/zcc.py @ 327:61c9df5bffce

Changed emulated board to cortex a8 board
author Windel Bouwman
date Sat, 01 Feb 2014 17:21:21 +0100
parents e9fe6988497c
children 8f6f3ace4e78
line wrap: on
line source

#!/usr/bin/env python

import sys
import argparse
import logging

from ppci.c3 import Builder, AstPrinter
import ppci
from ppci.irutils import Verifier, Writer
from ppci.codegen import CodeGenerator
import outstream
from utils import HexFile
import target
from target.target_list import target_list
from ppci import irutils
import io
from ppci.transform import CleanPass, RemoveAddZero


logformat='%(asctime)s|%(levelname)s|%(name)s|%(message)s'


def logLevel(s):
    """ Converts a string to a valid logging level """
    numeric_level = getattr(logging, s.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: {}'.format(s))
    return numeric_level


class RstFormatter(logging.Formatter):
    """ Formatter that tries to create an rst document """
    def __init__(self):
        super().__init__(fmt=logformat)

    def format(self, record):
        s = super().format(record)
        s += '\n'
        if hasattr(record, 'c3_ast'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            AstPrinter().printAst(record.c3_ast, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ircode'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            Writer('  ').write(record.ircode, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'irfunc'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            Writer('  ').write_function(record.irfunc, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ppci_frame'):
            f = io.StringIO()
            frame = record.ppci_frame
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            print('  {}'.format(frame.name), file=f)
            for i in frame.instructions:
                print('   {}'.format(i),file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ra_cfg'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. graphviz::', file=f)
            print('', file=f)
            print('  digraph G {', file=f)
            print('    size="8,80";', file=f)
            cfg = record.ra_cfg
            cfg.to_dot(f)
            print('  }', file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ra_ig'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. graphviz::', file=f)
            print('', file=f)
            print('  digraph G {', file=f)
            print('    ratio="compress";', file=f)
            print('    size="8,80";', file=f)
            ig = record.ra_ig
            ig.to_dot(f)
            print('  }', file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'zcc_outs'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            outstream.OutputStreamWriter('  ').dump(record.zcc_outs, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        return s


targets = {t.name: t for t in target_list}
targetnames = list(targets.keys())

# Parse arguments:
parser = argparse.ArgumentParser(description='lcfos Compiler')
parser.add_argument('source', type=argparse.FileType('r'), \
  help='the source file to build', nargs="+")
parser.add_argument('-i', '--imp', type=argparse.FileType('r'), \
  help='Possible import module', action='append', default=[])

parser.add_argument('--optimize', action='store_true', help="Optimize")
parser.add_argument('--target', help="Backend selection",
    choices=targetnames, required=True)
parser.add_argument('-o', '--output', help='Output file', metavar='filename')
parser.add_argument('--hexfile', help='Output hexfile',
    type=argparse.FileType('w'))
parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])', 
                    type=logLevel, default='WARN')
parser.add_argument('--report', 
            help='Specify a file to write the compile report to', 
            type=argparse.FileType('w'))


def zcc(srcs, imps, tg, outs, diag):
    """
        Compiler driver
        Compile sources into output stream.
        Sources is an iterable of open files.
    """
    logger = logging.getLogger('zcc')
    logger.info('Zcc started {}'.format(srcs))
    # Front end:
    c3b = Builder(diag, tg)
    cg = CodeGenerator(tg)

    # TODO: remove this arm specifics:
    outs.getSection('code').address = 0x08000000
    outs.getSection('data').address = 0x20000000

    # Emit some custom start code:
    tg.startCode(outs)
    for ircode in c3b.build(srcs, imps):
        if not ircode:
            return

        d = {'ircode':ircode}
        logger.info('Verifying code {}'.format(ircode), extra=d)
        Verifier().verify(ircode)

        # Optimization passes:
        CleanPass().run(ircode)
        Verifier().verify(ircode)
        RemoveAddZero().run(ircode)
        Verifier().verify(ircode)
        CleanPass().run(ircode)
        Verifier().verify(ircode)

        # Code generation:
        d = {'ircode':ircode}
        logger.info('Starting code generation for {}'.format(ircode), extra=d)
        cg.generate(ircode, outs)
    # TODO: fixup references, do this in another way?
    outs.backpatch()
    outs.backpatch()  # Why two times?
    return c3b.ok


def main(args):
    # Configure some logging:
    logging.getLogger().setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setFormatter(logging.Formatter(logformat))
    ch.setLevel(args.log)
    logging.getLogger().addHandler(ch)
    if args.report:
        fh = logging.StreamHandler(stream=args.report)
        fh.setFormatter(RstFormatter())
        logging.getLogger().addHandler(fh)

    tg = targets[args.target]
    diag = ppci.DiagnosticsManager()
    outs = outstream.TextOutputStream()

    res = zcc(args.source, args.imp, tg, outs, diag)
    if not res:
        diag.printErrors()
        return 1

    logging.info('Assembly created', extra={'zcc_outs':outs})

    code_bytes = outs.sections['code'].to_bytes()
    if args.output:
        output_filename = args.output
        with open(output_filename, 'wb') as f:
            f.write(code_bytes)

    if args.hexfile:
        logging.info('Creating hexfile')
        hf = HexFile()
        hf.addRegion(0x08000000, code_bytes)
        hf.save(args.hexfile)

    if args.report:
        logging.getLogger().removeHandler(fh)
    logging.getLogger().removeHandler(ch)
    return 0


if __name__ == '__main__':
    arguments = parser.parse_args()
    sys.exit(main(arguments))