looking for replacements of the hard-coded control blocks
[ieee754fpu.git] / src / add / singlepipe.py
index d6a96cbdb37f8c26d4f2e1d45f8f2c6e942c726b..fe052be72a3e70fde85e56058cf708ea9e7cd341 100644 (file)
@@ -172,6 +172,7 @@ from nmigen.hdl.rec import Record, Layout
 
 from abc import ABCMeta, abstractmethod
 from collections.abc import Sequence
+from queue import Queue
 
 
 class RecordObject(Record):
@@ -628,6 +629,12 @@ class ControlBase:
 
         return eqs
 
+    def _postprocess(self, i): # XXX DISABLED
+        return i # RETURNS INPUT
+        if hasattr(self.stage, "postprocess"):
+            return self.stage.postprocess(i)
+        return i
+
     def set_input(self, i):
         """ helper function to set the input data
         """
@@ -734,14 +741,16 @@ class BufferedHandshake(ControlBase):
 
         # data pass-through conditions
         with self.m.If(npnn):
+            o_data = self._postprocess(result)
             self.m.d.sync += [self.n.o_valid.eq(p_i_valid), # valid if p_valid
-                              eq(self.n.o_data, result),    # update output
+                              eq(self.n.o_data, o_data),    # update output
                              ]
         # buffer flush conditions (NOTE: can override data passthru conditions)
         with self.m.If(nir_por_n): # not stalled
             # Flush the [already processed] buffer to the output port.
+            o_data = self._postprocess(r_data)
             self.m.d.sync += [self.n.o_valid.eq(1),  # reg empty
-                              eq(self.n.o_data, r_data), # flush buffer
+                              eq(self.n.o_data, o_data), # flush buffer
                              ]
         # output ready conditions
         self.m.d.sync += self.p._o_ready.eq(nir_novn | por_pivn)
@@ -811,12 +820,14 @@ class SimpleHandshake(ControlBase):
 
         # previous valid and ready
         with m.If(p_i_valid_p_o_ready):
+            o_data = self._postprocess(result)
             m.d.sync += [r_busy.eq(1),      # output valid
-                         eq(self.n.o_data, result), # update output
+                         eq(self.n.o_data, o_data), # update output
                         ]
         # previous invalid or not ready, however next is accepting
         with m.Elif(n_i_ready):
-            m.d.sync += [eq(self.n.o_data, result)]
+            o_data = self._postprocess(result)
+            m.d.sync += [eq(self.n.o_data, o_data)]
             # TODO: could still send data here (if there was any)
             #m.d.sync += self.n.o_valid.eq(0) # ...so set output invalid
             m.d.sync += r_busy.eq(0) # ...so set output invalid
@@ -917,11 +928,11 @@ class UnbufferedPipeline(ControlBase):
 
         with m.If(pv):
             m.d.sync += eq(r_data, self.stage.process(self.p.i_data))
-        m.d.comb += eq(self.n.o_data, r_data)
+        o_data = self._postprocess(r_data)
+        m.d.comb += eq(self.n.o_data, o_data)
 
         return self.m
 
-
 class UnbufferedPipeline2(ControlBase):
     """ A simple pipeline stage with single-clock synchronisation
         and two-way valid/ready synchronised signalling.
@@ -997,8 +1008,9 @@ class UnbufferedPipeline2(ControlBase):
         m.d.comb += self.p._o_ready.eq(~buf_full)
         m.d.sync += buf_full.eq(~self.n.i_ready_test & self.n.o_valid)
 
-        odata = Mux(buf_full, buf, self.stage.process(self.p.i_data))
-        m.d.comb += eq(self.n.o_data, odata)
+        o_data = Mux(buf_full, buf, self.stage.process(self.p.i_data))
+        o_data = self._postprocess(o_data)
+        m.d.comb += eq(self.n.o_data, o_data)
         m.d.sync += eq(buf, self.n.o_data)
 
         return self.m
@@ -1051,6 +1063,8 @@ class PassThroughHandshake(ControlBase):
     def elaborate(self, platform):
         self.m = m = ControlBase._elaborate(self, platform)
 
+        r_data = self.stage.ospec() # output type
+
         # temporaries
         p_i_valid = Signal(reset_less=True)
         pvr = Signal(reset_less=True)
@@ -1060,8 +1074,10 @@ class PassThroughHandshake(ControlBase):
         m.d.comb += self.p.o_ready.eq(~self.n.o_valid |  self.n.i_ready_test)
         m.d.sync += self.n.o_valid.eq(p_i_valid       | ~self.p.o_ready)
 
-        odata = Mux(pvr, self.stage.process(self.p.i_data), self.n.o_data)
-        m.d.sync += eq(self.n.o_data, odata)
+        odata = Mux(pvr, self.stage.process(self.p.i_data), r_data)
+        m.d.sync += eq(r_data, odata)
+        r_data = self._postprocess(r_data)
+        m.d.comb += eq(self.n.o_data, r_data)
 
         return m
 
@@ -1082,7 +1098,8 @@ class FIFOControl(ControlBase):
         i_data -> fifo.din -> FIFO -> fifo.dout -> o_data
     """
 
-    def __init__(self, depth, stage, fwft=True, buffered=False):
+    def __init__(self, depth, stage, in_multi=None, stage_ctl=False,
+                                     fwft=True, buffered=False, pipe=False):
         """ FIFO Control
 
             * depth: number of entries in the FIFO
@@ -1111,8 +1128,9 @@ class FIFOControl(ControlBase):
             depth += 1
         self.fwft = fwft
         self.buffered = buffered
+        self.pipe = pipe
         self.fdepth = depth
-        ControlBase.__init__(self, stage=stage)
+        ControlBase.__init__(self, stage, in_multi, stage_ctl)
 
     def elaborate(self, platform):
         self.m = m = ControlBase._elaborate(self, platform)
@@ -1122,7 +1140,7 @@ class FIFOControl(ControlBase):
         if self.buffered:
             fifo = SyncFIFOBuffered(fwidth, self.fdepth)
         else:
-            fifo = SyncFIFO(fwidth, self.fdepth, fwft=self.fwft)
+            fifo = Queue(fwidth, self.fdepth, fwft=self.fwft, pipe=self.pipe)
         m.submodules.fifo = fifo
 
         # store result of processing in combinatorial temporary
@@ -1145,6 +1163,34 @@ class FIFOControl(ControlBase):
             m.d.comb += connections
         else:
             m.d.sync += connections # unbuffered fwft mode needs sync
-        m.d.comb += flatten(self.n.o_data).eq(fifo.dout)
+        o_data = flatten(self.n.o_data).eq(fifo.dout)
+        o_data = self._postprocess(o_data)
+        m.d.comb += o_data
 
         return m
+
+
+# aka "RegStage".
+class UnbufferedPipeline(FIFOControl):
+    def __init__(self, stage, in_multi=None, stage_ctl=False):
+        FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl,
+                                   fwft=True, pipe=False)
+
+# aka "BreakReadyStage" XXX had to set fwft=True to get it to work
+class PassThroughHandshake(FIFOControl):
+    def __init__(self, stage, in_multi=None, stage_ctl=False):
+        FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl,
+                                   fwft=True, pipe=True)
+
+# this is *probably* BufferedHandshake, although test #997 now succeeds.
+class BufferedHandshake(FIFOControl):
+    def __init__(self, stage, in_multi=None, stage_ctl=False):
+        FIFOControl.__init__(self, 2, stage, in_multi, stage_ctl,
+                                   fwft=True, pipe=False)
+
+
+# this is *probably* SimpleHandshake (note: memory cell size=0)
+class SimpleHandshake(FIFOControl):
+    def __init__(self, stage, in_multi=None, stage_ctl=False):
+        FIFOControl.__init__(self, 0, stage, in_multi, stage_ctl,
+                                   fwft=True, pipe=False)