--- /dev/null
+import inspect
+
+from ._core import Process
+
+
+__all__ = ["PyClockProcess"]
+
+
+class PyClockProcess(Process):
+ def __init__(self, state, signal, *, phase, period):
+ assert len(signal) == 1
+
+ self.state = state
+ self.slot = self.state.get_signal(signal)
+ self.phase = phase
+ self.period = period
+
+ self.reset()
+
+ def reset(self):
+ self.runnable = True
+ self.passive = True
+ self.initial = True
+
+ def run(self):
+ if self.initial:
+ self.initial = False
+ self.state.timeline.delay(self.phase, self)
+
+ else:
+ clk_state = self.state.slots[self.slot]
+ clk_state.set(not clk_state.curr)
+ self.state.timeline.delay(self.period / 2, self)
+
+ self.runnable = False
from ._core import *
from ._pyrtl import _FragmentCompiler
from ._pycoro import PyCoroProcess
+from ._pyclock import PyClockProcess
__all__ = ["Settle", "Delay", "Tick", "Passive", "Active", "Simulator"]
raise ValueError("Domain {!r} already has a clock driving it"
.format(domain.name))
- half_period = period / 2
if phase is None:
# By default, delay the first edge by half period. This causes any synchronous activity
# to happen at a non-zero time, distinguishing it from the reset values in the waveform
# viewer.
- phase = half_period
- def clk_process():
- yield Passive()
- yield Delay(phase)
- # Behave correctly if the process is added after the clock signal is manipulated, or if
- # its reset state is high.
- initial = (yield domain.clk)
- steps = (
- domain.clk.eq(~initial),
- Delay(half_period),
- domain.clk.eq(initial),
- Delay(half_period),
- )
- while True:
- yield from iter(steps)
- self._add_coroutine_process(clk_process, default_cmd=None)
+ phase = period / 2
+ self._processes.add(PyClockProcess(self._state, domain.clk, phase=phase, period=period))
self._clocked.add(domain)
def reset(self):