add maskable in/out cancellable test
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 3 Aug 2019 05:17:26 +0000 (06:17 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 3 Aug 2019 05:17:26 +0000 (06:17 +0100)
src/nmutil/multipipe.py
src/nmutil/test/test_inout_unary_mux_cancel_pipe.py

index 3fc58e797090a4b2c730a197ea7ae642db1ed661..6c858cd82af2980ea6ac5e8d11ed356111d70ee3 100644 (file)
@@ -26,7 +26,7 @@ from .iocontrol import NextControl, PrevControl
 class MultiInControlBase(Elaboratable):
     """ Common functions for Pipeline API
     """
-    def __init__(self, in_multi=None, p_len=1):
+    def __init__(self, in_multi=None, p_len=1, maskmode=False):
         """ Multi-input Control class.  Conforms to same API as ControlBase...
             mostly.  has additional indices to the *multiple* input stages
 
@@ -38,11 +38,13 @@ class MultiInControlBase(Elaboratable):
             * add data_o member  to NextControl
         """
         # set up input and output IO ACK (prev/next ready/valid)
+        maskwid = p_len if maskmode else 0
+        print ("multi_in", maskwid, maskmode, p_len)
         p = []
         for i in range(p_len):
-            p.append(PrevControl(in_multi))
+            p.append(PrevControl(in_multi, maskwid=maskwid))
         self.p = Array(p)
-        self.n = NextControl()
+        self.n = NextControl(maskwid=maskwid)
 
     def connect_to_next(self, nxt, p_idx=0):
         """ helper function to connect to the next stage data/valid/ready.
@@ -89,7 +91,7 @@ class MultiInControlBase(Elaboratable):
 class MultiOutControlBase(Elaboratable):
     """ Common functions for Pipeline API
     """
-    def __init__(self, n_len=1, in_multi=None):
+    def __init__(self, n_len=1, in_multi=None, maskmode=False):
         """ Multi-output Control class.  Conforms to same API as ControlBase...
             mostly.  has additional indices to the multiple *output* stages
             [MultiInControlBase has multiple *input* stages]
@@ -103,10 +105,11 @@ class MultiOutControlBase(Elaboratable):
         """
 
         # set up input and output IO ACK (prev/next ready/valid)
-        self.p = PrevControl(in_multi)
+        maskwid = n_len if maskmode else 0
+        self.p = PrevControl(in_multi, maskwid=maskwid)
         n = []
         for i in range(n_len):
-            n.append(NextControl())
+            n.append(NextControl(maskwid=maskwid))
         self.n = Array(n)
 
     def connect_to_next(self, nxt, n_idx=0):
@@ -158,9 +161,10 @@ class CombMultiOutPipeline(MultiOutControlBase):
         n.data_o : stage output data array.       shaped according to ospec
     """
 
-    def __init__(self, stage, n_len, n_mux):
-        MultiOutControlBase.__init__(self, n_len=n_len)
+    def __init__(self, stage, n_len, n_mux, maskmode=False):
+        MultiOutControlBase.__init__(self, n_len=n_len, maskmode=maskmode)
         self.stage = stage
+        self.maskmode = maskmode
         self.n_mux = n_mux
 
         # set up the input and output data
@@ -205,6 +209,8 @@ class CombMultiOutPipeline(MultiOutControlBase):
         m.d.comb += data_valid.eq(p_valid_i | \
                                     (~self.n[muxid].ready_i & data_valid))
         with m.If(pv):
+            if self.maskmode:
+                m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i)
             m.d.comb += eq(r_data, self.p.data_i)
         m.d.comb += eq(self.n[muxid].data_o, self.process(r_data))
 
@@ -226,9 +232,10 @@ class CombMultiInPipeline(MultiInControlBase):
             SYNCHRONOUSLY.
     """
 
-    def __init__(self, stage, p_len, p_mux):
-        MultiInControlBase.__init__(self, p_len=p_len)
+    def __init__(self, stage, p_len, p_mux, maskmode=False):
+        MultiInControlBase.__init__(self, p_len=p_len, maskmode=maskmode)
         self.stage = stage
+        self.maskmode = maskmode
         self.p_mux = p_mux
 
         # set up the input and output data
@@ -293,6 +300,8 @@ class CombMultiInPipeline(MultiInControlBase):
             m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o)
             with m.If(vr):
                 m.d.comb += eq(r_data[i], self.p[i].data_i)
+                if self.maskmode:
+                    m.d.comb += self.n.mask_o.eq(self.p[i].mask_i)
 
         m.d.comb += eq(self.n.data_o, self.process(r_data[mid]))
 
@@ -300,9 +309,10 @@ class CombMultiInPipeline(MultiInControlBase):
 
 
 class CombMuxOutPipe(CombMultiOutPipeline):
-    def __init__(self, stage, n_len):
+    def __init__(self, stage, n_len, maskmode=False):
         # HACK: stage is also the n-way multiplexer
-        CombMultiOutPipeline.__init__(self, stage, n_len=n_len, n_mux=stage)
+        CombMultiOutPipeline.__init__(self, stage, n_len=n_len,
+                                            n_mux=stage, maskmode=maskmode)
 
         # HACK: n-mux is also the stage... so set the muxid equal to input muxid
         print ("combmuxout", self.p.data_i.muxid)
@@ -349,9 +359,10 @@ class PriorityCombMuxInPipe(CombMultiInPipeline):
     """ an example of how to use the combinatorial pipeline.
     """
 
-    def __init__(self, stage, p_len=2):
+    def __init__(self, stage, p_len=2, maskmode=False):
         p_mux = InputPriorityArbiter(self, p_len)
-        CombMultiInPipeline.__init__(self, stage, p_len, p_mux)
+        CombMultiInPipeline.__init__(self, stage, p_len, p_mux,
+                                     maskmode=maskmode)
 
 
 if __name__ == '__main__':
index 03fddde0f7ab12ec9023fc57b913442ba42c120a..bde4fe986a4c5b1ac4da6315032370b451cbb157 100644 (file)
@@ -1,5 +1,6 @@
 """ key strategic example showing how to do multi-input fan-in into a
-    multi-stage pipeline, then multi-output fanout.
+    multi-stage pipeline, then multi-output fanout, with an unary muxid
+    and cancellation
 
     the multiplex ID from the fan-in is passed in to the pipeline, preserved,
     and used as a routing ID on the fanout.
@@ -13,7 +14,7 @@ from nmigen.cli import verilog, rtlil
 
 from nmutil.multipipe import CombMultiOutPipeline, CombMuxOutPipe
 from nmutil.multipipe import PriorityCombMuxInPipe
-from nmutil.singlepipe import SimpleHandshake, RecordObject, Object
+from nmutil.singlepipe import MaskCancellable, RecordObject, Object
 
 
 class PassData2(RecordObject):
@@ -44,9 +45,10 @@ class PassThroughStage:
 
 
 
-class PassThroughPipe(SimpleHandshake):
-    def __init__(self):
-        SimpleHandshake.__init__(self, PassThroughStage())
+class PassThroughPipe(MaskCancellable):
+    def __init__(self, maskwid, cancelmask):
+        self.cancelmask = cancelmask
+        MaskCancellable.__init__(self, PassThroughStage(), maskwid)
 
 
 class InputTest:
@@ -54,7 +56,7 @@ class InputTest:
         self.dut = dut
         self.di = {}
         self.do = {}
-        self.tlen = 100
+        self.tlen = 10
         for muxid in range(dut.num_rows):
             self.di[muxid] = {}
             self.do[muxid] = {}
@@ -70,6 +72,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.mask_i.eq(1<<muxid)
             yield
             o_p_ready = yield rs.ready_o
             while not o_p_ready:
@@ -134,10 +137,12 @@ class InputTest:
 
 
 class TestPriorityMuxPipe(PriorityCombMuxInPipe):
-    def __init__(self, num_rows):
+    def __init__(self, num_rows, cancelmask):
         self.num_rows = num_rows
+        self.cancelmask = cancelmask
         stage = PassThroughStage()
-        PriorityCombMuxInPipe.__init__(self, stage, p_len=self.num_rows)
+        PriorityCombMuxInPipe.__init__(self, stage,
+                                       p_len=self.num_rows, maskmode=True)
 
 
 class OutputTest:
@@ -145,7 +150,7 @@ class OutputTest:
         self.dut = dut
         self.di = []
         self.do = {}
-        self.tlen = 100
+        self.tlen = 10
         for i in range(self.tlen * dut.num_rows):
             if i < dut.num_rows:
                 muxid = i
@@ -178,19 +183,22 @@ class OutputTest:
 
 
 class TestMuxOutPipe(CombMuxOutPipe):
-    def __init__(self, num_rows):
+    def __init__(self, num_rows, cancelmask):
         self.num_rows = num_rows
+        self.cancelmask = cancelmask
         stage = PassThroughStage()
-        CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows)
+        CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows,
+                                maskmode=True)
 
 
 class TestInOutPipe(Elaboratable):
     def __init__(self, num_rows=4):
-        self.num_rows = num_rows
-        self.inpipe = TestPriorityMuxPipe(num_rows) # fan-in (combinatorial)
-        self.pipe1 = PassThroughPipe()              # stage 1 (clock-sync)
-        self.pipe2 = PassThroughPipe()              # stage 2 (clock-sync)
-        self.outpipe = TestMuxOutPipe(num_rows)     # fan-out (combinatorial)
+        self.num_rows = nr = num_rows
+        self.cancelmask = cm = Signal(nr)         # cancellation mask
+        self.inpipe = TestPriorityMuxPipe(nr, cm) # fan-in (combinatorial)
+        self.pipe1 = PassThroughPipe(nr, cm)      # stage 1 (clock-sync)
+        self.pipe2 = PassThroughPipe(nr, cm)      # stage 2 (clock-sync)
+        self.outpipe = TestMuxOutPipe(nr, cm)     # fan-out (combinatorial)
 
         self.p = self.inpipe.p  # kinda annoying,
         self.n = self.outpipe.n # use pipe in/out as this class in/out