sim: drive clock signals

This commit is contained in:
Sebastien Bourdeauducq 2015-09-21 21:52:13 +08:00
parent a67b4baa0c
commit 99af825a5a
1 changed files with 49 additions and 22 deletions

View File

@ -12,30 +12,45 @@ from migen.sim.vcd import VCDWriter, DummyVCDWriter
class ClockState:
def __init__(self, period, times_before_tick):
self.period = period
self.times_before_tick = times_before_tick
def __init__(self, high, half_period, time_before_trans):
self.high = high
self.half_period = half_period
self.time_before_trans = time_before_trans
class TimeManager:
def __init__(self, description):
self.clocks = dict()
for k, v in description.items():
if not isinstance(v, tuple):
v = v, 0
self.clocks[k] = ClockState(v[0], v[0] - v[1])
for k, period_phase in description.items():
if isinstance(period_phase, tuple):
period, phase = period_phase
else:
period = period_phase
phase = 0
half_period = period//2
if phase >= half_period:
phase -= half_period
high = True
else:
high = False
self.clocks[k] = ClockState(high, half_period, half_period - phase)
def tick(self):
r = set()
dt = min(cs.times_before_tick for cs in self.clocks.values())
rising = set()
falling = set()
dt = min(cs.time_before_trans for cs in self.clocks.values())
for k, cs in self.clocks.items():
if cs.times_before_tick == dt:
r.add(k)
cs.times_before_tick -= dt
if not cs.times_before_tick:
cs.times_before_tick += cs.period
return dt, r
if cs.time_before_trans == dt:
cs.high = not cs.high
if cs.high:
rising.add(k)
else:
falling.add(k)
cs.time_before_trans -= dt
if not cs.time_before_trans:
cs.time_before_trans += cs.half_period
return dt, rising, falling
str2op = {
@ -188,23 +203,32 @@ class Simulator:
else:
self.generators[k] = [v]
self.time = TimeManager(clocks)
for clock in clocks.keys():
if clock not in self.fragment.clock_domains:
cd = ClockDomain(name=clock, reset_less=True)
cd.clk.reset = C(self.time.clocks[clock].high)
self.fragment.clock_domains.append(cd)
mta = MemoryToArray()
mta.transform_fragment(None, self.fragment)
# TODO: insert_resets on sync
# comb signals return to their reset value if nothing assigns them
self.fragment.comb[0:0] = [s.eq(s.reset)
for s in list_targets(self.fragment.comb)]
self.evaluator = Evaluator(mta.replacements)
if vcd_name is None:
self.vcd = DummyVCDWriter()
else:
signals = sorted(list_signals(self.fragment),
key=lambda x: x.duid)
signals = list_signals(self.fragment)
for cd in self.fragment.clock_domains:
signals.add(cd.clk)
if cd.rst is not None:
signals.add(cd.rst)
signals = sorted(signals, key=lambda x: x.duid)
self.vcd = VCDWriter(vcd_name, signals)
self.time = TimeManager(clocks)
self.evaluator = Evaluator(mta.replacements)
def __enter__(self):
return self
@ -263,13 +287,16 @@ class Simulator:
self._commit_and_comb_propagate()
while True:
dt, cds = self.time.tick()
dt, rising, falling = self.time.tick()
self.vcd.delay(dt)
for cd in cds:
for cd in rising:
self.evaluator.assign(self.fragment.clock_domains[cd].clk, 1)
if cd in self.fragment.sync:
self.evaluator.execute(self.fragment.sync[cd])
if cd in self.generators:
self._process_generators(cd)
for cd in falling:
self.evaluator.assign(self.fragment.clock_domains[cd].clk, 0)
self._commit_and_comb_propagate()
if not self._continue_simulation():