start converting hardfloat-verilog fmac to nmigen
[ieee754fpu.git] / src / nmutil / multipipe.py
index 82e3b8ae8088f0bbf799698b6e4c12086eb645e1..725afc16552bba44a8f597c680c7c84ae6465541 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, maskwid=0, routemask=False):
         """ Multi-input Control class.  Conforms to same API as ControlBase...
             mostly.  has additional indices to the *multiple* input stages
 
@@ -37,12 +37,18 @@ class MultiInControlBase(Elaboratable):
             * add data_i members to PrevControl and
             * add data_o member  to NextControl
         """
+        self.routemask = routemask
         # set up input and output IO ACK (prev/next ready/valid)
+        print ("multi_in", maskwid, 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()
+        if routemask:
+            nmaskwid = maskwid # straight route mask mode
+        else:
+            nmaskwid = maskwid * p_len # fan-in mode
+        self.n = NextControl(maskwid=maskwid*p_len) # masks fan in (Cat)
 
     def connect_to_next(self, nxt, p_idx=0):
         """ helper function to connect to the next stage data/valid/ready.
@@ -89,7 +95,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, maskwid=0, routemask=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]
@@ -102,11 +108,16 @@ class MultiOutControlBase(Elaboratable):
             * add data_o members to NextControl
         """
 
+        if routemask:
+            nmaskwid = maskwid # straight route mask mode
+        else:
+            nmaskwid = maskwid * n_len # fan-out mode
+
         # set up input and output IO ACK (prev/next ready/valid)
-        self.p = PrevControl(in_multi)
+        self.p = PrevControl(in_multi, maskwid=nmaskwid)
         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 +169,12 @@ 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, maskwid=0, routemask=False):
+        MultiOutControlBase.__init__(self, n_len=n_len, maskwid=maskwid,
+                                            routemask=routemask)
         self.stage = stage
+        self.maskwid = maskwid
+        self.routemask = routemask
         self.n_mux = n_mux
 
         # set up the input and output data
@@ -178,7 +192,7 @@ class CombMultiOutPipeline(MultiOutControlBase):
         m = MultiOutControlBase.elaborate(self, platform)
 
         if hasattr(self.n_mux, "elaborate"): # TODO: identify submodule?
-            m.submodules += self.n_mux
+            m.submodules.n_mux = self.n_mux
 
         # need buffer register conforming to *input* spec
         r_data = _spec(self.stage.ispec, 'r_data') # input type
@@ -186,7 +200,7 @@ class CombMultiOutPipeline(MultiOutControlBase):
             self.stage.setup(m, r_data)
 
         # multiplexer id taken from n_mux
-        mid = self.n_mux.m_id
+        muxid = self.n_mux.m_id
         print ("self.n_mux", self.n_mux)
         print ("self.n_mux.m_id", self.n_mux.m_id)
 
@@ -194,20 +208,37 @@ 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[mid].valid_o
-        m.d.comb += self.p.ready_o.eq(~data_valid | self.n[mid].ready_i)
-        m.d.comb += data_valid.eq(p_valid_i | \
-                                    (~self.n[mid].ready_i & data_valid))
-        with m.If(pv):
-            m.d.comb += eq(r_data, self.p.data_i)
-        m.d.comb += eq(self.n[mid].data_o, self.process(r_data))
-
+        #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)
+        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)
+            else:
+                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)):
+                    ml.append(self.n[i].mask_o)
+                    ms.append(self.n[i].stop_o)
+                m.d.comb += Cat(*ms).eq(self.p.stop_i)
+                with m.If(pv):
+                    m.d.comb += Cat(*ml).eq(self.p.mask_i)
         return m
 
 
@@ -226,9 +257,11 @@ 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, maskwid=0, routemask=False):
+        MultiInControlBase.__init__(self, p_len=p_len, maskwid=maskwid,
+                                          routemask=routemask)
         self.stage = stage
+        self.maskwid = maskwid
         self.p_mux = p_mux
 
         # set up the input and output data
@@ -245,7 +278,7 @@ class CombMultiInPipeline(MultiInControlBase):
     def elaborate(self, platform):
         m = MultiInControlBase.elaborate(self, platform)
 
-        m.submodules += self.p_mux
+        m.submodules.p_mux = self.p_mux
 
         # need an array of buffer registers conforming to *input* spec
         r_data = []
@@ -261,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)
@@ -271,12 +305,16 @@ 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)
             m.d.comb += p_valid_i[i].eq(0)
             m.d.comb += self.p[i].ready_o.eq(0)
-        m.d.comb += p_valid_i[mid].eq(self.p_mux.active)
+        p = self.p[mid]
+        maskedout = Signal(reset_less=True)
+        m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i)
+        m.d.comb += p_valid_i[mid].eq(maskedout & self.p_mux.active)
         m.d.comb += self.p[mid].ready_o.eq(~data_valid[mid] | self.n.ready_i)
         m.d.comb += n_ready_in[mid].eq(nirn & data_valid[mid])
         anyvalid = Signal(i, reset_less=True)
@@ -286,13 +324,42 @@ class CombMultiInPipeline(MultiInControlBase):
         anyvalid = Cat(*av)
         m.d.comb += self.n.valid_o.eq(anyvalid.bool())
         m.d.comb += data_valid[mid].eq(p_valid_i[mid] | \
-                                    (n_ready_in[mid] & data_valid[mid]))
-
-        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)
-            with m.If(vr):
-                m.d.comb += eq(r_data[i], self.p[i].data_i)
+                                    (n_ready_in[mid] ))
+
+        if self.routemask:
+            # XXX hack - fixes loop
+            m.d.comb += eq(self.n.stop_o, self.p[0].stop_i)
+            for i in range(p_len):
+                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)
+                #m.d.comb += vr.eq(p.valid_i & p.ready_o)
+                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)
+        else:
+            ml = [] # accumulate output masks
+            ms = [] # accumulate output stops
+            for i in range(p_len):
+                vr = Signal(reset_less=True)
+                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:
+                    mlen = len(self.p[i].mask_i)
+                    s = mlen*i
+                    e = mlen*(i+1)
+                    ml.append(Mux(vr, self.p[i].mask_i, Const(0, mlen)))
+                    ms.append(self.p[i].stop_i)
+            if self.maskwid:
+                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]))
 
@@ -300,13 +367,18 @@ class CombMultiInPipeline(MultiInControlBase):
 
 
 class CombMuxOutPipe(CombMultiOutPipeline):
-    def __init__(self, stage, n_len):
+    def __init__(self, stage, n_len, maskwid=0, muxidname=None,
+                                     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)
+        CombMultiOutPipeline.__init__(self, stage, n_len=n_len,
+                                            n_mux=stage, maskwid=maskwid,
+                                            routemask=routemask)
 
-        # HACK: n-mux is also the stage... so set the muxid equal to input mid
-        print ("combmuxout", self.p.data_i.mid)
-        stage.m_id = self.p.data_i.mid
+        # 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)
+        stage.m_id = muxid
 
 
 
@@ -332,7 +404,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)
@@ -349,9 +427,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, maskwid=0, routemask=False):
         p_mux = InputPriorityArbiter(self, p_len)
-        CombMultiInPipeline.__init__(self, stage, p_len, p_mux)
+        CombMultiInPipeline.__init__(self, stage, p_len, p_mux,
+                                     maskwid=maskwid, routemask=routemask)
 
 
 if __name__ == '__main__':