Source code for hwtBuildsystem.cli_utils.unit_from_cli_args


import argparse
import inspect
from io import StringIO
import os
import sys
from typing import Type, Optional, List, Dict

from hdlConvertorAst.translate.common.name_scope import LanguageKeyword
from hwt.serializer.store_manager import SaveToSingleFiles
from hwt.serializer.verilog import VerilogSerializer
from hwt.serializer.vhdl import Vhdl2008Serializer
from hwt.synthesizer.unit import Unit
from hwt.synthesizer.utils import to_rtl
from hwtBuildsystem.hwt.multiConfigUnit import MultiConfigUnitWrapper


def _parse_configs(defInstance: Unit, args: List[str], default_params: List[Dict[str, object]]):
    configs_cnt = None
    for p in defInstance._params:
        v = getattr(args, p._name)
        if configs_cnt is None:
            configs_cnt = len(v)
        else:
            assert configs_cnt == len(v), ("All parameters must have same number of values,"
                                           " because each item represents a value for specific combination")
    assert configs_cnt is not None, ("At least some parameters needs to be specified,"
        " otherwise you can instantiate component directly and you do not need this function")

    unitConfigs = []
    for i in range(configs_cnt):
        conf = {}
        for p in defInstance._params:
            v = getattr(args, p._name)
            v = p.get_value().__class__(v[i])
            conf[p._name] = v
        unitConfigs.append(conf)

    for conf in default_params:
        assert len(conf) == len(defInstance._params), (conf, defInstance._params)
        for p in defInstance._params:
            v = conf[p._name]
            v = p.get_value().__class__(v)
            conf[p._name] = v

        unitConfigs.append(conf)

    unitConfigs = [tuple(sorted(c.items(), key=lambda x: x[0])) for c in unitConfigs]
    seenConfigs = set()
    for c in unitConfigs:
        if c not in seenConfigs:
            yield c
            seenConfigs.add(c)


[docs]def ban_names_in_serializer(serializer_cls: Type, reserved_ids: Optional[List[str]]) -> Type: if reserved_ids is None: return serializer_cls else: class ToHdlAst(serializer_cls.TO_HDL_AST): _keywords_dict = dict(serializer_cls.TO_HDL_AST._keywords_dict, **{name: LanguageKeyword() for name in reserved_ids}) class Serializer(serializer_cls): TO_HDL_AST = ToHdlAst return Serializer
[docs]def unit_from_cli_args(unitCls: Type, default_params: List[Dict[str, object]], args:Optional[List[str]]=None, out_folder:Optional[str]=None, unit_name:Optional[str]=None, reserved_ids:Optional[List[str]]=None, stdout:StringIO=None): """ :param unitCls: unit class or anything callable which produces instance of Unit :param default_params: list of default parameters for a component to resolve which parameters/generics affect which port width :param args: list of CLI arguments, if None the CLI args of this python execution are used :param reserved_ids: optional list of identifier names which should not be used in generated code (used to prevent name collisions) """ defInstance = unitCls() if stdout is None: stdout = sys.stdout parser = argparse.ArgumentParser('Generate hwt component files from specification of possible parameter/generic values') parser.add_argument('-f', '--files', action='store_true', help='Print all source absolute file paths') parser.add_argument('-g', '--generics', action='store_true', help='Print component generics') parser.add_argument('-c', '--component', action='store_true', help='Print component name') parser.add_argument('-l', '--language', type=str, choices=["vhdl2008", "sv2012"], default="vhdl2008", help='Specifies target language') for p in defInstance._params: parser.add_argument(f'--{p._name}', default=[p.get_value(), ], nargs='+') args = parser.parse_args(args=args) if args.component: stdout.write(str(defInstance._getDefaultName())) return if args.generics: stdout.write(str(' '.join([p._name for p in defInstance._params]))) return unitVariants = [] for conf in _parse_configs(defInstance, args, default_params): curInst = unitCls() for param_name, param_value in conf: setattr(curInst, param_name, param_value) unitVariants.append(curInst) if unit_name is None: unitFile = inspect.getfile(defInstance.__class__) unit_name = os.path.splitext(os.path.basename(unitFile))[0] if out_folder is None: out_folder = os.getcwd() rtl_dir_path = os.path.join(out_folder, unit_name) serializers = { "vhdl2008": ban_names_in_serializer(Vhdl2008Serializer, reserved_ids), "sv2012": ban_names_in_serializer(VerilogSerializer, reserved_ids), } store_man = SaveToSingleFiles(serializers[args.language], rtl_dir_path, name=unit_name) multiConfUnit = MultiConfigUnitWrapper(unitVariants) to_rtl(multiConfUnit, store_manager=store_man) if args.files: stdout.write(str(' '.join(list(filter(None, store_man.files))))) return