Source code for hwt.synthesizer.rtlLevel.netlist

from typing import List, Optional, Union, Dict, Set

from hdlConvertorAst.hdlAst._defs import HdlIdDef
from hdlConvertorAst.hdlAst._expr import HdlValueId
from hdlConvertorAst.hdlAst._structural import HdlModuleDec, HdlModuleDef, \
    HdlCompInst
from hwt.code import If
from hwt.doc_markers import internal
from hwt.hdl.operatorDefs import AllOps
from hwt.hdl.statements.statement import HdlStatement
from hwt.hdl.types.defs import BIT
from hwt.hdl.types.hdlType import HdlType
from hwt.hdl.value import HValue
from hwt.serializer.utils import HdlStatement_sort_key, RtlSignal_sort_key
from hwt.synthesizer.dummyPlatform import DummyPlatform
from hwt.synthesizer.exceptions import SigLvlConfErr
from hwt.synthesizer.interfaceLevel.mainBases import InterfaceBase
from hwt.synthesizer.param import Param
from hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal, NOT_SPECIFIED
from hwt.synthesizer.rtlLevel.rtlSyncSignal import RtlSyncSignal
from hwt.synthesizer.rtlLevel.statements_to_HdlStmCodeBlockContainers import statements_to_HdlStmCodeBlockContainers
from ipCorePackager.constants import DIRECTION


[docs]class RtlNetlist(): """ Hierarchical container for signals :ivar ~.parent: optional parent for debug and late component inspection :ivar ~.signals: set of all signals in this context :ivar ~.statements: list of all statements which are connected to signals in this context :ivar ~.subUnits: is set of all units in this context :ivar ~.interfaces: initialized in create_HdlModuleDef :ivar ~.ent: initialized in create_HdlModuleDec :ivar ~.arch: initialized in create_HdlModuleDef """
[docs] def __init__(self, parent: Optional["Unit"]=None): self.parent = parent self.signals: Set[RtlSignal] = set() self.statements: Set[HdlStatement] = set() self.subUnits: Set["Unit"] = set() self.interfaces: Dict[RtlSignal, DIRECTION] = {} self.ent: Optional[HdlModuleDec] = None self.arch: Optional[HdlModuleDef] = None
[docs] def sig(self, name: str, dtype=BIT, clk=None, syncRst=None, def_val=None, nop_val=NOT_SPECIFIED) -> Union[RtlSignal, RtlSyncSignal]: """ Create new signal in this context :param clk: clock signal, if specified signal is synthesized as RtlSyncSignal :param syncRst: synchronous reset signal :param def_val: a default value used for reset and initialization :param nop_val: a value which is used to drive the signal if there is no other drive (used to prevent latches and to specify default values for unconnected signals) """ _def_val = _try_cast_any_to_HValue(def_val, dtype, True) if nop_val is not NOT_SPECIFIED: nop_val = _try_cast_any_to_HValue(nop_val, dtype, False) if clk is not None: s = RtlSyncSignal(self, name, dtype, _def_val if isinstance(_def_val, HValue) else dtype.from_py(None), nop_val) if syncRst is not None and def_val is None: raise SigLvlConfErr( "Probably forgotten default value on sync signal %s", name) # dst_resolve_fn is overridden because default assign would assign to the "next" signal if syncRst is not None: r = If(syncRst._isOn(), s(_def_val, dst_resolve_fn=lambda x: x) ).Else( s(s.next, dst_resolve_fn=lambda x: x) ) else: r = [ s(s.next, dst_resolve_fn=lambda x: x) ] if isinstance(clk, (InterfaceBase, RtlSignal)): clk_trigger = clk._onRisingEdge() else: # has to be tuple of (clk_sig, AllOps.RISING/FALLING_EDGE) clk, clk_edge = clk if clk_edge is AllOps.RISING_EDGE: clk_trigger = clk._onRisingEdge() elif clk_edge is AllOps.FALLING_EDGE: clk_trigger = clk._onRisingEdge() else: raise ValueError( "Invalid clock edge specification", clk_edge) If(clk_trigger, r ) else: if syncRst: raise SigLvlConfErr( f"Signal {name:s} has reset but has no clk") assert isinstance(_def_val, HValue) or (isinstance(_def_val, RtlSignal) and _def_val._const), (_def_val, "The default value needs to be constant") s = RtlSignal(self, name, dtype, def_val=_def_val, nop_val=nop_val) return s
[docs] def create_HdlModuleDec(self, name: str, store_manager: "StoreManager", params: List[Param]): """ Generate a module header (entity) for this module """ self.ent = ent = HdlModuleDec() ent.name = store_manager.name_scope.checked_name(name, ent) ns = store_manager.hierarchy_push(ent) # create generics for p in sorted(params, key=lambda x: x._name): hdl_val = p.get_hdl_value() v = HdlIdDef() v.origin = p v.name = p.hdl_name = ns.checked_name(p._name, p) v.type = hdl_val._dtype v.value = hdl_val ent.params.append(v) return ent
[docs] def create_HdlModuleDef(self, target_platform: DummyPlatform, store_manager: "StoreManager"): """ Generate a module body (architecture) for this module * Resolve name collisions * Convert netlist representation to HdlProcesses * Remove unconnected * Mark visibility of signals """ for proc in target_platform.beforeHdlArchGeneration: proc(self) ns = store_manager.name_scope mdef = HdlModuleDef() mdef.dec = self.ent mdef.module_name = HdlValueId(self.ent.name, obj=self.ent) mdef.name = "rtl" processes = sorted(self.statements, key=HdlStatement_sort_key) processes = sorted(statements_to_HdlStmCodeBlockContainers(processes), key=HdlStatement_sort_key) # add signals, variables, etc. in architecture for s in sorted((s for s in self.signals if not s.hidden and s not in self.interfaces.keys()), key=RtlSignal_sort_key): s: RtlSignal assert s.ctx is self, ("RtlSignals in this context must know that they are in this context", s) v = HdlIdDef() v.origin = s s.name = v.name = ns.checked_name(s.name, s) v.type = s._dtype v.value = s.def_val v.is_const = s._const mdef.objs.append(v) for p in processes: p.name = ns.checked_name(p.name, p) mdef.objs.extend(processes) # instantiate subUnits in architecture for u in self.subUnits: ci = HdlCompInst() ci.origin = u ci.module_name = HdlValueId(u._ctx.ent.name, obj=u._ctx.ent) ci.name = HdlValueId(ns.checked_name(u._name + "_inst", ci), obj=u) e = u._ctx.ent ci.param_map.extend(e.params) ci.port_map.extend(e.ports) mdef.objs.append(ci) self.arch = mdef return mdef
[docs] def getDebugScopeName(self): scope = [] p = self.parent while p is not None: scope.append(p._name) try: p = p._parent except AttributeError: break return ".".join(reversed(scope))
[docs]@internal def _try_cast_any_to_HValue(v, dtype: HdlType, require_const: bool): if isinstance(v, RtlSignal): assert not require_const or v._const, \ "Initial value of signal has to be a constant" return v._auto_cast(dtype) elif isinstance(v, HValue): return v._auto_cast(dtype) elif isinstance(v, InterfaceBase): return v._sig else: return dtype.from_py(v)