From 2b26be5b974d43047bf096a555408a62bab2c4eb Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Mon, 29 Apr 2019 01:14:25 +0100 Subject: [PATCH] move wrapping of stage into StageHandler --- src/add/iocontrol.py | 87 ++++++++++++++++++++++------------------ src/add/singlepipe.py | 14 +++---- src/add/test_buf_pipe.py | 8 ++-- 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/add/iocontrol.py b/src/add/iocontrol.py index dfa04797..423694b9 100644 --- a/src/add/iocontrol.py +++ b/src/add/iocontrol.py @@ -436,18 +436,19 @@ class StageChain(StageCls): return self.o # conform to Stage API: return last-loop output -class StageHandler(Elaboratable): - """ Stage handling class +class StageHandler: # (Elaboratable): + """ Stage handling (wrapper) class: makes e.g. static classes "real" + (instances) and provides a way to allocate data_i and data_o """ - def __init__(self, ctrl, stage): - """ - """ - if stage is not None: - self.new_data(self, self, "data") + def __init__(self, stage): self.stage = stage + def ispec(self, name): return _spec(self.stage.ispec, name) + def ospec(self, name): return _spec(self.stage.ospec, name) + def process(self, i): return self.stage.process(i) - @property - def data_r(self): - return self.stage.process(self.p.data_i) + def setup(self, m, i): + if self.stage is None or not hasattr(self.stage, "setup"): + return + self.stage.setup(m, i) def _postprocess(self, i): # XXX DISABLED return i # RETURNS INPUT @@ -458,33 +459,11 @@ class StageHandler(Elaboratable): def new_data(self, p, n, 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) - - def elaborate(self, platform): - """ handles case where stage has dynamic ready/valid functions - """ - m = Module() - m.submodules.p = self.p - m.submodules.n = self.n + return (_spec(p.stage.ispec, "%s_i" % name), + _spec(n.stage.ospec, "%s_o" % name)) - if self.stage is not None and hasattr(self.stage, "setup"): - self.stage.setup(m, self.p.data_i) - if not self.p.stage_ctl: - return m - - # intercept the previous (outgoing) "ready", combine with stage ready - m.d.comb += self.p.s_ready_o.eq(self.p._ready_o & self.stage.d_ready) - - # intercept the next (incoming) "ready" and combine it with data valid - sdv = self.stage.d_valid(self.n.ready_i) - m.d.comb += self.n.d_valid.eq(self.n.ready_i & sdv) - - return m - - -class ControlBase(StageHandler): +class ControlBase(StageHandler, Elaboratable): """ Common functions for Pipeline API. Note: a "pipeline stage" only exists (conceptually) when a ControlBase derivative is handed a Stage (combinatorial block) @@ -499,13 +478,22 @@ class ControlBase(StageHandler): * add data_i member to PrevControl (p) and * add data_o member to NextControl (n) """ - self.stage = stage - # set up input and output IO ACK (prev/next ready/valid) self.p = PrevControl(in_multi, stage_ctl) self.n = NextControl(stage_ctl) - StageHandler.__init__(self, self, stage) + self.sh = StageHandler(stage) + if stage is not None: + self.new_data(self, self, "data") + + def new_data(self, p, n, name): + """ allocates new data_i and data_o + """ + self.p.data_i, self.n.data_o = self.sh.new_data(p.sh, n.sh, name) + + @property + def data_r(self): + return self.sh.process(self.p.data_i) def connect_to_next(self, nxt): """ helper function to connect to the next stage data/valid/ready. @@ -582,6 +570,29 @@ class ControlBase(StageHandler): return eqs + def elaborate(self, platform): + """ handles case where stage has dynamic ready/valid functions + """ + m = Module() + m.submodules.p = self.p + m.submodules.n = self.n + + self.sh.setup(m, self.p.data_i) + + if not self.p.stage_ctl: + return m + + stage = self.sh.stage + + # intercept the previous (outgoing) "ready", combine with stage ready + m.d.comb += self.p.s_ready_o.eq(self.p._ready_o & stage.d_ready) + + # intercept the next (incoming) "ready" and combine it with data valid + sdv = stage.d_valid(self.n.ready_i) + m.d.comb += self.n.d_valid.eq(self.n.ready_i & sdv) + + return m + def set_input(self, i): """ helper function to set the input data """ diff --git a/src/add/singlepipe.py b/src/add/singlepipe.py index 5f7dc66b..5be2d919 100644 --- a/src/add/singlepipe.py +++ b/src/add/singlepipe.py @@ -184,8 +184,8 @@ class BufferedHandshake(ControlBase): def elaborate(self, platform): self.m = ControlBase.elaborate(self, platform) - result = _spec(self.stage.ospec, "r_tmp") - r_data = _spec(self.stage.ospec, "r_data") + result = _spec(self.sh.ospec, "r_tmp") + r_data = _spec(self.sh.ospec, "r_data") # establish some combinatorial temporaries o_n_validn = Signal(reset_less=True) @@ -280,7 +280,7 @@ class SimpleHandshake(ControlBase): self.m = m = ControlBase.elaborate(self, platform) r_busy = Signal() - result = _spec(self.stage.ospec, "r_tmp") + result = _spec(self.sh.ospec, "r_tmp") # establish some combinatorial temporaries n_ready_i = Signal(reset_less=True, name="n_i_rdy_data") @@ -388,7 +388,7 @@ class UnbufferedPipeline(ControlBase): self.m = m = ControlBase.elaborate(self, platform) data_valid = Signal() # is data valid or not - r_data = _spec(self.stage.ospec, "r_tmp") # output type + r_data = _spec(self.sh.ospec, "r_tmp") # output type # some temporaries p_valid_i = Signal(reset_less=True) @@ -474,7 +474,7 @@ class UnbufferedPipeline2(ControlBase): self.m = m = ControlBase.elaborate(self, platform) buf_full = Signal() # is data valid or not - buf = _spec(self.stage.ospec, "r_tmp") # output type + buf = _spec(self.sh.ospec, "r_tmp") # output type # some temporaries p_valid_i = Signal(reset_less=True) @@ -543,7 +543,7 @@ class PassThroughHandshake(ControlBase): def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) - r_data = _spec(self.stage.ospec, "r_tmp") # output type + r_data = _spec(self.sh.ospec, "r_tmp") # output type # temporaries p_valid_i = Signal(reset_less=True) @@ -621,7 +621,7 @@ class FIFOControl(ControlBase): m.submodules.fifo = fifo # store result of processing in combinatorial temporary - result = _spec(self.stage.ospec, "r_temp") + result = _spec(self.sh.ospec, "r_temp") m.d.comb += nmoperator.eq(result, self.data_r) # connect previous rdy/valid/data - do cat on data_i diff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py index 7155c908..1408164a 100644 --- a/src/add/test_buf_pipe.py +++ b/src/add/test_buf_pipe.py @@ -635,8 +635,8 @@ class ExampleStageDelayCls(StageCls, Elaboratable): class ExampleBufDelayedPipe(BufferedHandshake): def __init__(self): - stage = ExampleStageDelayCls(valid_trigger=2) - BufferedHandshake.__init__(self, stage, stage_ctl=True) + self.stage = ExampleStageDelayCls(valid_trigger=2) + BufferedHandshake.__init__(self, self.stage, stage_ctl=True) def elaborate(self, platform): m = BufferedHandshake.elaborate(self, platform) @@ -667,8 +667,8 @@ def resultfn_12(data_o, expected, i, o): class ExampleUnBufDelayedPipe(BufferedHandshake): def __init__(self): - stage = ExampleStageDelayCls(valid_trigger=3) - BufferedHandshake.__init__(self, stage, stage_ctl=True) + self.stage = ExampleStageDelayCls(valid_trigger=3) + BufferedHandshake.__init__(self, self.stage, stage_ctl=True) def elaborate(self, platform): m = BufferedHandshake.elaborate(self, platform) -- 2.30.2