Repository: amaranth-lang/amaranth (python)

Issue:
pysim: testbench-only signals are not placed at root level on the VCD file
Consider:
```python
from nmigen import Signal, Module
from nmigen.sim import Simulator

m = Module()
s = Signal()
t = Signal()
m.d.sync += s.eq(1)


def process():
    yield t.eq(1)


for engine in ["pysim", "cxxsim"]:
    sim = Simulator(m, engine=engine)
    sim.add_clock(1e-6)
    sim.add_sync_process(process)
    with sim.write_vcd(f"bug17.{engine}.vcd", traces=[s, t]):
        sim.run()
```

On PySim, both `s` and `t` are placed under the `top`module.
On CXXSim, `t` is at the root.

The generated GTKWave document (if any) correctly display the trace, but an already existing manually-generated document would need modification, which is inconvenient.

Pull request description:
sim.pysim: use "bench" as a top level root for testbench signals.
Fixes #561.

Patch:
diff --git a/amaranth/sim/pysim.py b/amaranth/sim/pysim.py
index a295d56..504361d 100644
--- a/amaranth/sim/pysim.py
+++ b/amaranth/sim/pysim.py
@@ -19,7 +19,7 @@ class _NameExtractor:
     def __init__(self):
         self.names = SignalDict()
 
-    def __call__(self, fragment, *, hierarchy=("top",)):
+    def __call__(self, fragment, *, hierarchy=("bench", "top",)):
         def add_signal_name(signal):
             hierarchical_signal_name = (*hierarchy, signal.name)
             if signal not in self.names:
@@ -74,7 +74,7 @@ class _VCDWriter:
         trace_names = SignalDict()
         for trace in traces:
             if trace not in signal_names:
-                trace_names[trace] = {("top", trace.name)}
+                trace_names[trace] = {('bench', trace.name)}
             self.traces.append(trace)
 
         if self.vcd_writer is None:
diff --git a/docs/changes.rst b/docs/changes.rst
index 1e2745d..84ba53b 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -74,6 +74,7 @@ Toolchain changes
 * Added: :meth:`build.BuildPlan.execute_remote_ssh`.
 * Deprecated: :class:`test.utils.FHDLTestCase`, with no replacement.
 * Deprecated: :func:`back.rtlil.convert()` and :func:`back.verilog.convert()` without an explicit `ports=` argument.
+* Changed: VCD output now uses a top-level "bench" module that contains testbench only signals.
 
 
 Platform integration changes


Test patch:
diff --git a/tests/test_sim.py b/tests/test_sim.py
index c12b087..e8ffa5d 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -849,7 +849,7 @@ class SimulatorRegressionTestCase(FHDLTestCase):
                 pass
         sim = Simulator(dut)
         with self.assertRaisesRegex(NameError,
-                r"^Signal 'top\.name with space_state' contains a whitespace character$"):
+                r"^Signal 'bench\.top\.name with space_state' contains a whitespace character$"):
             with open(os.path.devnull, "w") as f:
                 with sim.write_vcd(f):
                     sim.run()