From 96fe0cff3cd5918c27257c2ae25ad980a0bc7a62 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sun, 7 Apr 2019 10:30:20 +0100 Subject: [PATCH] add sync handshake logic --- src/add/singlepipe.py | 87 ++++++++++++++++++++++++++++++++++++++++ src/add/test_buf_pipe.py | 31 +++++++------- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/src/add/singlepipe.py b/src/add/singlepipe.py index 590773a8..b27e90ef 100644 --- a/src/add/singlepipe.py +++ b/src/add/singlepipe.py @@ -636,6 +636,93 @@ class BufferedPipeline(ControlBase): return self.m +class BufferedPipeline2(ControlBase): + """ buffered pipeline stage. data and strobe signals travel in sync. + if ever the input is ready and the output is not, processed data + is shunted in a temporary register. + + Argument: stage. see Stage API above + + stage-1 p.i_valid >>in stage n.o_valid out>> stage+1 + stage-1 p.o_ready <>in stage n.o_data out>> stage+1 + | | + process --->----^ + | | + +-- r_data ->-+ + + input data p.i_data is read (only), is processed and goes into an + intermediate result store [process()]. this is updated combinatorially. + + in a non-stall condition, the intermediate result will go into the + output (update_output). however if ever there is a stall, it goes + into r_data instead [update_buffer()]. + + when the non-stall condition is released, r_data is the first + to be transferred to the output [flush_buffer()], and the stall + condition cleared. + + on the next cycle (as long as stall is not raised again) the + input may begin to be processed and transferred directly to output. + + """ + 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() + + def elaborate(self, platform): + + self.m = ControlBase._elaborate(self, platform) + + result = self.stage.ospec() + r_busy = Signal(reset=0) + if hasattr(self.stage, "setup"): + self.stage.setup(self.m, self.p.i_data) + + # establish some combinatorial temporaries + o_n_validn = Signal(reset_less=True) + n_i_ready = Signal(reset_less=True, name="n_i_rdy_data") + o_n_valid_i_n_ready = Signal(reset_less=True) + p_i_valid = Signal(reset_less=True) + self.m.d.comb += [p_i_valid.eq(self.p.i_valid_test), + o_n_validn.eq(~self.n.o_valid), + n_i_ready.eq(self.n.i_ready_test), + o_n_valid_i_n_ready.eq(self.n.o_valid & n_i_ready), + ] + + # store result of processing in combinatorial temporary + self.m.d.comb += eq(result, self.stage.process(self.p.i_data)) + + with self.m.If(self.p.o_ready): # output is ready + with self.m.If(p_i_valid): # and input is valid + self.m.d.sync += [r_busy.eq(1), + eq(self.n.o_data, result), # update output + ] + # else stay in idle condition (output ready, but input wasn't valid) + + # output valid but not ready, and input is ready + with self.m.Elif(o_n_valid_i_n_ready): + # output transaction just took place + self.m.d.sync += [r_busy.eq(0), + self.n.o_valid.eq(0), # set output invalid + ] + # + with self.m.Elif(o_n_validn): + # can check here for data valid + self.m.d.sync += [self.n.o_valid.eq(1), + #eq(self.n.o_data, result), # update output + ] + + #self.m.d.comb += self.p._o_ready.eq(~r_busy) + self.m.d.comb += self.p._o_ready.eq(~(((~n_i_ready)&(self.n.o_valid))| \ + (r_busy))) + return self.m + + class UnbufferedPipeline(ControlBase): """ A simple pipeline stage with single-clock synchronisation and two-way valid/ready synchronised signalling. diff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py index 8c157732..d9cee561 100644 --- a/src/add/test_buf_pipe.py +++ b/src/add/test_buf_pipe.py @@ -25,6 +25,7 @@ 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 singlepipe import BufferedPipeline2 from random import randint, seed @@ -209,7 +210,7 @@ class Test5: send = True else: send = randint(0, send_range) != 0 - #send = True + send = True o_p_ready = yield self.dut.p.o_ready if not o_p_ready: yield @@ -228,7 +229,7 @@ class Test5: stall_range = randint(0, 3) for j in range(randint(1,10)): ready = randint(0, stall_range) != 0 - #ready = True + ready = True yield self.dut.n.i_ready.eq(ready) yield o_n_valid = yield self.dut.n.o_valid @@ -591,7 +592,7 @@ class ExampleStageDelayCls(StageCls): fashion """ - def __init__(self, valid_trigger=2): + def __init__(self, valid_trigger=3): self.count = Signal(2) self.valid_trigger = valid_trigger @@ -692,11 +693,11 @@ class ExampleBufPipe3(ControlBase): # Test 15 ###################################################################### -class ExampleBufModeAdd1Pipe(BufferedPipeline): +class ExampleBufModeAdd1Pipe(BufferedPipeline2): def __init__(self): stage = ExampleStageCls() - BufferedPipeline.__init__(self, stage, buffermode=False) + BufferedPipeline2.__init__(self, stage) ###################################################################### @@ -885,28 +886,28 @@ if __name__ == '__main__': with open("test_unbufpipe13.il", "w") as f: f.write(vl) - print ("test 14") - dut = ExampleBufPipe3() + print ("test 15)") + dut = ExampleBufModeAdd1Pipe() data = data_chain1() - test = Test5(dut, test9_resultfn, data=data) - run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe14.vcd") + test = Test5(dut, test12_resultfn, data=data) + run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf15.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_bufpipe14.il", "w") as f: + with open("test_bufunbuf15.il", "w") as f: f.write(vl) - print ("test 15)") - dut = ExampleBufModeAdd1Pipe() + print ("test 14") + dut = ExampleBufPipe3() data = data_chain1() - test = Test5(dut, test12_resultfn, data=data) - run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf15.vcd") + test = Test5(dut, test9_resultfn, data=data) + run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe14.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_bufunbuf15.il", "w") as f: + with open("test_bufpipe14.il", "w") as f: f.write(vl) print ("test 16)") -- 2.30.2