From 38dbb484c785f8ef5603750e88e8dc6875e6c944 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Tue, 2 Apr 2019 02:44:24 +0100 Subject: [PATCH] pipeline ObjectProxy objects now stored in module, not linked to output yet --- src/add/pipeline.py | 64 +++++++++++++++++++++++++++-------- src/add/pipeline_example.py | 12 +++---- src/add/singlepipe.py | 66 ++++++++++++++++++------------------- src/add/test_buf_pipe.py | 16 ++++----- 4 files changed, 98 insertions(+), 60 deletions(-) diff --git a/src/add/pipeline.py b/src/add/pipeline.py index 1b0a7458..45070322 100644 --- a/src/add/pipeline.py +++ b/src/add/pipeline.py @@ -28,6 +28,16 @@ def like(value, rname, pipe, pipemode=False): reset_less=True) return Signal.like(value, name=rname, reset_less=True) +def get_assigns(_assigns): + assigns = [] + for e in _assigns: + if isinstance(e, ObjectProxy): + assigns += get_assigns(e._assigns) + else: + assigns.append(e) + return assigns + + def get_eqs(_eqs): eqs = [] for e in _eqs: @@ -46,6 +56,7 @@ class ObjectProxy: self.name = name self._pipemode = pipemode self._eqs = [] + self._assigns = [] self._preg_map = {} @classmethod @@ -116,6 +127,9 @@ class ObjectProxy: elif self._m: print ("OP !pipemode assign", new_pipereg, value, type(value)) self._m.d.comb += eq(new_pipereg, value) + else: + print ("OP !pipemode !m", new_pipereg, value, type(value)) + self._assigns += eq(new_pipereg, value) class PipelineStage: @@ -143,6 +157,7 @@ class PipelineStage: print ("make current", self._stagename, m) self._pipemode = pipemode self._eqs = [] + self._assigns = [] def __getattr__(self, name): try: @@ -168,18 +183,28 @@ class PipelineStage: self._preg_map[next_stage][name] = new_pipereg if self._pipemode: self._eqs.append(value) - print ("pipemode: append", new_pipereg, value) + assign = eq(new_pipereg, value) + print ("pipemode: append", new_pipereg, value, assign) + if isinstance(value, ObjectProxy): + print ("OP, assigns:", value._assigns) + self._assigns += value._assigns #self._m.d.comb += assign - else: + self._assigns += assign + elif self._m: print ("!pipemode: assign", new_pipereg, value) assign = eq(new_pipereg, value) self._m.d.sync += assign + else: + print ("!pipemode !m: defer assign", new_pipereg, value) + assign = eq(new_pipereg, value) + self._assigns += assign class AutoStage(StageCls): - def __init__(self, inspecs, outspecs, eqs): - self.inspecs, self.outspecs, self.eqs = inspecs, outspecs, eqs - self.o = self.ospec() + def __init__(self, inspecs, outspecs, eqs, assigns): + self.inspecs, self.outspecs = inspecs, outspecs + self.eqs, self.assigns = eqs, assigns + #self.o = self.ospec() def ispec(self): return self.like(self.inspecs) def ospec(self): return self.like(self.outspecs) def like(self, specs): @@ -190,12 +215,23 @@ class AutoStage(StageCls): def process(self, i): print ("stage process", i) - return self.o + return self.eqs def setup(self, m, i): print ("stage setup", i) - m.d.sync += eq(i, self.eqs) - m.d.comb += eq(self.o, i) + #m.d.comb += eq(self.o, i) + + +class AutoPipe(UnbufferedPipeline): + def __init__(self, stage, assigns): + UnbufferedPipeline.__init__(self, stage) + self.assigns = assigns + + def elaborate(self, platform): + m = UnbufferedPipeline.elaborate(self, platform) + m.d.comb += self.assigns + print ("assigns", self.assigns) + return m class PipeManager: @@ -207,9 +243,9 @@ class PipeManager: @contextmanager def Stage(self, name, prev=None, ispec=None): print ("start stage", name) - stage = PipelineStage(name, self.m, prev, self.pipemode, ispec=ispec) + stage = PipelineStage(name, None, prev, self.pipemode, ispec=ispec) try: - yield stage, stage._m + yield stage, self.m #stage._m finally: pass if self.pipemode: @@ -220,10 +256,12 @@ class PipeManager: inspecs = self.get_specs(stage, name) outspecs = self.get_specs(stage, '__nextstage__', liked=True) eqs = get_eqs(stage._eqs) + assigns = get_assigns(stage._assigns) print ("stage eqs", name, eqs) - s = AutoStage(inspecs, outspecs, eqs) + print ("stage assigns", name, assigns) + s = AutoStage(inspecs, outspecs, eqs, assigns) self.stages.append(s) - print ("end stage", name, "\n") + print ("end stage", name, self.pipemode, "\n") def get_specs(self, stage, name, liked=False): if name in stage._preg_map: @@ -247,7 +285,7 @@ class PipeManager: if self.pipetype == 'buffered': p = BufferedPipeline(s) else: - p = UnbufferedPipeline(s) + p = AutoPipe(s, s.assigns) pipes.append(p) self.m.submodules += p diff --git a/src/add/pipeline_example.py b/src/add/pipeline_example.py index c3e0e328..b84496e7 100644 --- a/src/add/pipeline_example.py +++ b/src/add/pipeline_example.py @@ -119,10 +119,10 @@ class PipelineStageObjectExample: m = Module() - o = ObjectProxy(m, pipemode=False) + o = ObjectProxy(None, pipemode=False) o.a = Signal(4) o.b = Signal(4) - self.obj = o + self._obj = o localv2 = Signal(4) m.d.sync += localv2.eq(localv2 + 3) @@ -133,13 +133,13 @@ class PipelineStageObjectExample: with PipeManager(m, pipemode=True) as pipe: with pipe.Stage("first", - ispec=[self._loopback, self.obj]) as (p, m): + ispec=[self._loopback, self._obj]) as (p, m): p.n = ~self._loopback - p.o = self.obj + p.o = self._obj with pipe.Stage("second", p) as (p, m): #p.n = ~self._loopback + 2 p.n = p.n + Const(2) - o = ObjectProxy(m, pipemode=False) + o = ObjectProxy(None, pipemode=False) o.a = p.n o.b = p.o.b + p.n + Const(5) p.o = o @@ -148,7 +148,7 @@ class PipelineStageObjectExample: localv = Signal(4) m.d.comb += localv.eq(2) p.n = p.n << localv - o = ObjectProxy(m, pipemode=False) + o = ObjectProxy(None, pipemode=False) o.b = p.n + p.o.b + p.o.a p.o = o diff --git a/src/add/singlepipe.py b/src/add/singlepipe.py index 033536a6..c49c3416 100644 --- a/src/add/singlepipe.py +++ b/src/add/singlepipe.py @@ -396,7 +396,6 @@ class ControlBase: * add i_data member to PrevControl (p) and * add o_data member to NextControl (n) """ - # set up input and output IO ACK (prev/next ready/valid) self.p = PrevControl(in_multi) self.n = NextControl() @@ -527,56 +526,57 @@ class BufferedPipeline(ControlBase): self.n.o_data = stage.ospec() def elaborate(self, platform): - m = Module() + + self.m = Module() result = self.stage.ospec() r_data = self.stage.ospec() if hasattr(self.stage, "setup"): - self.stage.setup(m, self.p.i_data) + self.stage.setup(self.m, self.p.i_data) # establish some combinatorial temporaries o_n_validn = Signal(reset_less=True) i_p_valid_o_p_ready = Signal(reset_less=True) p_i_valid = Signal(reset_less=True) - m.d.comb += [p_i_valid.eq(self.p.i_valid_logic()), + self.m.d.comb += [p_i_valid.eq(self.p.i_valid_logic()), o_n_validn.eq(~self.n.o_valid), i_p_valid_o_p_ready.eq(p_i_valid & self.p.o_ready), ] # store result of processing in combinatorial temporary - m.d.comb += eq(result, self.stage.process(self.p.i_data)) + self.m.d.comb += eq(result, self.stage.process(self.p.i_data)) # if not in stall condition, update the temporary register - with m.If(self.p.o_ready): # not stalled - m.d.sync += eq(r_data, result) # update buffer + with self.m.If(self.p.o_ready): # not stalled + self.m.d.sync += eq(r_data, result) # update buffer - with m.If(self.n.i_ready): # next stage is ready - with m.If(self.p.o_ready): # not stalled + with self.m.If(self.n.i_ready): # next stage is ready + with self.m.If(self.p.o_ready): # not stalled # nothing in buffer: send (processed) input direct to output - m.d.sync += [self.n.o_valid.eq(p_i_valid), - eq(self.n.o_data, result), # update output + self.m.d.sync += [self.n.o_valid.eq(p_i_valid), + eq(self.n.o_data, result), # update output ] - with m.Else(): # p.o_ready is false, and something is in buffer. + with self.m.Else(): # p.o_ready is false, and something in buffer # Flush the [already processed] buffer to the output port. - m.d.sync += [self.n.o_valid.eq(1), # declare reg empty - eq(self.n.o_data, r_data), # flush buffer - self.p.o_ready.eq(1), # clear stall condition + self.m.d.sync += [self.n.o_valid.eq(1), # declare reg empty + eq(self.n.o_data, r_data), # flush buffer + self.p.o_ready.eq(1), # clear stall ] # ignore input, since p.o_ready is also false. # (n.i_ready) is false here: next stage is ready - with m.Elif(o_n_validn): # next stage being told "ready" - m.d.sync += [self.n.o_valid.eq(p_i_valid), - self.p.o_ready.eq(1), # Keep the buffer empty - eq(self.n.o_data, result), # set output data + with self.m.Elif(o_n_validn): # next stage being told "ready" + self.m.d.sync += [self.n.o_valid.eq(p_i_valid), + self.p.o_ready.eq(1), # Keep the buffer empty + eq(self.n.o_data, result), # set output data ] # (n.i_ready) false and (n.o_valid) true: - with m.Elif(i_p_valid_o_p_ready): + with self.m.Elif(i_p_valid_o_p_ready): # If next stage *is* ready, and not stalled yet, accept input - m.d.sync += self.p.o_ready.eq(~(p_i_valid & self.n.o_valid)) + self.m.d.sync += self.p.o_ready.eq(~(p_i_valid & self.n.o_valid)) - return m + return self.m class UnbufferedPipeline(ControlBase): @@ -625,27 +625,27 @@ class UnbufferedPipeline(ControlBase): self.n.o_data = stage.ospec() # output type def elaborate(self, platform): - m = Module() + self.m = Module() data_valid = Signal() # is data valid or not r_data = self.stage.ispec() # input type if hasattr(self.stage, "setup"): - self.stage.setup(m, r_data) + self.stage.setup(self.m, r_data) # some temporarie p_i_valid = Signal(reset_less=True) pv = Signal(reset_less=True) - m.d.comb += p_i_valid.eq(self.p.i_valid_logic()) - m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready) + self.m.d.comb += p_i_valid.eq(self.p.i_valid_logic()) + self.m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready) - m.d.comb += self.n.o_valid.eq(data_valid) - m.d.comb += self.p.o_ready.eq(~data_valid | self.n.i_ready) - m.d.sync += data_valid.eq(p_i_valid | \ + self.m.d.comb += self.n.o_valid.eq(data_valid) + self.m.d.comb += self.p.o_ready.eq(~data_valid | self.n.i_ready) + self.m.d.sync += data_valid.eq(p_i_valid | \ (~self.n.i_ready & data_valid)) - with m.If(pv): - m.d.sync += eq(r_data, self.p.i_data) - m.d.comb += eq(self.n.o_data, self.stage.process(r_data)) - return m + with self.m.If(pv): + self.m.d.sync += eq(r_data, self.p.i_data) + self.m.d.comb += eq(self.n.o_data, self.stage.process(r_data)) + return self.m class PassThroughStage(StageCls): diff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py index af725d23..fce4ff67 100644 --- a/src/add/test_buf_pipe.py +++ b/src/add/test_buf_pipe.py @@ -333,14 +333,14 @@ def test9_resultfn(o_data, expected, i, o): class SetLessThan: def __init__(self, width, signed): - self.src1 = Signal((width, signed)) - self.src2 = Signal((width, signed)) - self.output = Signal(width) + self.m = Module() + self.src1 = Signal((width, signed), name="src1") + self.src2 = Signal((width, signed), name="src2") + self.output = Signal(width, name="out") def elaborate(self, platform): - m = Module() - m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0)) - return m + self.m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0)) + return self.m class LTStage(StageCls): @@ -350,10 +350,10 @@ class LTStage(StageCls): self.slt = SetLessThan(16, True) def ispec(self): - return (Signal(16), Signal(16)) + return (Signal(16, name="sig1"), Signal(16, "sig2")) def ospec(self): - return Signal(16) + return Signal(16, "out") def setup(self, m, i): self.o = Signal(16) -- 2.30.2