route-back experimentation
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 7 Aug 2019 11:26:13 +0000 (12:26 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 7 Aug 2019 11:26:13 +0000 (12:26 +0100)
src/nmutil/iocontrol.py
src/nmutil/multipipe.py
src/nmutil/test/test_inout_feedback_pipe.py

index 04e4123839a03b8737f92d4a9cd8b2a0cc2dd1e5..2f8c9ccfaf6d5f4df4f5bf4344a057fe09e49cb8 100644 (file)
@@ -298,6 +298,7 @@ class NextControl(Elaboratable):
                 res.append(nxt.stop_i.eq(self.stop_o))
         if do_data:
             res.append(nmoperator.eq(nxt.data_i, self.data_o))
+        print ("connect to next", self, self.maskwid, nxt.data_i, do_data, do_stop)
         return res
 
     def _connect_out(self, nxt, direct=False, fn=None,
index c0cc90992cc58ff2152f653e1f1540009931fe45..a5655c35cc904de1370a0b3e0cec565d6651707e 100644 (file)
@@ -208,27 +208,26 @@ class CombMultiOutPipeline(MultiOutControlBase):
         p_valid_i = Signal(reset_less=True)
         pv = Signal(reset_less=True)
         m.d.comb += p_valid_i.eq(self.p.valid_i_test)
-        m.d.comb += pv.eq(self.p.valid_i & self.p.ready_o)
+        m.d.comb += pv.eq(self.p.valid_i) #& self.n[muxid].ready_i)
 
         # all outputs to next stages first initialised to zero (invalid)
         # the only output "active" is then selected by the muxid
         for i in range(len(self.n)):
             m.d.comb += self.n[i].valid_o.eq(0)
-        data_valid = self.n[muxid].valid_o
-        m.d.comb += self.p.ready_o.eq(~data_valid | self.n[muxid].ready_i)
-        m.d.comb += data_valid.eq(p_valid_i | \
-                                    (~self.n[muxid].ready_i & data_valid))
+        #with m.If(pv):
+        m.d.comb += self.n[muxid].valid_o.eq(pv)
+        m.d.comb += self.p.ready_o.eq(self.n[muxid].ready_i)
 
         # send data on
-        with m.If(pv):
-            m.d.comb += eq(r_data, self.p.data_i)
+        #with m.If(pv):
+        m.d.comb += eq(r_data, self.p.data_i)
         m.d.comb += eq(self.n[muxid].data_o, self.process(r_data))
 
         if self.maskwid:
             if self.routemask: # straight "routing" mode - treat like data
                 m.d.comb += self.n[muxid].stop_o.eq(self.p.stop_i)
-                with m.If(pv):
-                    m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i)
+                #with m.If(pv):
+                m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i)
             else:
                 ml = [] # accumulate output masks
                 ms = [] # accumulate output stops
@@ -295,6 +294,7 @@ class CombMultiInPipeline(MultiInControlBase):
             p_valid_i.append(Signal(name="p_valid_i", reset_less=True))
             n_ready_in.append(Signal(name="n_ready_in", reset_less=True))
             if hasattr(self.stage, "setup"):
+                print ("setup", self, self.stage, r)
                 self.stage.setup(m, r)
         if len(r_data) > 1:
             r_data = Array(r_data)
@@ -305,6 +305,7 @@ class CombMultiInPipeline(MultiInControlBase):
         nirn = Signal(reset_less=True)
         m.d.comb += nirn.eq(~self.n.ready_i)
         mid = self.p_mux.m_id
+        print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len)
         for i in range(p_len):
             m.d.comb += data_valid[i].eq(0)
             m.d.comb += n_ready_in[i].eq(1)
@@ -323,19 +324,26 @@ class CombMultiInPipeline(MultiInControlBase):
                                     (n_ready_in[mid] & data_valid[mid]))
 
         if self.routemask:
-            m.d.comb += eq(self.n.stop_o, self.p[mid].stop_i)
             for i in range(p_len):
-                m.d.comb += eq(self.n.stop_o, self.p[i].stop_i)
+                p = self.p[i]
                 vr = Signal(reset_less=True)
-                m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o)
+                maskedout = Signal(reset_less=True)
+                m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i)
+                m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o)
                 with m.If(vr):
-                    m.d.comb += eq(self.n.mask_o, self.p[mid].mask_i)
+                    m.d.comb += eq(self.n.mask_o, self.p[i].mask_i)
+                    m.d.comb += eq(r_data[i], self.p[i].data_i)
+                    m.d.comb += eq(self.n.stop_o, self.p[i].stop_i)
         else:
             ml = [] # accumulate output masks
             ms = [] # accumulate output stops
             for i in range(p_len):
                 vr = Signal(reset_less=True)
-                m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o)
+                p = self.p[i]
+                vr = Signal(reset_less=True)
+                maskedout = Signal(reset_less=True)
+                m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i)
+                m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o)
                 with m.If(vr):
                     m.d.comb += eq(r_data[i], self.p[i].data_i)
                 if self.maskwid:
@@ -391,7 +399,13 @@ class InputPriorityArbiter(Elaboratable):
         in_ready = []
         for i in range(self.num_rows):
             p_valid_i = Signal(reset_less=True)
-            m.d.comb += p_valid_i.eq(self.pipe.p[i].valid_i_test)
+            if self.pipe.maskwid and not self.pipe.routemask:
+                p = self.pipe.p[i]
+                maskedout = Signal(reset_less=True)
+                m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i)
+                m.d.comb += p_valid_i.eq(maskedout.bool() & p.valid_i_test)
+            else:
+                m.d.comb += p_valid_i.eq(self.pipe.p[i].valid_i_test)
             in_ready.append(p_valid_i)
         m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids"
         m.d.comb += self.active.eq(~pe.n)   # encoder active (one input valid)
index 31d051e0aab3900e98bd1462b0eb977abc2dd14a..aea582dd69d39121d5f60c8fdf167dcbe6a21dc6 100644 (file)
@@ -8,7 +8,7 @@
 
 from random import randint
 from math import log
-from nmigen import Module, Signal, Cat, Value, Elaboratable
+from nmigen import Module, Signal, Cat, Value, Elaboratable, Const
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
 
@@ -34,7 +34,7 @@ class PassThroughStage:
         return PassData()
     def ospec(self):
         return self.ispec() # same as ospec
-    def setup(self, m, i):
+    def _setup(self, m, i):
         comb = m.d.comb
         #comb += self.o.eq(i)
     def process(self, i):
@@ -48,15 +48,15 @@ class SplitRouteStage:
     def ispec(self):
         return PassData()
     def ospec(self):
-        return self.ispec() # same as ospec
+        return PassData()
 
     def setup(self, m, i):
         comb = m.d.comb
         comb += self.o.eq(i)
-        with m.If(i.operator == 0):
-            #comb += self.o.routeid.eq(1) # selects 2nd output in CombMuxOutPipe
+        with m.If(i.operator == Const(1, 2)):
+            comb += self.o.routeid.eq(1) # selects 2nd output in CombMuxOutPipe
             comb += self.o.data.eq(i.data + 1) # add 1 to say "we did it"
-            comb += self.o.operator.eq(1) # don't get into infinite loop
+            comb += self.o.operator.eq(2) # don't get into infinite loop
         with m.Else():
             comb += self.o.routeid.eq(0) # selects 2nd output in CombMuxOutPipe
 
@@ -64,12 +64,16 @@ class SplitRouteStage:
         return self.o
 
 
+class DecisionPipe(MaskCancellable):
+    def __init__(self, maskwid):
+        stage = SplitRouteStage()
+        MaskCancellable.__init__(self, stage, maskwid)
+
 class RouteBackPipe(CombMuxOutPipe):
     """ routes data back to start of pipeline
     """
     def __init__(self):
-        self.num_rows = 2
-        stage = SplitRouteStage()
+        stage = PassThroughStage()
         CombMuxOutPipe.__init__(self, stage, n_len=2,
                                 maskwid=4, muxidname="routeid",
                                 routemask=True)
@@ -79,7 +83,6 @@ class MergeRoutePipe(PriorityCombMuxInPipe):
     """ merges data coming from end of pipe (with operator now == 1)
     """
     def __init__(self):
-        self.num_rows = 2
         stage = PassThroughStage()
         PriorityCombMuxInPipe.__init__(self, stage, p_len=2, maskwid=4,
                                         routemask=True)
@@ -114,6 +117,7 @@ class InputTest:
             yield rs.data_i.data.eq(op2)
             yield rs.data_i.idx.eq(i)
             yield rs.data_i.muxid.eq(muxid)
+            yield rs.data_i.operator.eq(1)
             yield rs.mask_i.eq(1)
             yield
             o_p_ready = yield rs.ready_o
@@ -164,11 +168,11 @@ class InputTest:
                 if len(self.do[muxid]) == 0:
                     break
 
-            stall_range = randint(0, 3)
-            for j in range(randint(1,10)):
-                stall = randint(0, stall_range) != 0
-                yield self.dut.n[0].ready_i.eq(stall)
-                yield
+            #stall_range = randint(0, 3)
+            #for j in range(randint(1,10)):
+            #    stall = randint(0, stall_range) != 0
+            #    yield self.dut.n[0].ready_i.eq(stall)
+            #    yield
 
             n = self.dut.n[muxid]
             yield n.ready_i.eq(1)
@@ -183,7 +187,7 @@ class InputTest:
             out_i = yield n.data_o.idx
             out_v = yield n.data_o.data
 
-            print ("recv", out_muxid, out_i, hex(out_v), out_v)
+            print ("recv", out_muxid, out_i, hex(out_v), hex(out_v))
 
             # see if this output has occurred already, delete it if it has
             assert muxid == out_muxid, \
@@ -193,7 +197,7 @@ class InputTest:
                 continue
             assert out_i in self.do[muxid], "out_i %d not in array %s" % \
                                           (out_i, repr(self.do[muxid]))
-            assert self.do[muxid][out_i] == out_v + 1 # check data
+            assert self.do[muxid][out_i] + 1 == out_v # check data
             del self.do[muxid][out_i]
             todel = self.sent[muxid].index(out_i)
             del self.sent[muxid][todel]
@@ -227,11 +231,12 @@ class TestInOutPipe(Elaboratable):
         self.inpipe = TestPriorityMuxPipe(nr) # fan-in (combinatorial)
         self.mergein = MergeRoutePipe()       # merge in feedback
         self.pipe1 = PassThroughPipe(nr)      # stage 1 (clock-sync)
-        self.pipe2 = PassThroughPipe(nr)      # stage 2 (clock-sync)
+        self.pipe2 = DecisionPipe(nr)         # stage 2 (clock-sync)
         #self.pipe3 = PassThroughPipe(nr)      # stage 3 (clock-sync)
         #self.pipe4 = PassThroughPipe(nr)      # stage 4 (clock-sync)
         self.splitback = RouteBackPipe()      # split back to mergein
         self.outpipe = TestMuxOutPipe(nr)     # fan-out (combinatorial)
+        self.fifoback = PassThroughPipe(nr)   # temp route-back store
 
         self.p = self.inpipe.p  # kinda annoying,
         self.n = self.outpipe.n # use pipe in/out as this class in/out
@@ -247,14 +252,16 @@ class TestInOutPipe(Elaboratable):
         #m.submodules.pipe4 = self.pipe4
         m.submodules.splitback = self.splitback
         m.submodules.outpipe = self.outpipe
+        m.submodules.fifoback = self.fifoback
 
-        m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[0])
+        m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[1])
         m.d.comb += self.mergein.n.connect_to_next(self.pipe1.p)
         m.d.comb += self.pipe1.connect_to_next(self.pipe2)
         #m.d.comb += self.pipe2.connect_to_next(self.pipe3)
         #m.d.comb += self.pipe3.connect_to_next(self.pipe4)
         m.d.comb += self.pipe2.connect_to_next(self.splitback)
-        m.d.comb += self.splitback.n[1].connect_to_next(self.mergein.p[1])
+        m.d.comb += self.splitback.n[1].connect_to_next(self.fifoback.p)
+        m.d.comb += self.fifoback.n.connect_to_next(self.mergein.p[0])
         m.d.comb += self.splitback.n[0].connect_to_next(self.outpipe.p)
 
         return m
@@ -269,13 +276,13 @@ def test1():
     with open("test_inoutmux_feedback_pipe.il", "w") as f:
         f.write(vl)
 
-    tlen = 20
+    tlen = 3
 
     test = InputTest(dut, tlen)
-    run_simulation(dut, [test.rcv(1), test.rcv(0),
-                         test.rcv(3), test.rcv(2),
+    run_simulation(dut, [test.rcv(0), test.rcv(1),
+                         #test.rcv(3), test.rcv(2),
                          test.send(0), test.send(1),
-                         test.send(3), test.send(2),
+                         #test.send(3), test.send(2),
                         ],
                    vcd_name="test_inoutmux_feedback_pipe.vcd")