From f32e08299a545d4a2146ac839aa0eb0a40cf38d6 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 14 Aug 2019 14:39:10 +0100 Subject: [PATCH] debugging feedback pipe --- src/nmutil/multipipe.py | 139 +++++++++++++++++++- src/nmutil/test/test_inout_feedback_pipe.py | 6 +- 2 files changed, 139 insertions(+), 6 deletions(-) diff --git a/src/nmutil/multipipe.py b/src/nmutil/multipipe.py index c63d5e02..b6eb0cd7 100644 --- a/src/nmutil/multipipe.py +++ b/src/nmutil/multipipe.py @@ -39,7 +39,7 @@ class MultiInControlBase(Elaboratable): """ self.routemask = routemask # set up input and output IO ACK (prev/next ready/valid) - print ("multi_in", maskwid, p_len) + print ("multi_in", self, maskwid, p_len, routemask) p = [] for i in range(p_len): p.append(PrevControl(in_multi, maskwid=maskwid)) @@ -48,7 +48,7 @@ class MultiInControlBase(Elaboratable): nmaskwid = maskwid # straight route mask mode else: nmaskwid = maskwid * p_len # fan-in mode - self.n = NextControl(maskwid=maskwid*p_len) # masks fan in (Cat) + self.n = NextControl(maskwid=nmaskwid) # masks fan in (Cat) def connect_to_next(self, nxt, p_idx=0): """ helper function to connect to the next stage data/valid/ready. @@ -204,6 +204,8 @@ class CombMultiOutPipeline(MultiOutControlBase): print ("self.n_mux", self.n_mux) print ("self.n_mux.m_id", self.n_mux.m_id) + self.n_mux.m_id.name = "m_id" + # temporaries p_valid_i = Signal(reset_less=True) pv = Signal(reset_less=True) @@ -318,6 +320,7 @@ class CombMultiInPipeline(MultiInControlBase): m.d.comb += data_valid[i].eq(0) m.d.comb += n_ready_in[i].eq(1) m.d.comb += p_valid_i[i].eq(0) + m.d.comb += self.p[i].ready_o.eq(~data_valid[i] | self.n.ready_i) m.d.comb += self.p[i].ready_o.eq(0) p = self.p[mid] maskedout = Signal(reset_less=True) @@ -339,8 +342,25 @@ class CombMultiInPipeline(MultiInControlBase): if self.routemask: # XXX hack - fixes loop - m.d.comb += eq(self.n.stop_o, self.p[0].stop_i) + m.d.comb += eq(self.n.stop_o, self.p[-1].stop_i) + for i in range(p_len): + p = self.p[i] + vr = Signal(name="vr%d" % i, reset_less=True) + maskedout = Signal(name="maskedout%d" % i, reset_less=True) + if hasattr(p, "mask_i"): + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + else: + m.d.comb += maskedout.eq(1) + m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o) + #m.d.comb += vr.eq(p.valid_i & p.ready_o) + with m.If(vr): + m.d.comb += eq(self.n.mask_o, self.p[i].mask_i) + m.d.comb += eq(r_data[i], self.p[i].data_i) + else: + ml = [] # accumulate output masks + ms = [] # accumulate output stops for i in range(p_len): + vr = Signal(reset_less=True) p = self.p[i] vr = Signal(reset_less=True) maskedout = Signal(reset_less=True) @@ -349,6 +369,119 @@ class CombMultiInPipeline(MultiInControlBase): else: m.d.comb += maskedout.eq(1) m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o) + with m.If(vr): + m.d.comb += eq(r_data[i], self.p[i].data_i) + if self.maskwid: + mlen = len(self.p[i].mask_i) + s = mlen*i + e = mlen*(i+1) + ml.append(Mux(vr, self.p[i].mask_i, Const(0, mlen))) + ms.append(self.p[i].stop_i) + if self.maskwid: + m.d.comb += self.n.mask_o.eq(Cat(*ml)) + m.d.comb += self.n.stop_o.eq(Cat(*ms)) + + m.d.comb += eq(self.n.data_o, self.process(r_data[mid])) + + return m + + +class NonCombMultiInPipeline(MultiInControlBase): + """ A multi-input pipeline block conforming to the Pipeline API + + Attributes: + ----------- + p.data_i : StageInput, shaped according to ispec + The pipeline input + p.data_o : StageOutput, shaped according to ospec + The pipeline output + r_data : input_shape according to ispec + A temporary (buffered) copy of a prior (valid) input. + This is HELD if the output is not ready. It is updated + SYNCHRONOUSLY. + """ + + def __init__(self, stage, p_len, p_mux, maskwid=0, routemask=False): + MultiInControlBase.__init__(self, p_len=p_len, maskwid=maskwid, + routemask=routemask) + self.stage = stage + self.maskwid = maskwid + self.p_mux = p_mux + + # set up the input and output data + for i in range(p_len): + name = 'data_i_%d' % i + self.p[i].data_i = _spec(stage.ispec, name) # input type + self.n.data_o = _spec(stage.ospec, 'data_o') + + def process(self, i): + if hasattr(self.stage, "process"): + return self.stage.process(i) + return i + + def elaborate(self, platform): + m = MultiInControlBase.elaborate(self, platform) + + m.submodules.p_mux = self.p_mux + + # need an array of buffer registers conforming to *input* spec + r_data = [] + r_busy = [] + p_valid_i = [] + p_len = len(self.p) + for i in range(p_len): + name = 'r_%d' % i + r = _spec(self.stage.ispec, name) # input type + r_data.append(r) + r_busy.append(Signal(name="r_busy%d" % i, reset_less=True)) + p_valid_i.append(Signal(name="p_valid_i%d" % i, reset_less=True)) + if hasattr(self.stage, "setup"): + print ("setup", self, self.stage, r) + self.stage.setup(m, r) + if len(r_data) > 1: + r_data = Array(r_data) + p_valid_i = Array(p_valid_i) + r_busy = Array(r_busy) + + nirn = Signal(reset_less=True) + m.d.comb += nirn.eq(~self.n.ready_i) + mid = self.p_mux.m_id + print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len) + for i in range(p_len): + m.d.comb += r_busy[i].eq(0) + m.d.comb += n_ready_in[i].eq(1) + m.d.comb += p_valid_i[i].eq(0) + m.d.comb += self.p[i].ready_o.eq(n_ready_in[i]) + p = self.p[mid] + maskedout = Signal(reset_less=True) + if hasattr(p, "mask_i"): + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + else: + m.d.comb += maskedout.eq(1) + m.d.comb += p_valid_i[mid].eq(maskedout & self.p_mux.active) + m.d.comb += self.p[mid].ready_o.eq(~data_valid[mid] | self.n.ready_i) + m.d.comb += n_ready_in[mid].eq(nirn & data_valid[mid]) + anyvalid = Signal(i, reset_less=True) + av = [] + for i in range(p_len): + av.append(data_valid[i]) + anyvalid = Cat(*av) + m.d.comb += self.n.valid_o.eq(anyvalid.bool()) + m.d.comb += data_valid[mid].eq(p_valid_i[mid] | \ + (n_ready_in[mid] )) + + if self.routemask: + # XXX hack - fixes loop + m.d.comb += eq(self.n.stop_o, self.p[-1].stop_i) + for i in range(p_len): + p = self.p[i] + vr = Signal(name="vr%d" % i, reset_less=True) + maskedout = Signal(name="maskedout%d" % i, reset_less=True) + if hasattr(p, "mask_i"): + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + else: + m.d.comb += maskedout.eq(1) + m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o) #m.d.comb += vr.eq(p.valid_i & p.ready_o) with m.If(vr): m.d.comb += eq(self.n.mask_o, self.p[i].mask_i) diff --git a/src/nmutil/test/test_inout_feedback_pipe.py b/src/nmutil/test/test_inout_feedback_pipe.py index c4f4d07e..60a18616 100644 --- a/src/nmutil/test/test_inout_feedback_pipe.py +++ b/src/nmutil/test/test_inout_feedback_pipe.py @@ -254,14 +254,14 @@ class TestInOutPipe(Elaboratable): m.submodules.outpipe = self.outpipe m.submodules.fifoback = self.fifoback - m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[1]) + m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[0]) m.d.comb += self.mergein.n.connect_to_next(self.pipe1.p) m.d.comb += self.pipe1.connect_to_next(self.pipe2) #m.d.comb += self.pipe2.connect_to_next(self.pipe3) #m.d.comb += self.pipe3.connect_to_next(self.pipe4) m.d.comb += self.pipe2.connect_to_next(self.splitback) m.d.comb += self.splitback.n[1].connect_to_next(self.fifoback.p) - m.d.comb += self.fifoback.n.connect_to_next(self.mergein.p[0]) + m.d.comb += self.fifoback.n.connect_to_next(self.mergein.p[1]) m.d.comb += self.splitback.n[0].connect_to_next(self.outpipe.p) return m @@ -276,7 +276,7 @@ def test1(): with open("test_inoutmux_feedback_pipe.il", "w") as f: f.write(vl) - tlen = 100 + tlen = 5 test = InputTest(dut, tlen) run_simulation(dut, [test.rcv(0), #test.rcv(1), -- 2.30.2