back.pysim: extract timeline handling to class _Timeline. NFC.
This commit is contained in:
parent
d3d210eaee
commit
94faf497ba
|
@ -138,6 +138,54 @@ class _Process:
|
||||||
raise NotImplementedError # :nocov:
|
raise NotImplementedError # :nocov:
|
||||||
|
|
||||||
|
|
||||||
|
class _Timeline:
|
||||||
|
def __init__(self):
|
||||||
|
self.now = 0.0
|
||||||
|
self.deadlines = dict()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.now = 0.0
|
||||||
|
self.deadlines.clear()
|
||||||
|
|
||||||
|
def at(self, run_at, process):
|
||||||
|
assert process not in self.deadlines
|
||||||
|
self.deadlines[process] = run_at
|
||||||
|
|
||||||
|
def delay(self, delay_by, process):
|
||||||
|
if delay_by is None:
|
||||||
|
run_at = self.now
|
||||||
|
else:
|
||||||
|
run_at = self.now + delay_by
|
||||||
|
self.at(run_at, process)
|
||||||
|
|
||||||
|
def advance(self):
|
||||||
|
nearest_processes = set()
|
||||||
|
nearest_deadline = None
|
||||||
|
for process, deadline in self.deadlines.items():
|
||||||
|
if deadline is None:
|
||||||
|
if nearest_deadline is not None:
|
||||||
|
nearest_processes.clear()
|
||||||
|
nearest_processes.add(process)
|
||||||
|
nearest_deadline = self.now
|
||||||
|
break
|
||||||
|
elif nearest_deadline is None or deadline <= nearest_deadline:
|
||||||
|
assert deadline >= self.now
|
||||||
|
if nearest_deadline is not None and deadline < nearest_deadline:
|
||||||
|
nearest_processes.clear()
|
||||||
|
nearest_processes.add(process)
|
||||||
|
nearest_deadline = deadline
|
||||||
|
|
||||||
|
if not nearest_processes:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for process in nearest_processes:
|
||||||
|
process.runnable = True
|
||||||
|
del self.deadlines[process]
|
||||||
|
self.now = nearest_deadline
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class _SignalState:
|
class _SignalState:
|
||||||
__slots__ = ("signal", "curr", "next", "waiters", "pending")
|
__slots__ = ("signal", "curr", "next", "waiters", "pending")
|
||||||
|
|
||||||
|
@ -167,21 +215,16 @@ class _SignalState:
|
||||||
|
|
||||||
class _SimulatorState:
|
class _SimulatorState:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.signals = SignalDict()
|
self.timeline = _Timeline()
|
||||||
self.slots = []
|
self.signals = SignalDict()
|
||||||
self.pending = set()
|
self.slots = []
|
||||||
|
self.pending = set()
|
||||||
self.timestamp = 0.0
|
|
||||||
self.deadlines = dict()
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
for signal, index in self.signals.items():
|
for signal, index in self.signals.items():
|
||||||
self.slots[index].curr = self.slots[index].next = signal.reset
|
self.slots[index].curr = self.slots[index].next = signal.reset
|
||||||
self.pending.clear()
|
self.pending.clear()
|
||||||
|
|
||||||
self.timestamp = 0.0
|
|
||||||
self.deadlines.clear()
|
|
||||||
|
|
||||||
def get_signal(self, signal):
|
def get_signal(self, signal):
|
||||||
try:
|
try:
|
||||||
return self.signals[signal]
|
return self.signals[signal]
|
||||||
|
@ -210,33 +253,6 @@ class _SimulatorState:
|
||||||
self.pending.clear()
|
self.pending.clear()
|
||||||
return converged
|
return converged
|
||||||
|
|
||||||
def advance(self):
|
|
||||||
nearest_processes = set()
|
|
||||||
nearest_deadline = None
|
|
||||||
for process, deadline in self.deadlines.items():
|
|
||||||
if deadline is None:
|
|
||||||
if nearest_deadline is not None:
|
|
||||||
nearest_processes.clear()
|
|
||||||
nearest_processes.add(process)
|
|
||||||
nearest_deadline = self.timestamp
|
|
||||||
break
|
|
||||||
elif nearest_deadline is None or deadline <= nearest_deadline:
|
|
||||||
assert deadline >= self.timestamp
|
|
||||||
if nearest_deadline is not None and deadline < nearest_deadline:
|
|
||||||
nearest_processes.clear()
|
|
||||||
nearest_processes.add(process)
|
|
||||||
nearest_deadline = deadline
|
|
||||||
|
|
||||||
if not nearest_processes:
|
|
||||||
return False
|
|
||||||
|
|
||||||
for process in nearest_processes:
|
|
||||||
process.runnable = True
|
|
||||||
del self.deadlines[process]
|
|
||||||
self.timestamp = nearest_deadline
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class _Emitter:
|
class _Emitter:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -783,14 +799,11 @@ class _CoroutineProcess(_Process):
|
||||||
return
|
return
|
||||||
|
|
||||||
elif type(command) is Settle:
|
elif type(command) is Settle:
|
||||||
self.state.deadlines[self] = None
|
self.state.timeline.delay(None, self)
|
||||||
return
|
return
|
||||||
|
|
||||||
elif type(command) is Delay:
|
elif type(command) is Delay:
|
||||||
if command.interval is None:
|
self.state.timeline.delay(command.interval, self)
|
||||||
self.state.deadlines[self] = None
|
|
||||||
else:
|
|
||||||
self.state.deadlines[self] = self.state.timestamp + command.interval
|
|
||||||
return
|
return
|
||||||
|
|
||||||
elif type(command) is Passive:
|
elif type(command) is Passive:
|
||||||
|
@ -937,7 +950,7 @@ class Simulator:
|
||||||
|
|
||||||
for waveform_writer in self._waveform_writers:
|
for waveform_writer in self._waveform_writers:
|
||||||
for signal_state in self._state.pending:
|
for signal_state in self._state.pending:
|
||||||
waveform_writer.update(self._state.timestamp,
|
waveform_writer.update(self._state.timeline.now,
|
||||||
signal_state.signal, signal_state.curr)
|
signal_state.signal, signal_state.curr)
|
||||||
|
|
||||||
# 2. commit: apply every queued signal change, waking up any waiting processes
|
# 2. commit: apply every queued signal change, waking up any waiting processes
|
||||||
|
@ -958,7 +971,7 @@ class Simulator:
|
||||||
Returns ``True`` if there are any active processes, ``False`` otherwise.
|
Returns ``True`` if there are any active processes, ``False`` otherwise.
|
||||||
"""
|
"""
|
||||||
self._real_step()
|
self._real_step()
|
||||||
self._state.advance()
|
self._state.timeline.advance()
|
||||||
return any(not process.passive for process in self._processes)
|
return any(not process.passive for process in self._processes)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -980,8 +993,8 @@ class Simulator:
|
||||||
|
|
||||||
If the simulation stops advancing, this function will never return.
|
If the simulation stops advancing, this function will never return.
|
||||||
"""
|
"""
|
||||||
assert self._state.timestamp <= deadline
|
assert self._state.timeline.now <= deadline
|
||||||
while (self.advance() or run_passive) and self._state.timestamp < deadline:
|
while (self.advance() or run_passive) and self._state.timeline.now < deadline:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
|
@ -1004,11 +1017,11 @@ class Simulator:
|
||||||
traces : iterable of Signal
|
traces : iterable of Signal
|
||||||
Signals to display traces for.
|
Signals to display traces for.
|
||||||
"""
|
"""
|
||||||
if self._state.timestamp != 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._signal_names,
|
||||||
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
|
||||||
waveform_writer.close(self._state.timestamp)
|
waveform_writer.close(self._state.timeline.now)
|
||||||
self._waveform_writers.remove(waveform_writer)
|
self._waveform_writers.remove(waveform_writer)
|
||||||
|
|
Loading…
Reference in a new issue