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:
parent
6ffafef794
commit
c7f719ab93
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1180,6 +1180,8 @@ class SignalTestCase(FHDLTestCase):
|
|||
self.assertEqual(s1.name, "s1")
|
||||
s2 = Signal(name="sig")
|
||||
self.assertEqual(s2.name, "sig")
|
||||
s3 = Signal(name="")
|
||||
self.assertEqual(s3.name, "")
|
||||
|
||||
def test_init(self):
|
||||
s1 = Signal(4, init=0b111, reset_less=True)
|
||||
|
@ -1294,6 +1296,8 @@ class SignalTestCase(FHDLTestCase):
|
|||
def test_repr(self):
|
||||
s1 = Signal()
|
||||
self.assertEqual(repr(s1), "(sig s1)")
|
||||
s2 = Signal(name="")
|
||||
self.assertEqual(repr(s2), "(sig)")
|
||||
|
||||
def test_like(self):
|
||||
s1 = Signal.like(Signal(4))
|
||||
|
|
|
@ -962,6 +962,7 @@ class NamesTestCase(FHDLTestCase):
|
|||
o1 = Signal()
|
||||
o2 = Signal()
|
||||
o3 = Signal()
|
||||
o4 = Signal(name="")
|
||||
i1 = Signal(name="i")
|
||||
|
||||
f = Fragment()
|
||||
|
@ -980,6 +981,7 @@ class NamesTestCase(FHDLTestCase):
|
|||
"o1": (o1, PortDirection.Output),
|
||||
"o2": (o2, PortDirection.Output),
|
||||
"o3": (o3, PortDirection.Output),
|
||||
"o4": (o4, PortDirection.Output),
|
||||
}
|
||||
design = f.prepare(ports)
|
||||
self.assertEqual(design.fragments[design.fragment].signal_names, SignalDict([
|
||||
|
@ -988,12 +990,20 @@ class NamesTestCase(FHDLTestCase):
|
|||
(o1, "o1"),
|
||||
(o2, "o2"),
|
||||
(o3, "o3"),
|
||||
# (o4, "o4"), # Signal has a private name.
|
||||
(cd_sync.clk, "clk"),
|
||||
(cd_sync.rst, "rst$6"),
|
||||
(cd_sync.rst, "rst$7"),
|
||||
(cd_sync_norst.clk, "sync_norst_clk"),
|
||||
(i1, "i$7"),
|
||||
(i1, "i$8"),
|
||||
]))
|
||||
|
||||
def test_wrong_private_unnamed_toplevel_ports(self):
|
||||
s = Signal(name="")
|
||||
f = Fragment()
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Signals with private names cannot be used in unnamed top-level ports$"):
|
||||
Design(f, ports=((None, s, None),), hierarchy=("top",))
|
||||
|
||||
def test_assign_names_to_fragments(self):
|
||||
f = Fragment()
|
||||
f.add_subfragment(a := Fragment())
|
||||
|
|
|
@ -14,6 +14,7 @@ from amaranth.hdl._dsl import *
|
|||
from amaranth.hdl._ir import *
|
||||
from amaranth.sim import *
|
||||
from amaranth.lib.memory import Memory
|
||||
from amaranth.lib.data import View, StructLayout
|
||||
|
||||
from .utils import *
|
||||
from amaranth._utils import _ignore_deprecated
|
||||
|
@ -1042,6 +1043,21 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
with sim.write_vcd(f):
|
||||
pass
|
||||
|
||||
def test_vcd_private_signal(self):
|
||||
sim = Simulator(Module())
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Cannot trace signal with private name$"):
|
||||
with open(os.path.devnull, "w") as f:
|
||||
with sim.write_vcd(f, traces=(Signal(name=""),)):
|
||||
pass
|
||||
|
||||
sim = Simulator(Module())
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Cannot trace signal with private name \(within \(cat \(sig x\) \(sig\)\)\)$"):
|
||||
with open(os.path.devnull, "w") as f:
|
||||
with sim.write_vcd(f, traces=(Cat(Signal(name="x"), Signal(name="")),)):
|
||||
pass
|
||||
|
||||
def test_no_negated_boolean_warning(self):
|
||||
m = Module()
|
||||
a = Signal()
|
||||
|
|
Loading…
Reference in a new issue