hdl.ast: allow Signals to be privately named using name=""

* Given a private name `$\d+` in RTLIL (as they are not named in the IR)

* Not automatically added to VCD files (as they are not named in the IR)

* Cannot be traced to a VCD (as they have no name to put in the file)

* Cannot be used with an unnamed top-level port (as there is no name)
This commit is contained in:
Thomas Watson 2024-03-23 11:33:29 -05:00 committed by Catherine
parent 6ffafef794
commit c7f719ab93
6 changed files with 56 additions and 6 deletions

View file

@ -1884,7 +1884,8 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
If not specified, ``shape`` defaults to 1-bit and non-signed.
name : str
Name hint for this signal. If ``None`` (default) the name is inferred from the variable
name this ``Signal`` is assigned to.
name this ``Signal`` is assigned to. If the empty string, then this ``Signal`` is treated
as private and is generally hidden from view.
init : int or integral Enum
Reset (synchronous) or default (combinatorial) value.
When this ``Signal`` is assigned to in synchronous context and the corresponding clock
@ -1920,7 +1921,10 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
if name is not None and not isinstance(name, str):
raise TypeError(f"Name must be a string, not {name!r}")
self.name = name or tracer.get_var_name(depth=2 + src_loc_at, default="$signal")
if name is None:
self.name = tracer.get_var_name(depth=2 + src_loc_at, default="$signal")
else:
self.name = name
orig_shape = shape
if shape is None:
@ -2102,7 +2106,10 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
return SignalSet((self,))
def __repr__(self):
return f"(sig {self.name})"
if self.name != "":
return f"(sig {self.name})"
else:
return "(sig)"
@final

View file

@ -552,6 +552,8 @@ class Design:
assigned_names = {name for name, conn, dir in self.ports if name is not None}
for name, conn, dir in self.ports:
if name is None:
if conn.name == "": # Nothing to name this port!
raise TypeError("Signals with private names cannot be used in unnamed top-level ports")
name = _add_name(assigned_names, conn.name)
assigned_names.add(name)
new_ports.append((name, conn, dir))
@ -590,7 +592,7 @@ class Design:
frag_info.io_port_names[conn] = name
for signal in frag_info.used_signals:
if signal not in frag_info.signal_names:
if signal not in frag_info.signal_names and signal.name != "": # Private name shouldn't be added.
frag_info.signal_names[signal] = _add_name(frag_info.assigned_names, signal.name)
for port in frag_info.used_io_ports:
if port not in frag_info.io_port_names:

View file

@ -4,6 +4,7 @@ import warnings
from .._utils import deprecated
from ..hdl._cd import *
from ..hdl._ir import *
from ..hdl._ast import Value, ValueLike
from ._base import BaseEngine
@ -238,5 +239,15 @@ class Simulator:
file.close()
raise ValueError("Cannot start writing waveforms after advancing simulation time")
for trace in traces:
if isinstance(trace, ValueLike):
trace_cast = Value.cast(trace)
for trace_signal in trace_cast._rhs_signals():
if trace_signal.name == "":
if trace_signal is trace:
raise TypeError("Cannot trace signal with private name")
else:
raise TypeError(f"Cannot trace signal with private name (within {trace!r})")
return self._engine.write_vcd(vcd_file=vcd_file, gtkw_file=gtkw_file,
traces=traces, fs_per_delta=fs_per_delta)