sim: drive clock signals
authorSebastien Bourdeauducq <sb@m-labs.hk>
Mon, 21 Sep 2015 13:52:13 +0000 (21:52 +0800)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Mon, 21 Sep 2015 13:53:41 +0000 (21:53 +0800)
migen/sim/core.py

index 1514dfd34bc944a417cfa8a32fcc886e93ef8f42..3ee5cae6e65eaeec82fefd70050e529fcbe0165d 100644 (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():