update comments on FIFOControl
[ieee754fpu.git] / src / add / singlepipe.py
index b1e808aec344b6ed903256416593a3f05ffa792c..f9acfb5ad570fab250d7dd571ca83544ce2dd1b8 100644 (file)
@@ -1,11 +1,10 @@
-""" Pipeline and BufferedHandshake implementation, conforming to the same API.
-    For multi-input and multi-output variants, see multipipe.
+""" Pipeline API.  For multi-input and multi-output variants, see multipipe.
 
     Associated development bugs:
     * http://bugs.libre-riscv.org/show_bug.cgi?id=64
     * http://bugs.libre-riscv.org/show_bug.cgi?id=57
 
-    Important: see Stage API (iocontrol.py) in combination with below
+    Important: see Stage API (stageapi.py) in combination with below
 
     RecordBasedStage:
     ----------------
 
 from nmigen import Signal, Mux, Module, Elaboratable
 from nmigen.cli import verilog, rtlil
-from nmigen.lib.fifo import SyncFIFO, SyncFIFOBuffered
-from nmigen.hdl.ast import ArrayProxy
 from nmigen.hdl.rec import Record
 
 from queue import Queue
 import inspect
 
-import nmoperator
 from iocontrol import (PrevControl, NextControl, Object, RecordObject)
-from stageapi import (_spec, StageCls, Stage,
-                       StageChain, StageHelper)
+from stageapi import (_spec, StageCls, Stage, StageChain, StageHelper)
+import nmoperator
                       
 
 class RecordBasedStage(Stage):
@@ -202,13 +198,12 @@ class ControlBase(StageHelper, Elaboratable):
 
         # set up the input and output data
         if stage is not None:
-            self._new_data(self, self, "data")
+            self._new_data("data")
 
-    def _new_data(self, p, n, name):
+    def _new_data(self, name):
         """ allocates new data_i and data_o
         """
-        self.p.data_i = _spec(p.stage.ispec, "%s_i" % name)
-        self.n.data_o = _spec(n.stage.ospec, "%s_o" % name)
+        self.p.data_i, self.n.data_o = self.new_specs(name)
 
     @property
     def data_r(self):
@@ -272,6 +267,7 @@ class ControlBase(StageHelper, Elaboratable):
               an elaborate() to m.d.comb
         """
         assert len(pipechain) > 0, "pipechain must be non-zero length"
+        assert self.stage is None, "do not use connect with a stage"
         eqs = [] # collated list of assignment statements
 
         # connect inter-chain
@@ -283,9 +279,10 @@ class ControlBase(StageHelper, Elaboratable):
         # connect front and back of chain to ourselves
         front = pipechain[0]                # first in chain
         end = pipechain[-1]                 # last in chain
-        self._new_data(front, end, "chain") # NOTE: REPLACES existing data
+        self.set_specs(front, end) # sets up ispec/ospec functions
+        self._new_data("chain") # NOTE: REPLACES existing data
         eqs += front._connect_in(self)      # front p to our p
-        eqs += end._connect_out(self)       # end n   to out n
+        eqs += end._connect_out(self)       # end n   to our n
 
         return eqs
 
@@ -729,23 +726,29 @@ class RegisterPipeline(UnbufferedPipeline):
 
 
 class FIFOControl(ControlBase):
-    """ FIFO Control.  Uses SyncFIFO to store data, coincidentally
+    """ FIFO Control.  Uses Queue to store data, coincidentally
         happens to have same valid/ready signalling as Stage API.
 
         data_i -> fifo.din -> FIFO -> fifo.dout -> data_o
     """
     def __init__(self, depth, stage, in_multi=None, stage_ctl=False,
-                                     fwft=True, buffered=False, pipe=False):
+                                     fwft=True, pipe=False):
         """ FIFO Control
 
-            * :depth:    number of entries in the FIFO
-            * :stage:    data processing block
-            * :fwft:     first word fall-thru mode (non-fwft introduces delay)
-            * :buffered: use buffered FIFO (introduces extra cycle delay)
+            * :depth: number of entries in the FIFO
+            * :stage: data processing block
+            * :fwft:  first word fall-thru mode (non-fwft introduces delay)
+            * :pipe:  specifies pipe mode.
+
+            when fwft = True it indicates that transfers may occur
+            combinatorially through stage processing in the same clock cycle.
+            This requires that the Stage be a Moore FSM:
+            https://en.wikipedia.org/wiki/Moore_machine
 
-            NOTE 1: FPGAs may have trouble with the defaults for SyncFIFO
-                    (fwft=True, buffered=False).  XXX TODO: fix this by
-                    using Queue in all cases instead.
+            when fwft = False it indicates that all output signals are
+            produced only from internal registers or memory, i.e. that the
+            Stage is a Mealy FSM:
+            https://en.wikipedia.org/wiki/Mealy_machine
 
             data is processed (and located) as follows:
 
@@ -756,12 +759,7 @@ class FIFOControl(ControlBase):
             this is how the FIFO gets de-catted without needing a de-cat
             function
         """
-
-        assert not (fwft and buffered), "buffered cannot do fwft"
-        if buffered:
-            depth += 1
         self.fwft = fwft
-        self.buffered = buffered
         self.pipe = pipe
         self.fdepth = depth
         ControlBase.__init__(self, stage, in_multi, stage_ctl)
@@ -771,10 +769,7 @@ class FIFOControl(ControlBase):
 
         # make a FIFO with a signal of equal width to the data_o.
         (fwidth, _) = nmoperator.shape(self.n.data_o)
-        if self.buffered:
-            fifo = SyncFIFOBuffered(fwidth, self.fdepth)
-        else:
-            fifo = Queue(fwidth, self.fdepth, fwft=self.fwft, pipe=self.pipe)
+        fifo = Queue(fwidth, self.fdepth, fwft=self.fwft, pipe=self.pipe)
         m.submodules.fifo = fifo
 
         # store result of processing in combinatorial temporary
@@ -793,7 +788,7 @@ class FIFOControl(ControlBase):
         connections = [self.n.valid_o.eq(fifo.readable),
                        fifo.re.eq(self.n.ready_i_test),
                       ]
-        if self.fwft or self.buffered:
+        if self.fwft:
             m.d.comb += connections # combinatorial on next ready/valid
         else:
             m.d.sync += connections # unbuffered fwft mode needs sync