add PassThroughHandshake class and unit test
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 8 Apr 2019 08:27:08 +0000 (09:27 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 8 Apr 2019 08:27:08 +0000 (09:27 +0100)
src/add/singlepipe.py
src/add/test_buf_pipe.py

index 95aae54fc40d2945aacd664164a8ac14c9896b6c..f6c2070342b2d874b95b7710b4be006f7acd79ec 100644 (file)
     logic, if chained together, is *combinatorial*, resulting in
     progressively larger gate delay.
 
+    PassThroughHandshake:
+    ------------------
+
+    A Control class that introduces a single clock delay, passing its
+    data through unaltered.  Unlike RegisterPipeline (which relies
+    on UnbufferedPipeline and PassThroughStage) it handles ready/valid
+    itself.
+
     RegisterPipeline:
     ----------------
 
@@ -850,6 +858,36 @@ class PassThroughStage(StageCls):
     def process(self, i): return i
 
 
+class PassThroughHandshake(ControlBase):
+    """ A control block that delays by one clock cycle.
+    """
+    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):
+        m = ControlBase._elaborate(self, platform)
+
+        # temporaries
+        p_i_valid = Signal(reset_less=True)
+        pvr = Signal(reset_less=True)
+        m.d.comb += p_i_valid.eq(self.p.i_valid_test)
+        m.d.comb += pvr.eq(p_i_valid & self.p.o_ready)
+
+        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)
+
+        self.m = m
+        return m
+
+
 class RegisterPipeline(UnbufferedPipeline):
     """ A pipeline stage that delays by one clock cycle, creating a
         sync'd latch out of o_data and o_valid as an indirect byproduct
index fe00449bdf9961760584f532f81e40db250ff6a8..b0dfa4dcfa8d46ae00979fdfaa8fcf66df421420 100644 (file)
@@ -26,6 +26,8 @@ from example_buf_pipe import PrevControl, NextControl, BufferedHandshake
 from example_buf_pipe import StageChain, ControlBase, StageCls
 from singlepipe import UnbufferedPipeline2
 from singlepipe import SimpleHandshake
+from singlepipe import PassThroughHandshake
+from singlepipe import PassThroughStage
 
 from random import randint, seed
 
@@ -706,6 +708,26 @@ class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2):
         UnbufferedPipeline2.__init__(self, stage)
 
 
+######################################################################
+# Test 18
+######################################################################
+
+class PassThroughTest(PassThroughHandshake):
+
+    def iospecfn(self):
+        return Signal(16, "out")
+
+    def __init__(self):
+        stage = PassThroughStage(self.iospecfn)
+        PassThroughHandshake.__init__(self, stage)
+
+def test_identical_resultfn(o_data, expected, i, o):
+    res = expected
+    assert o_data == res, \
+                "%d-%d data %x not match %x\n" \
+                % (i, o, o_data, res)
+
+
 ######################################################################
 # Test 998
 ######################################################################
@@ -930,6 +952,18 @@ if __name__ == '__main__':
     with open("test_unbufpipe17.il", "w") as f:
         f.write(vl)
 
+    print ("test 18")
+    dut = PassThroughTest()
+    data = data_chain1()
+    test = Test5(dut, test_identical_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_passthru18.vcd")
+    ports = [dut.p.i_valid, dut.n.i_ready,
+             dut.n.o_valid, dut.p.o_ready] + \
+             [dut.p.i_data] + [dut.n.o_data]
+    vl = rtlil.convert(dut, ports=ports)
+    with open("test_passthru18.il", "w") as f:
+        f.write(vl)
+
     print ("test 998 (fails, bug)")
     dut = ExampleBufPipe3()
     data = data_chain1()