wishbone: fix that RoundRobin might assert CYC indefinitely
authorHarry Ho <hh@m-labs.hk>
Wed, 29 Jan 2020 04:14:11 +0000 (12:14 +0800)
committerHarry Ho <hh@m-labs.hk>
Wed, 29 Jan 2020 07:13:26 +0000 (15:13 +0800)
nmigen_soc/scheduler.py
nmigen_soc/wishbone/bus.py

index 61b3d169d3b3a154a30cae482ad733a32813bc2a..7af3b107f4dd12347798f4769e5a866f11507665 100644 (file)
@@ -18,22 +18,28 @@ class RoundRobin(Elaboratable):
         Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
     grant : Signal(range(n))
         Signal that equals to the index of the device which is currently granted access.
+    stb : Signal()
+        Strobe signal to enable granting access to the next device requesting. Externally driven.
     """
     def __init__(self, n):
         self.n = n
         self.request = Signal(n)
         self.grant = Signal(range(n))
+        self.stb = Signal()
 
     def elaborate(self, platform):
         m = Module()
 
-        with m.Switch(self.grant):
-            for i in range(self.n):
-                with m.Case(i):
-                    with m.If(~self.request[i]):
-                        for j in reversed(range(i+1, i+self.n)):
-                            t = j % self.n
-                            with m.If(self.request[t]):
-                                m.d.sync += self.grant.eq(t)
+        with m.If(self.stb):
+            with m.Switch(self.grant):
+                for i in range(self.n):
+                    with m.Case(i):
+                        with m.If(~self.request[i]):
+                            for j in reversed(range(i+1, i+self.n)):
+                                # If i+1 <= j < n, then t == j;     (after i)
+                                # If n <= j < i+n, then t == j - n  (before i)
+                                t = j % self.n
+                                with m.If(self.request[t]):
+                                    m.d.sync += self.grant.eq(t)
 
         return m
\ No newline at end of file
index 142b099f4989459fe71fdf5c8205ec1b47febeb4..7956b249798b30b2150122710c6049853c29cb58 100644 (file)
@@ -366,13 +366,17 @@ class Arbiter(Elaboratable):
         if self._scheduler == "rr":
             m.submodules.scheduler = scheduler = RoundRobin(self._next_index)
         grant = Signal(self._next_index)
-        m.d.comb += grant.eq(scheduler.grant)
+        m.d.comb += [
+            # CYC should not be indefinitely asserted. (See RECOMMENDATION 3.05, Wishbone B4)
+            scheduler.stb.eq(~self.bus.cyc),
+            grant.eq(scheduler.grant)
+        ]
 
         for signal_name, (_, signal_direction) in self.bus.layout.fields.items():
             # FANOUT signals: only mux the granted master with the interface
             if signal_direction == Direction.FANOUT:
-                master_signals = Array(getattr(master_bus, signal_name) 
-                                       for __, (___, master_bus) 
+                master_signals = Array(getattr(master_bus, signal_name)
+                                       for __, (___, master_bus)
                                        in self._masters.items())
                 m.d.comb += getattr(self.bus, signal_name).eq(master_signals[grant])
             # FANIN signals: ACK and ERR are ORed to all masters;
@@ -422,7 +426,7 @@ class InterconnectShared(Elaboratable):
 
         for target_bus in targets:
             self._targets.append(target_bus)
-        
+
         self.arbiter = Arbiter(
             addr_width=self.addr_width,
             data_width=self.data_width,
@@ -461,4 +465,4 @@ class InterconnectShared(Elaboratable):
             self.arbiter.bus.connect(self.decoder.bus)
         )
 
-        return m
\ No newline at end of file
+        return m