add 2nd unbuffered pipeline class
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 6 Apr 2019 03:56:00 +0000 (04:56 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 6 Apr 2019 03:56:00 +0000 (04:56 +0100)
src/add/singlepipe.py
src/add/test_buf_pipe.py

index 42b20654eeb12b32d9efb1bd98da2d24dfce385f..f9e5ec8f49a063b6da383efeca50fc78930f5788 100644 (file)
@@ -699,6 +699,74 @@ class UnbufferedPipeline(ControlBase):
         return self.m
 
 
+class UnbufferedPipeline2(ControlBase):
+    """ A simple pipeline stage with single-clock synchronisation
+        and two-way valid/ready synchronised signalling.
+
+        Note that a stall in one stage will result in the entire pipeline
+        chain stalling.
+
+        Also that unlike BufferedPipeline, the valid/ready signalling does NOT
+        travel synchronously with the data: the valid/ready signalling
+        combines in a *combinatorial* fashion.  Therefore, a long pipeline
+        chain will lengthen propagation delays.
+
+        Argument: stage.  see Stage API, above
+
+        stage-1   p.i_valid >>in   stage   n.o_valid out>>   stage+1
+        stage-1   p.o_ready <<out  stage   n.i_ready <<in    stage+1
+        stage-1   p.i_data  >>in   stage   n.o_data  out>>   stage+1
+                              |             |
+                            r_data        result
+                              |             |
+                              +--process ->-+
+
+        Attributes:
+        -----------
+        p.i_data : StageInput, shaped according to ispec
+            The pipeline input
+        p.o_data : StageOutput, shaped according to ospec
+            The pipeline output
+        buf : output_shape according to ospec
+            A temporary (buffered) copy of a valid output
+            This is HELD if the output is not ready.  It is updated
+            SYNCHRONOUSLY.
+    """
+
+    def __init__(self, stage, stage_ctl=False):
+        ControlBase.__init__(self, stage_ctl=stage_ctl)
+        self.stage = stage
+
+        # set up the input and output data
+        self.p.i_data = stage.ispec() # input type
+        self.n.o_data = stage.ospec() # output type
+
+    def elaborate(self, platform):
+        self.m = ControlBase._elaborate(self, platform)
+
+        buf_full = Signal() # is data valid or not
+        buf = self.stage.ospec() # output type
+        if hasattr(self.stage, "setup"):
+            self.stage.setup(self.m, self.p.i_data)
+
+        # some temporaries
+        p_i_valid = Signal(reset_less=True)
+        self.m.d.comb += p_i_valid.eq(self.p.i_valid_test)
+
+        self.m.d.comb += self.n.o_valid.eq(buf_full | p_i_valid)
+        self.m.d.comb += self.p._o_ready.eq(~buf_full)
+        self.m.d.sync += buf_full.eq(~self.n.i_ready_test & \
+                                        (p_i_valid | buf_full))
+        with self.m.If(buf_full):
+            self.m.d.comb += eq(self.n.o_data, buf)
+        with self.m.Else():
+            self.m.d.comb += eq(self.n.o_data,
+                                self.stage.process(self.p.i_data))
+        self.m.d.sync += eq(buf, self.n.o_data)
+
+        return self.m
+
+
 class PassThroughStage(StageCls):
     """ a pass-through stage which has its input data spec equal to its output,
         and "passes through" its data from input to output.
index 17caa176b5a3e692c9ab841f0c919d8b7ee2e8da..2c3c430f91f37fbeb0094c87aa6211d93a148d0a 100644 (file)
@@ -24,6 +24,7 @@ from example_buf_pipe import ExamplePipeline, UnbufferedPipeline
 from example_buf_pipe import ExampleStageCls
 from example_buf_pipe import PrevControl, NextControl, BufferedPipeline
 from example_buf_pipe import StageChain, ControlBase, StageCls
+from singlepipe import UnbufferedPipeline2
 
 from random import randint
 
@@ -206,7 +207,6 @@ class Test5:
                     send = True
                 else:
                     send = randint(0, send_range) != 0
-                send = True
                 o_p_ready = yield self.dut.p.o_ready
                 if not o_p_ready:
                     yield
@@ -688,17 +688,14 @@ class ExampleBufAdd1Pipe(BufferedPipeline):
         BufferedPipeline.__init__(self, stage)
 
 
-class ExampleUnBufAdd1Pipe(UnbufferedPipeline):
+class ExampleUnBufAdd1Pipe(UnbufferedPipeline2):
 
     def __init__(self):
         stage = ExampleStageCls()
-        UnbufferedPipeline.__init__(self, stage)
+        UnbufferedPipeline2.__init__(self, stage)
 
 
 class ExampleBufUnBufPipe(ControlBase):
-    """ Example of how to do delayed pipeline, where the stage signals
-        whether it is ready.
-    """
 
     def elaborate(self, platform):
         m = ControlBase._elaborate(self, platform)