From 6d417568ad68565fc7e01e7611ce8cf0b8fdb603 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 8 Jul 2020 08:29:20 +0000 Subject: [PATCH] back.pysim: only extract signal names if VCD is requested. This commit also fixes an issue introduced in 2606ee33 that regressed simulator startup time and bloated VCD files. (It's actually about 10% faster now than *before* the regression was introduced.) --- nmigen/back/pysim.py | 57 +++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/nmigen/back/pysim.py b/nmigen/back/pysim.py index 155a649..7983b94 100644 --- a/nmigen/back/pysim.py +++ b/nmigen/back/pysim.py @@ -18,6 +18,38 @@ from ..sim._cmds import * __all__ = ["Settle", "Delay", "Tick", "Passive", "Active", "Simulator"] +class _NameExtractor: + def __init__(self): + self.names = SignalDict() + + def __call__(self, fragment, *, hierarchy=("top",)): + def add_signal_name(signal): + hierarchical_signal_name = (*hierarchy, signal.name) + if signal not in self.names: + self.names[signal] = {hierarchical_signal_name} + else: + self.names[signal].add(hierarchical_signal_name) + + for domain_name, domain_signals in fragment.drivers.items(): + if domain_name is not None: + domain = fragment.domains[domain_name] + add_signal_name(domain.clk) + if domain.rst is not None: + add_signal_name(domain.rst) + + for statement in fragment.statements: + for signal in statement._lhs_signals() | statement._rhs_signals(): + if not isinstance(signal, (ClockSignal, ResetSignal)): + add_signal_name(signal) + + for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments): + if subfragment_name is None: + subfragment_name = "U${}".format(subfragment_index) + self(subfragment, hierarchy=(*hierarchy, subfragment_name)) + + return self.names + + class _WaveformWriter: def update(self, timestamp, signal, value): raise NotImplementedError # :nocov: @@ -35,7 +67,7 @@ class _VCDWaveformWriter(_WaveformWriter): def decode_to_vcd(signal, value): return signal.decoder(value).expandtabs().replace(" ", "_") - def __init__(self, signal_names, *, vcd_file, gtkw_file=None, traces=()): + def __init__(self, fragment, *, vcd_file, gtkw_file=None, traces=()): if isinstance(vcd_file, str): vcd_file = open(vcd_file, "wt") if isinstance(gtkw_file, str): @@ -52,6 +84,8 @@ class _VCDWaveformWriter(_WaveformWriter): self.traces = [] + signal_names = _NameExtractor()(fragment) + trace_names = SignalDict() for trace in traces: if trace not in signal_names: @@ -630,20 +664,12 @@ class _CompiledProcess(_Process): class _FragmentCompiler: - def __init__(self, state, signal_names): + def __init__(self, state): self.state = state - self.signal_names = signal_names def __call__(self, fragment, *, hierarchy=("top",)): processes = set() - def add_signal_name(signal): - hierarchical_signal_name = (*hierarchy, signal.name) - if signal not in self.signal_names: - self.signal_names[signal] = {hierarchical_signal_name} - else: - self.signal_names[signal].add(hierarchical_signal_name) - for domain_name, domain_signals in fragment.drivers.items(): domain_stmts = LHSGroupFilter(domain_signals)(fragment.statements) domain_process = _CompiledProcess(self.state, comb=domain_name is None) @@ -665,10 +691,6 @@ class _FragmentCompiler: else: domain = fragment.domains[domain_name] - add_signal_name(domain.clk) - if domain.rst is not None: - add_signal_name(domain.rst) - clk_trigger = 1 if domain.clk_edge == "pos" else 0 self.state.add_trigger(domain_process, domain.clk, trigger=clk_trigger) if domain.rst is not None and domain.async_reset: @@ -710,9 +732,6 @@ class _FragmentCompiler: processes.add(domain_process) - for used_signal in domain_process.state.signals: - add_signal_name(used_signal) - for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments): if subfragment_name is None: subfragment_name = "U${}".format(subfragment_index) @@ -830,7 +849,7 @@ class Simulator: self._state = _SimulatorState() self._signal_names = SignalDict() self._fragment = Fragment.get(fragment, platform=None).prepare() - self._processes = _FragmentCompiler(self._state, self._signal_names)(self._fragment) + self._processes = _FragmentCompiler(self._state)(self._fragment) self._clocked = set() self._waveform_writers = [] @@ -1013,7 +1032,7 @@ class Simulator: """ if self._state.timeline.now != 0.0: raise ValueError("Cannot start writing waveforms after advancing simulation time") - waveform_writer = _VCDWaveformWriter(self._signal_names, + waveform_writer = _VCDWaveformWriter(self._fragment, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces) self._waveform_writers.append(waveform_writer) yield -- 2.30.2