Source code for m2isar.frontends.coredsl2.parser

# SPDX-License-Identifier: Apache-2.0
#
# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R
#
# Copyright (C) 2022
# Chair of Electrical Design Automation
# Technical University of Munich

import argparse
import itertools
import logging
import pathlib
import pickle
import sys

from ... import M2Error, M2SyntaxError
from ...metamodel import (M2_METAMODEL_VERSION, M2Model, arch, behav,
                          patch_model)
from ...metamodel.code_info import CodeInfoBase
from . import expr_interpreter
from .architecture_model_builder import ArchitectureModelBuilder
from .behavior_model_builder import BehaviorModelBuilder
from .importer import recursive_import
from .load_order import LoadOrder
from .utils import make_parser


[docs] def main(): parser = argparse.ArgumentParser() parser.add_argument("top_level", help="The top-level CoreDSL file.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) args = parser.parse_args() logging.basicConfig(level=getattr(logging, args.log.upper())) logger = logging.getLogger("parser") top_level = pathlib.Path(args.top_level) abs_top_level = top_level.resolve() search_path = abs_top_level.parent parser = make_parser(abs_top_level) try: logger.info("parsing top level") tree = parser.description_content() recursive_import(tree, search_path) except M2SyntaxError as e: logger.critical("Error during parsing: %s", e) sys.exit(1) logger.info("reading instruction load order") lo = LoadOrder() try: cores = lo.visit(tree) except M2Error as e: logger.critical("Error during load order building: %s", e) sys.exit(1) model_path = search_path.joinpath('gen_model') model_path.mkdir(exist_ok=True) temp_save = {} models: "dict[str, arch.CoreDef]" = {} patch_model(expr_interpreter) for core_name, core_def in cores.items(): logger.info('building architecture model for core %s', core_name) try: arch_builder = ArchitectureModelBuilder() c = arch_builder.visit(core_def) except M2Error as e: logger.critical("Error building architecture model of core %s: %s", core_name, e) for orig, overwritten in arch_builder._overwritten_instrs: logger.warning("instr %s from extension %s was overwritten by %s from %s", orig.name, orig.ext_name, overwritten.name, overwritten.ext_name) temp_save[core_name] = (c, arch_builder) models[core_name] = c[-1] for core_name, core_def in models.items(): logger.info('building behavior model for core %s', core_name) warned_fns = set() logger.debug("checking core constants") unassigned_const = False for const in core_def.constants.values(): if const.value is None: logger.critical("constant %s in core %s has no value assigned!", const.name, core_name) unassigned_const = True #sys.exit(-1) if unassigned_const: sys.exit(-1) logger.debug("evaluating core parameters") for const_def in core_def.constants.values(): const_def._value = const_def.value for mem_def in itertools.chain(core_def.memories.values(), core_def.memory_aliases.values()): mem_def._size = mem_def.size mem_def.range._lower_base = mem_def.range.lower_base mem_def.range._upper_base = mem_def.range.upper_base for attr_name, attr_ops in mem_def.attributes.items(): ops = [] for attr_op in attr_ops: try: behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, {}, core_def.functions, warned_fns) op = behav_builder.visit(attr_op) ops.append(op) except M2Error as e: logger.critical("error processing attribute \"%s\" of memory \"%s\": %s", attr_name, fn_def.name, e) sys.exit(1) mem_def.attributes[attr_name] = ops for fn_def in core_def.functions.values(): if isinstance(fn_def.operation, behav.Operation) and not fn_def.extern: raise M2SyntaxError(f"non-extern function {fn_def.name} has no body") fn_def._size = fn_def.size for fn_arg in fn_def.args.values(): fn_arg._size = fn_arg.size fn_arg._width = fn_arg.width logger.debug("generating function behavior") for fn_name, fn_def in core_def.functions.items(): logger.debug("generating function %s", fn_name) logger.debug("generating attributes") for attr_name, attr_ops in fn_def.attributes.items(): ops = [] for attr_op in attr_ops: try: behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, fn_def.args, core_def.functions, warned_fns) op = behav_builder.visit(attr_op) ops.append(op) except M2Error as e: logger.critical("error processing attribute \"%s\" of function \"%s\": %s", attr_name, fn_def.name, e) sys.exit(1) fn_def.attributes[attr_name] = ops behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, fn_def.args, core_def.functions, warned_fns) if not isinstance(fn_def.operation, behav.Operation): try: op = behav_builder.visit(fn_def.operation) except M2Error as e: logger.critical("Error building behavior for function %s: %s", fn_name, e) sys.exit() fn_def.scalars = behav_builder._scalars if isinstance(op, list): fn_def.operation = behav.Operation(op) else: fn_def.operation = behav.Operation([op]) logger.debug("generating always blocks") always_block_statements = [] arch_builder = temp_save[core_name][1] for block_def in arch_builder._always_blocks.values(): logger.debug("generating always block %s", block_def.name) logger.debug("generating attributes") for attr_name, attr_ops in block_def.attributes.items(): ops = [] for attr_op in attr_ops: try: behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, {}, core_def.functions, warned_fns) op = behav_builder.visit(attr_op) ops.append(op) except M2Error as e: logger.critical("error processing attribute \"%s\" of instruction \"%s\": %s", attr_name, block_def.name, e) sys.exit(1) block_def.attributes[attr_name] = ops behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, {}, core_def.functions, warned_fns) try: op = behav_builder.visit(block_def.operation) except M2Error as e: logger.critical("error building behavior for always block %s: %s", block_def.name, e) sys.exit(1) always_block_statements.append(op) logger.debug("generating instruction behavior") for instr_def in core_def.instructions.values(): logger.debug("generating instruction %s", instr_def.name) logger.debug("generating attributes") for attr_name, attr_ops in instr_def.attributes.items(): ops = [] for attr_op in attr_ops: try: behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, instr_def.fields, core_def.functions, warned_fns) op = behav_builder.visit(attr_op) ops.append(op) except M2Error as e: logger.critical("error processing attribute \"%s\" of instruction \"%s\": %s", attr_name, instr_def.name, e) sys.exit(1) instr_def.attributes[attr_name] = ops behav_builder = BehaviorModelBuilder(core_def.constants, core_def.memories, core_def.memory_aliases, instr_def.fields, core_def.functions, warned_fns) try: op = behav_builder.visit(instr_def.operation) except M2Error as e: logger.critical("error building behavior for instruction %s::%s: %s", instr_def.ext_name, instr_def.name, e) sys.exit(1) instr_def.scalars = behav_builder._scalars if isinstance(op, list): op = behav.Operation(op) else: op = behav.Operation([op]) pc_inc = behav.Assignment( behav.NamedReference(core_def.pc_memory), behav.BinaryOperation( behav.NamedReference(core_def.pc_memory), behav.Operator("+"), behav.IntLiteral(int(instr_def.size/8)) ) ) #op.statements.insert(0, pc_inc) op.statements = always_block_statements + op.statements instr_def.operation = op logger.info("dumping model") with open(model_path / (abs_top_level.stem + '.m2isarmodel'), 'wb') as f: model_obj = M2Model( M2_METAMODEL_VERSION, models, CodeInfoBase.database ) pickle.dump(model_obj, f)
if __name__ == '__main__': main()