From 7ace29822445f2564091c422dbca2a23fde38002 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Mon, 8 Apr 2019 09:27:08 +0100 Subject: [PATCH] add PassThroughHandshake class and unit test --- src/add/singlepipe.py | 38 ++++++++++++++++++++++++++++++++++++++ src/add/test_buf_pipe.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/add/singlepipe.py b/src/add/singlepipe.py index 95aae54f..f6c20703 100644 --- a/src/add/singlepipe.py +++ b/src/add/singlepipe.py @@ -95,6 +95,14 @@ 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 diff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py index fe00449b..b0dfa4dc 100644 --- a/src/add/test_buf_pipe.py +++ b/src/add/test_buf_pipe.py @@ -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() -- 2.30.2