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.)
This commit is contained in:
parent
3c3cfd48fb
commit
6d417568ad
|
@ -18,6 +18,38 @@ from ..sim._cmds import *
|
||||||
__all__ = ["Settle", "Delay", "Tick", "Passive", "Active", "Simulator"]
|
__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:
|
class _WaveformWriter:
|
||||||
def update(self, timestamp, signal, value):
|
def update(self, timestamp, signal, value):
|
||||||
raise NotImplementedError # :nocov:
|
raise NotImplementedError # :nocov:
|
||||||
|
@ -35,7 +67,7 @@ class _VCDWaveformWriter(_WaveformWriter):
|
||||||
def decode_to_vcd(signal, value):
|
def decode_to_vcd(signal, value):
|
||||||
return signal.decoder(value).expandtabs().replace(" ", "_")
|
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):
|
if isinstance(vcd_file, str):
|
||||||
vcd_file = open(vcd_file, "wt")
|
vcd_file = open(vcd_file, "wt")
|
||||||
if isinstance(gtkw_file, str):
|
if isinstance(gtkw_file, str):
|
||||||
|
@ -52,6 +84,8 @@ class _VCDWaveformWriter(_WaveformWriter):
|
||||||
|
|
||||||
self.traces = []
|
self.traces = []
|
||||||
|
|
||||||
|
signal_names = _NameExtractor()(fragment)
|
||||||
|
|
||||||
trace_names = SignalDict()
|
trace_names = SignalDict()
|
||||||
for trace in traces:
|
for trace in traces:
|
||||||
if trace not in signal_names:
|
if trace not in signal_names:
|
||||||
|
@ -630,20 +664,12 @@ class _CompiledProcess(_Process):
|
||||||
|
|
||||||
|
|
||||||
class _FragmentCompiler:
|
class _FragmentCompiler:
|
||||||
def __init__(self, state, signal_names):
|
def __init__(self, state):
|
||||||
self.state = state
|
self.state = state
|
||||||
self.signal_names = signal_names
|
|
||||||
|
|
||||||
def __call__(self, fragment, *, hierarchy=("top",)):
|
def __call__(self, fragment, *, hierarchy=("top",)):
|
||||||
processes = set()
|
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():
|
for domain_name, domain_signals in fragment.drivers.items():
|
||||||
domain_stmts = LHSGroupFilter(domain_signals)(fragment.statements)
|
domain_stmts = LHSGroupFilter(domain_signals)(fragment.statements)
|
||||||
domain_process = _CompiledProcess(self.state, comb=domain_name is None)
|
domain_process = _CompiledProcess(self.state, comb=domain_name is None)
|
||||||
|
@ -665,10 +691,6 @@ class _FragmentCompiler:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
domain = fragment.domains[domain_name]
|
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
|
clk_trigger = 1 if domain.clk_edge == "pos" else 0
|
||||||
self.state.add_trigger(domain_process, domain.clk, trigger=clk_trigger)
|
self.state.add_trigger(domain_process, domain.clk, trigger=clk_trigger)
|
||||||
if domain.rst is not None and domain.async_reset:
|
if domain.rst is not None and domain.async_reset:
|
||||||
|
@ -710,9 +732,6 @@ class _FragmentCompiler:
|
||||||
|
|
||||||
processes.add(domain_process)
|
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):
|
for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments):
|
||||||
if subfragment_name is None:
|
if subfragment_name is None:
|
||||||
subfragment_name = "U${}".format(subfragment_index)
|
subfragment_name = "U${}".format(subfragment_index)
|
||||||
|
@ -830,7 +849,7 @@ class Simulator:
|
||||||
self._state = _SimulatorState()
|
self._state = _SimulatorState()
|
||||||
self._signal_names = SignalDict()
|
self._signal_names = SignalDict()
|
||||||
self._fragment = Fragment.get(fragment, platform=None).prepare()
|
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._clocked = set()
|
||||||
self._waveform_writers = []
|
self._waveform_writers = []
|
||||||
|
|
||||||
|
@ -1013,7 +1032,7 @@ class Simulator:
|
||||||
"""
|
"""
|
||||||
if self._state.timeline.now != 0.0:
|
if self._state.timeline.now != 0.0:
|
||||||
raise ValueError("Cannot start writing waveforms after advancing simulation time")
|
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)
|
vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces)
|
||||||
self._waveform_writers.append(waveform_writer)
|
self._waveform_writers.append(waveform_writer)
|
||||||
yield
|
yield
|
||||||
|
|
Loading…
Reference in a new issue