Source code for hwt.synthesizer.rtlLevel.statements_to_HdlStmCodeBlockContainers

from copy import copy
from itertools import compress
from typing import Generator, List, Tuple

from hwt.doc_markers import internal
from hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer
from hwt.hdl.statements.statement import HwtSyntaxError
from hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement
from hwt.pyUtils.uniqList import UniqList
from hwt.synthesizer.rtlLevel.constants import NOT_SPECIFIED
from hwt.synthesizer.rtlLevel.fill_stm_list_with_enclosure import fill_stm_list_with_enclosure, \
    HdlAssignmentContainer_constructor
from hwt.synthesizer.rtlLevel.mainBases import RtlSignalBase
from hwt.synthesizer.rtlLevel.reduce_processes import reduceProcesses
from hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal


[docs]@internal def cut_off_drivers_of(dstSignal: RtlSignal, statements: ListOfHdlStatement)\ -> Tuple[ListOfHdlStatement, ListOfHdlStatement]: """ Cut off drivers from statements """ separated = ListOfHdlStatement() stm_filter = [] for stm in statements: stm._clean_signal_meta() d = stm._cut_off_drivers_of(dstSignal) if d is not None: separated.append(d) f = d is not stm stm_filter.append(f) return ListOfHdlStatement(compress(statements, stm_filter)), separated
[docs]@internal def name_for_process(outputs: List[RtlSignal]) -> str: """ Resolve name for process """ out_names = [] for sig in outputs: if not sig.hasGenericName: out_names.append(sig.name) if out_names: return min(out_names) else: return ""
[docs]@internal def _statements_to_HdlStmCodeBlockContainers(_statements, tryToSolveCombLoops: bool)\ ->Generator[HdlStmCodeBlockContainer, None, None]: assert _statements # try to simplify statements proc_statements = ListOfHdlStatement() for _stm in _statements: _stm._clean_signal_meta() stms, _ = _stm._try_reduce() proc_statements.extend(stms) if not proc_statements: return outputs = UniqList() _inputs = UniqList() sensitivity = UniqList() enclosed_for = set() _proc_statements = ListOfHdlStatement() for _stm in proc_statements: seen = set() _stm._discover_sensitivity(seen) _stm._discover_enclosure() if _stm._outputs: # remove a statement entirely if it has no ouput # (empty if statment or something similar) # simulation only processes should not be processed by this function # and process should always drive something, unless it is useless outputs.extend(_stm._outputs) _inputs.extend(_stm._inputs) sensitivity.extend(_stm._sensitivity) enclosed_for.update(_stm._enclosed_for) _proc_statements.append(_stm) proc_statements = _proc_statements if not proc_statements: # this can happen e.g. when If does not contains any HdlAssignmentContainer return sensitivity_recompute = False enclosure_recompute = False enclosure_values = {} for sig in outputs: # inject nop_val if needed if sig._nop_val is not NOT_SPECIFIED and sig not in enclosed_for: enclosure_recompute = True n = sig._nop_val enclosure_values[sig] = HdlAssignmentContainer_constructor(n, sig) if isinstance(n, RtlSignalBase): _inputs.append(n) sensitivity_recompute = True if enclosure_recompute: # we have some enclosure values, try fill missing code branches with # this values do_enclose_for = [o for o in outputs if o in enclosure_values] fill_stm_list_with_enclosure(None, enclosed_for, proc_statements, do_enclose_for, enclosure_values) if enclosure_recompute or sensitivity_recompute: for _stm in proc_statements: _stm._clean_signal_meta() seen = set() _stm._discover_sensitivity(seen) _stm._discover_enclosure() if sensitivity_recompute: sensitivity.clear() for _stm in proc_statements: sensitivity.extend(_stm._sensitivity) for o in outputs: assert not o.hidden, o seen = set() inputs = UniqList() for i in _inputs: inputs.extend(i._walk_public_drivers(seen)) intersect = outputs.intersection_set(sensitivity) if intersect: # there is a combinational loop inside a single process which # can not be solved by separation of statments in process if not tryToSolveCombLoops: raise HwtSyntaxError( "Combinational loop on signal(s)", intersect) # try to solve combinational loops by separating drivers of signals # from statements for sig in intersect: proc_statements, proc_stms_select = cut_off_drivers_of( sig, proc_statements) yield from _statements_to_HdlStmCodeBlockContainers(proc_stms_select, False) if proc_statements: yield from _statements_to_HdlStmCodeBlockContainers(proc_statements, False) else: # no combinational loops, wrap current statemetns to a process instance name = name_for_process(outputs) yield HdlStmCodeBlockContainer.from_known_io( "assig_process_" + name, proc_statements, sensitivity, inputs, outputs)
[docs]@internal def statements_to_HdlStmCodeBlockContainers(statements: ListOfHdlStatement)\ ->Generator[HdlStmCodeBlockContainer, None, None]: """ Pack statements into HdlStmCodeBlockContainer instances * for each out signal resolve it's drivers and collect them * split statements if there is and combinational loop * merge statements if it is possible * resolve sensitivity lists * wrap into HdlStmCodeBlockContainer instance * for every IO of process generate name if signal has not any """ # create copy because this set will be reduced statements = copy(statements) # process ranks = how many assignments is probably in process # used to minimize number of merge tries processes = [] while statements: stm = statements.pop() proc_statements = [stm, ] ps = _statements_to_HdlStmCodeBlockContainers(proc_statements, True) processes.extend(ps) yield from reduceProcesses(processes)