speed up ==, hash, <, >, <=, and >= for plain_data
[nmutil.git] / src / nmutil / multipipe.py
index 18315e31ec4b01821fc1e743d3b1e6ead1a1bcf8..0b91f8baf565528a10bd9297ba423674289b104b 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: LGPL-3-or-later
 """ Combinatorial Multi-input and Multi-output multiplexer blocks
     conforming to Pipeline API
 
@@ -32,6 +33,7 @@ from nmutil.iocontrol import NextControl, PrevControl
 class MultiInControlBase(Elaboratable):
     """ Common functions for Pipeline API
     """
+
     def __init__(self, in_multi=None, p_len=1, maskwid=0, routemask=False):
         """ Multi-input Control class.  Conforms to same API as ControlBase...
             mostly.  has additional indices to the *multiple* input stages
@@ -40,21 +42,21 @@ class MultiInControlBase(Elaboratable):
             * n: contains ready/valid to the next stage
 
             User must also:
-            * add data_i members to PrevControl and
-            * add data_o member  to NextControl
+            * add i_data members to PrevControl and
+            * add o_data member  to NextControl
         """
         self.routemask = routemask
         # set up input and output IO ACK (prev/next ready/valid)
-        print ("multi_in", self, maskwid, p_len, routemask)
+        print("multi_in", self, maskwid, p_len, routemask)
         p = []
         for i in range(p_len):
             p.append(PrevControl(in_multi, maskwid=maskwid))
         self.p = Array(p)
         if routemask:
-            nmaskwid = maskwid # straight route mask mode
+            nmaskwid = maskwid  # straight route mask mode
         else:
-            nmaskwid = maskwid * p_len # fan-in mode
-        self.n = NextControl(maskwid=nmaskwid) # masks fan in (Cat)
+            nmaskwid = maskwid * p_len  # fan-in mode
+        self.n = NextControl(maskwid=nmaskwid)  # masks fan in (Cat)
 
     def connect_to_next(self, nxt, p_idx=0):
         """ helper function to connect to the next stage data/valid/ready.
@@ -80,7 +82,7 @@ class MultiInControlBase(Elaboratable):
     def set_input(self, i, idx=0):
         """ helper function to set the input data
         """
-        return eq(self.p[idx].data_i, i)
+        return eq(self.p[idx].i_data, i)
 
     def elaborate(self, platform):
         m = Module()
@@ -101,6 +103,7 @@ class MultiInControlBase(Elaboratable):
 class MultiOutControlBase(Elaboratable):
     """ Common functions for Pipeline API
     """
+
     def __init__(self, n_len=1, in_multi=None, maskwid=0, routemask=False):
         """ Multi-output Control class.  Conforms to same API as ControlBase...
             mostly.  has additional indices to the multiple *output* stages
@@ -110,14 +113,14 @@ class MultiOutControlBase(Elaboratable):
             * n: contains ready/valid to the next stages PLURAL
 
             User must also:
-            * add data_i member to PrevControl and
-            * add data_o members to NextControl
+            * add i_data member to PrevControl and
+            * add o_data members to NextControl
         """
 
         if routemask:
-            nmaskwid = maskwid # straight route mask mode
+            nmaskwid = maskwid  # straight route mask mode
         else:
-            nmaskwid = maskwid * n_len # fan-out mode
+            nmaskwid = maskwid * n_len  # fan-out mode
 
         # set up input and output IO ACK (prev/next ready/valid)
         self.p = PrevControl(in_multi, maskwid=nmaskwid)
@@ -155,7 +158,7 @@ class MultiOutControlBase(Elaboratable):
     def set_input(self, i):
         """ helper function to set the input data
         """
-        return eq(self.p.data_i, i)
+        return eq(self.p.i_data, i)
 
     def __iter__(self):
         yield from self.p
@@ -171,23 +174,23 @@ class CombMultiOutPipeline(MultiOutControlBase):
 
         Attributes:
         -----------
-        p.data_i : stage input data (non-array).  shaped according to ispec
-        n.data_o : stage output data array.       shaped according to ospec
+        p.i_data : stage input data (non-array).  shaped according to ispec
+        n.o_data : stage output data array.       shaped according to ospec
     """
 
     def __init__(self, stage, n_len, n_mux, maskwid=0, routemask=False):
         MultiOutControlBase.__init__(self, n_len=n_len, maskwid=maskwid,
-                                            routemask=routemask)
+                                     routemask=routemask)
         self.stage = stage
         self.maskwid = maskwid
         self.routemask = routemask
         self.n_mux = n_mux
 
         # set up the input and output data
-        self.p.data_i = _spec(stage.ispec, 'data_i') # input type
+        self.p.i_data = _spec(stage.ispec, 'i_data')  # input type
         for i in range(n_len):
-            name = 'data_o_%d' % i
-            self.n[i].data_o = _spec(stage.ospec, name) # output type
+            name = 'o_data_%d' % i
+            self.n[i].o_data = _spec(stage.ospec, name)  # output type
 
     def process(self, i):
         if hasattr(self.stage, "process"):
@@ -197,18 +200,18 @@ class CombMultiOutPipeline(MultiOutControlBase):
     def elaborate(self, platform):
         m = MultiOutControlBase.elaborate(self, platform)
 
-        if hasattr(self.n_mux, "elaborate"): # TODO: identify submodule?
+        if hasattr(self.n_mux, "elaborate"):  # TODO: identify submodule?
             m.submodules.n_mux = self.n_mux
 
         # need buffer register conforming to *input* spec
-        r_data = _spec(self.stage.ispec, 'r_data') # input type
+        r_data = _spec(self.stage.ispec, 'r_data')  # input type
         if hasattr(self.stage, "setup"):
             self.stage.setup(m, r_data)
 
         # multiplexer id taken from n_mux
         muxid = self.n_mux.m_id
-        print ("self.n_mux", self.n_mux)
-        print ("self.n_mux.m_id", self.n_mux.m_id)
+        print("self.n_mux", self.n_mux)
+        print("self.n_mux.m_id", self.n_mux.m_id)
 
         self.n_mux.m_id.name = "m_id"
 
@@ -216,7 +219,7 @@ class CombMultiOutPipeline(MultiOutControlBase):
         p_i_valid = Signal(reset_less=True)
         pv = Signal(reset_less=True)
         m.d.comb += p_i_valid.eq(self.p.i_valid_test)
-        #m.d.comb += pv.eq(self.p.i_valid) #& self.n[muxid].i_ready)
+        # m.d.comb += pv.eq(self.p.i_valid) #& self.n[muxid].i_ready)
         m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready)
 
         # all outputs to next stages first initialised to zero (invalid)
@@ -224,29 +227,31 @@ class CombMultiOutPipeline(MultiOutControlBase):
         for i in range(len(self.n)):
             m.d.comb += self.n[i].o_valid.eq(0)
         if self.routemask:
-            #with m.If(pv):
+            # with m.If(pv):
             m.d.comb += self.n[muxid].o_valid.eq(pv)
             m.d.comb += self.p.o_ready.eq(self.n[muxid].i_ready)
         else:
             data_valid = self.n[muxid].o_valid
-            m.d.comb += self.p.o_ready.eq(~data_valid | self.n[muxid].i_ready)
-            m.d.comb += data_valid.eq(p_i_valid | \
-                                    (~self.n[muxid].i_ready & data_valid))
-
+            m.d.comb += self.p.o_ready.eq(self.n[muxid].i_ready)
+            m.d.comb += data_valid.eq(p_i_valid |
+                                      (~self.n[muxid].i_ready & data_valid))
 
         # send data on
-        #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))
+        # with m.If(pv):
+        m.d.comb += eq(r_data, self.p.i_data)
+        #m.d.comb += eq(self.n[muxid].o_data, self.process(r_data))
+        for i in range(len(self.n)):
+            with m.If(muxid == i):
+                m.d.comb += eq(self.n[i].o_data, self.process(r_data))
 
         if self.maskwid:
-            if self.routemask: # straight "routing" mode - treat like data
+            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)
             else:
-                ml = [] # accumulate output masks
-                ms = [] # accumulate output stops
+                ml = []  # accumulate output masks
+                ms = []  # accumulate output stops
                 # fan-out mode.
                 # conditionally fan-out mask bits, always fan-out stop bits
                 for i in range(len(self.n)):
@@ -263,9 +268,9 @@ class CombMultiInPipeline(MultiInControlBase):
 
         Attributes:
         -----------
-        p.data_i : StageInput, shaped according to ispec
+        p.i_data : StageInput, shaped according to ispec
             The pipeline input
-        p.data_o : StageOutput, shaped according to ospec
+        p.o_data : StageOutput, shaped according to ospec
             The pipeline output
         r_data : input_shape according to ispec
             A temporary (buffered) copy of a prior (valid) input.
@@ -275,16 +280,16 @@ class CombMultiInPipeline(MultiInControlBase):
 
     def __init__(self, stage, p_len, p_mux, maskwid=0, routemask=False):
         MultiInControlBase.__init__(self, p_len=p_len, maskwid=maskwid,
-                                          routemask=routemask)
+                                    routemask=routemask)
         self.stage = stage
         self.maskwid = maskwid
         self.p_mux = p_mux
 
         # set up the input and output data
         for i in range(p_len):
-            name = 'data_i_%d' % i
-            self.p[i].data_i = _spec(stage.ispec, name) # input type
-        self.n.data_o = _spec(stage.ospec, 'data_o')
+            name = 'i_data_%d' % i
+            self.p[i].i_data = _spec(stage.ispec, name)  # input type
+        self.n.o_data = _spec(stage.ospec, 'o_data')
 
     def process(self, i):
         if hasattr(self.stage, "process"):
@@ -304,16 +309,15 @@ class CombMultiInPipeline(MultiInControlBase):
         p_len = len(self.p)
         for i in range(p_len):
             name = 'r_%d' % i
-            r = _spec(self.stage.ispec, name) # input type
+            r = _spec(self.stage.ispec, name)  # input type
             r_data.append(r)
             data_valid.append(Signal(name="data_valid", reset_less=True))
             p_i_valid.append(Signal(name="p_i_valid", reset_less=True))
             n_i_readyn.append(Signal(name="n_i_readyn", reset_less=True))
             if hasattr(self.stage, "setup"):
-                print ("setup", self, self.stage, r)
+                print("setup", self, self.stage, r)
                 self.stage.setup(m, r)
-        if len(r_data) > 1:
-            r_data = Array(r_data)
+        if True:  # len(r_data) > 1: # hmm always create an Array even of len 1
             p_i_valid = Array(p_i_valid)
             n_i_readyn = Array(n_i_readyn)
             data_valid = Array(data_valid)
@@ -321,7 +325,7 @@ class CombMultiInPipeline(MultiInControlBase):
         nirn = Signal(reset_less=True)
         m.d.comb += nirn.eq(~self.n.i_ready)
         mid = self.p_mux.m_id
-        print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len)
+        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_i_readyn[i].eq(1)
@@ -334,7 +338,8 @@ class CombMultiInPipeline(MultiInControlBase):
             m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i)
         else:
             m.d.comb += maskedout.eq(1)
-        m.d.comb += p_i_valid[mid].eq(maskedout & self.p_mux.active)
+        m.d.comb += p_i_valid[mid].eq(maskedout & self.p_mux.active &
+                                      self.p[mid].i_valid)
         m.d.comb += self.p[mid].o_ready.eq(~data_valid[mid] | self.n.i_ready)
         m.d.comb += n_i_readyn[mid].eq(nirn & data_valid[mid])
         anyvalid = Signal(i, reset_less=True)
@@ -343,8 +348,8 @@ class CombMultiInPipeline(MultiInControlBase):
             av.append(data_valid[i])
         anyvalid = Cat(*av)
         m.d.comb += self.n.o_valid.eq(anyvalid.bool())
-        m.d.comb += data_valid[mid].eq(p_i_valid[mid] | \
-                                    (n_i_readyn[mid] ))
+        m.d.comb += data_valid[mid].eq(p_i_valid[mid] |
+                                       (n_i_readyn[mid]))
 
         if self.routemask:
             # XXX hack - fixes loop
@@ -361,10 +366,12 @@ class CombMultiInPipeline(MultiInControlBase):
                 #m.d.comb += vr.eq(p.i_valid & p.o_ready)
                 with m.If(vr):
                     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(r_data[i], self.process(self.p[i].i_data))
+                    with m.If(mid == i):
+                        m.d.comb += eq(self.n.o_data, r_data[i])
         else:
-            ml = [] # accumulate output masks
-            ms = [] # accumulate output stops
+            ml = []  # accumulate output masks
+            ms = []  # accumulate output stops
             for i in range(p_len):
                 vr = Signal(reset_less=True)
                 p = self.p[i]
@@ -376,7 +383,9 @@ class CombMultiInPipeline(MultiInControlBase):
                     m.d.comb += maskedout.eq(1)
                 m.d.comb += vr.eq(maskedout.bool() & p.i_valid & p.o_ready)
                 with m.If(vr):
-                    m.d.comb += eq(r_data[i], self.p[i].data_i)
+                    m.d.comb += eq(r_data[i], self.process(self.p[i].i_data))
+                    with m.If(mid == i):
+                        m.d.comb += eq(self.n.o_data, r_data[i])
                 if self.maskwid:
                     mlen = len(self.p[i].mask_i)
                     s = mlen*i
@@ -387,7 +396,8 @@ class CombMultiInPipeline(MultiInControlBase):
                 m.d.comb += self.n.mask_o.eq(Cat(*ml))
                 m.d.comb += self.n.stop_o.eq(Cat(*ms))
 
-        m.d.comb += eq(self.n.data_o, self.process(r_data[mid]))
+        #print ("o_data", self.n.o_data, "r_data[mid]", mid, r_data[mid])
+        #m.d.comb += eq(self.n.o_data, r_data[mid])
 
         return m
 
@@ -397,9 +407,9 @@ class NonCombMultiInPipeline(MultiInControlBase):
 
         Attributes:
         -----------
-        p.data_i : StageInput, shaped according to ispec
+        p.i_data : StageInput, shaped according to ispec
             The pipeline input
-        p.data_o : StageOutput, shaped according to ospec
+        p.o_data : StageOutput, shaped according to ospec
             The pipeline output
         r_data : input_shape according to ispec
             A temporary (buffered) copy of a prior (valid) input.
@@ -409,16 +419,16 @@ class NonCombMultiInPipeline(MultiInControlBase):
 
     def __init__(self, stage, p_len, p_mux, maskwid=0, routemask=False):
         MultiInControlBase.__init__(self, p_len=p_len, maskwid=maskwid,
-                                          routemask=routemask)
+                                    routemask=routemask)
         self.stage = stage
         self.maskwid = maskwid
         self.p_mux = p_mux
 
         # set up the input and output data
         for i in range(p_len):
-            name = 'data_i_%d' % i
-            self.p[i].data_i = _spec(stage.ispec, name) # input type
-        self.n.data_o = _spec(stage.ospec, 'data_o')
+            name = 'i_data_%d' % i
+            self.p[i].i_data = _spec(stage.ispec, name)  # input type
+        self.n.o_data = _spec(stage.ospec, 'o_data')
 
     def process(self, i):
         if hasattr(self.stage, "process"):
@@ -437,12 +447,12 @@ class NonCombMultiInPipeline(MultiInControlBase):
         p_len = len(self.p)
         for i in range(p_len):
             name = 'r_%d' % i
-            r = _spec(self.stage.ispec, name) # input type
+            r = _spec(self.stage.ispec, name)  # input type
             r_data.append(r)
             r_busy.append(Signal(name="r_busy%d" % i, reset_less=True))
             p_i_valid.append(Signal(name="p_i_valid%d" % i, reset_less=True))
             if hasattr(self.stage, "setup"):
-                print ("setup", self, self.stage, r)
+                print("setup", self, self.stage, r)
                 self.stage.setup(m, r)
         if len(r_data) > 1:
             r_data = Array(r_data)
@@ -452,7 +462,7 @@ class NonCombMultiInPipeline(MultiInControlBase):
         nirn = Signal(reset_less=True)
         m.d.comb += nirn.eq(~self.n.i_ready)
         mid = self.p_mux.m_id
-        print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len)
+        print("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len)
         for i in range(p_len):
             m.d.comb += r_busy[i].eq(0)
             m.d.comb += n_i_readyn[i].eq(1)
@@ -473,8 +483,8 @@ class NonCombMultiInPipeline(MultiInControlBase):
             av.append(data_valid[i])
         anyvalid = Cat(*av)
         m.d.comb += self.n.o_valid.eq(anyvalid.bool())
-        m.d.comb += data_valid[mid].eq(p_i_valid[mid] | \
-                                    (n_i_readyn[mid] ))
+        m.d.comb += data_valid[mid].eq(p_i_valid[mid] |
+                                       (n_i_readyn[mid]))
 
         if self.routemask:
             # XXX hack - fixes loop
@@ -491,10 +501,10 @@ class NonCombMultiInPipeline(MultiInControlBase):
                 #m.d.comb += vr.eq(p.i_valid & p.o_ready)
                 with m.If(vr):
                     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(r_data[i], self.p[i].i_data)
         else:
-            ml = [] # accumulate output masks
-            ms = [] # accumulate output stops
+            ml = []  # accumulate output masks
+            ms = []  # accumulate output stops
             for i in range(p_len):
                 vr = Signal(reset_less=True)
                 p = self.p[i]
@@ -506,7 +516,7 @@ class NonCombMultiInPipeline(MultiInControlBase):
                     m.d.comb += maskedout.eq(1)
                 m.d.comb += vr.eq(maskedout.bool() & p.i_valid & p.o_ready)
                 with m.If(vr):
-                    m.d.comb += eq(r_data[i], self.p[i].data_i)
+                    m.d.comb += eq(r_data[i], self.p[i].i_data)
                 if self.maskwid:
                     mlen = len(self.p[i].mask_i)
                     s = mlen*i
@@ -517,42 +527,42 @@ class NonCombMultiInPipeline(MultiInControlBase):
                 m.d.comb += self.n.mask_o.eq(Cat(*ml))
                 m.d.comb += self.n.stop_o.eq(Cat(*ms))
 
-        m.d.comb += eq(self.n.data_o, self.process(r_data[mid]))
+        m.d.comb += eq(self.n.o_data, self.process(r_data[mid]))
 
         return m
 
 
 class CombMuxOutPipe(CombMultiOutPipeline):
     def __init__(self, stage, n_len, maskwid=0, muxidname=None,
-                                     routemask=False):
+                 routemask=False):
         muxidname = muxidname or "muxid"
         # HACK: stage is also the n-way multiplexer
         CombMultiOutPipeline.__init__(self, stage, n_len=n_len,
-                                            n_mux=stage, maskwid=maskwid,
-                                            routemask=routemask)
+                                      n_mux=stage, maskwid=maskwid,
+                                      routemask=routemask)
 
         # HACK: n-mux is also the stage... so set the muxid equal to input muxid
-        muxid = getattr(self.p.data_i, muxidname)
-        print ("combmuxout", muxidname, muxid)
+        muxid = getattr(self.p.i_data, muxidname)
+        print("combmuxout", muxidname, muxid)
         stage.m_id = muxid
 
 
-
 class InputPriorityArbiter(Elaboratable):
     """ arbitration module for Input-Mux pipe, baed on PriorityEncoder
     """
+
     def __init__(self, pipe, num_rows):
         self.pipe = pipe
         self.num_rows = num_rows
         self.mmax = int(log(self.num_rows) / log(2))
-        self.m_id = Signal(self.mmax, reset_less=True) # multiplex id
+        self.m_id = Signal(self.mmax, reset_less=True)  # multiplex id
         self.active = Signal(reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
 
         assert len(self.pipe.p) == self.num_rows, \
-                "must declare input to be same size"
+            "must declare input to be same size"
         pe = PriorityEncoder(self.num_rows)
         m.submodules.selector = pe
 
@@ -568,7 +578,7 @@ class InputPriorityArbiter(Elaboratable):
             else:
                 m.d.comb += p_i_valid.eq(self.pipe.p[i].i_valid_test)
             in_ready.append(p_i_valid)
-        m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids"
+        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)
         m.d.comb += self.m_id.eq(pe.o)       # output one active input
 
@@ -578,7 +588,6 @@ class InputPriorityArbiter(Elaboratable):
         return [self.m_id, self.active]
 
 
-
 class PriorityCombMuxInPipe(CombMultiInPipeline):
     """ an example of how to use the combinatorial pipeline.
     """