From 0fc47b57590d3304a807d63593c2e95aac415469 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 7 Aug 2019 12:26:13 +0100 Subject: [PATCH] route-back experimentation --- src/nmutil/iocontrol.py | 1 + src/nmutil/multipipe.py | 44 +++++++++++------ src/nmutil/test/test_inout_feedback_pipe.py | 53 ++++++++++++--------- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/nmutil/iocontrol.py b/src/nmutil/iocontrol.py index 04e41238..2f8c9ccf 100644 --- a/src/nmutil/iocontrol.py +++ b/src/nmutil/iocontrol.py @@ -298,6 +298,7 @@ class NextControl(Elaboratable): res.append(nxt.stop_i.eq(self.stop_o)) if do_data: res.append(nmoperator.eq(nxt.data_i, self.data_o)) + print ("connect to next", self, self.maskwid, nxt.data_i, do_data, do_stop) return res def _connect_out(self, nxt, direct=False, fn=None, diff --git a/src/nmutil/multipipe.py b/src/nmutil/multipipe.py index c0cc9099..a5655c35 100644 --- a/src/nmutil/multipipe.py +++ b/src/nmutil/multipipe.py @@ -208,27 +208,26 @@ class CombMultiOutPipeline(MultiOutControlBase): p_valid_i = Signal(reset_less=True) pv = Signal(reset_less=True) m.d.comb += p_valid_i.eq(self.p.valid_i_test) - m.d.comb += pv.eq(self.p.valid_i & self.p.ready_o) + m.d.comb += pv.eq(self.p.valid_i) #& self.n[muxid].ready_i) # all outputs to next stages first initialised to zero (invalid) # the only output "active" is then selected by the muxid for i in range(len(self.n)): m.d.comb += self.n[i].valid_o.eq(0) - data_valid = self.n[muxid].valid_o - m.d.comb += self.p.ready_o.eq(~data_valid | self.n[muxid].ready_i) - m.d.comb += data_valid.eq(p_valid_i | \ - (~self.n[muxid].ready_i & data_valid)) + #with m.If(pv): + m.d.comb += self.n[muxid].valid_o.eq(pv) + m.d.comb += self.p.ready_o.eq(self.n[muxid].ready_i) # send data on - with m.If(pv): - m.d.comb += eq(r_data, self.p.data_i) + #with m.If(pv): + m.d.comb += eq(r_data, self.p.data_i) m.d.comb += eq(self.n[muxid].data_o, self.process(r_data)) if self.maskwid: if self.routemask: # straight "routing" mode - treat like data m.d.comb += self.n[muxid].stop_o.eq(self.p.stop_i) - with m.If(pv): - m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i) + #with m.If(pv): + m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i) else: ml = [] # accumulate output masks ms = [] # accumulate output stops @@ -295,6 +294,7 @@ class CombMultiInPipeline(MultiInControlBase): p_valid_i.append(Signal(name="p_valid_i", reset_less=True)) n_ready_in.append(Signal(name="n_ready_in", 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) @@ -305,6 +305,7 @@ class CombMultiInPipeline(MultiInControlBase): 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 += data_valid[i].eq(0) m.d.comb += n_ready_in[i].eq(1) @@ -323,19 +324,26 @@ class CombMultiInPipeline(MultiInControlBase): (n_ready_in[mid] & data_valid[mid])) if self.routemask: - m.d.comb += eq(self.n.stop_o, self.p[mid].stop_i) for i in range(p_len): - m.d.comb += eq(self.n.stop_o, self.p[i].stop_i) + p = self.p[i] vr = Signal(reset_less=True) - m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o) + maskedout = Signal(reset_less=True) + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + m.d.comb += vr.eq(maskedout.bool() & p.valid_i & p.ready_o) with m.If(vr): - m.d.comb += eq(self.n.mask_o, self.p[mid].mask_i) + 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) + m.d.comb += eq(self.n.stop_o, self.p[i].stop_i) else: ml = [] # accumulate output masks ms = [] # accumulate output stops for i in range(p_len): vr = Signal(reset_less=True) - m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o) + p = self.p[i] + vr = Signal(reset_less=True) + maskedout = Signal(reset_less=True) + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + 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: @@ -391,7 +399,13 @@ class InputPriorityArbiter(Elaboratable): in_ready = [] for i in range(self.num_rows): p_valid_i = Signal(reset_less=True) - m.d.comb += p_valid_i.eq(self.pipe.p[i].valid_i_test) + if self.pipe.maskwid and not self.pipe.routemask: + p = self.pipe.p[i] + maskedout = Signal(reset_less=True) + m.d.comb += maskedout.eq(p.mask_i & ~p.stop_i) + m.d.comb += p_valid_i.eq(maskedout.bool() & p.valid_i_test) + else: + m.d.comb += p_valid_i.eq(self.pipe.p[i].valid_i_test) in_ready.append(p_valid_i) m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids" m.d.comb += self.active.eq(~pe.n) # encoder active (one input valid) diff --git a/src/nmutil/test/test_inout_feedback_pipe.py b/src/nmutil/test/test_inout_feedback_pipe.py index 31d051e0..aea582dd 100644 --- a/src/nmutil/test/test_inout_feedback_pipe.py +++ b/src/nmutil/test/test_inout_feedback_pipe.py @@ -8,7 +8,7 @@ from random import randint from math import log -from nmigen import Module, Signal, Cat, Value, Elaboratable +from nmigen import Module, Signal, Cat, Value, Elaboratable, Const from nmigen.compat.sim import run_simulation from nmigen.cli import verilog, rtlil @@ -34,7 +34,7 @@ class PassThroughStage: return PassData() def ospec(self): return self.ispec() # same as ospec - def setup(self, m, i): + def _setup(self, m, i): comb = m.d.comb #comb += self.o.eq(i) def process(self, i): @@ -48,15 +48,15 @@ class SplitRouteStage: def ispec(self): return PassData() def ospec(self): - return self.ispec() # same as ospec + return PassData() def setup(self, m, i): comb = m.d.comb comb += self.o.eq(i) - with m.If(i.operator == 0): - #comb += self.o.routeid.eq(1) # selects 2nd output in CombMuxOutPipe + with m.If(i.operator == Const(1, 2)): + comb += self.o.routeid.eq(1) # selects 2nd output in CombMuxOutPipe comb += self.o.data.eq(i.data + 1) # add 1 to say "we did it" - comb += self.o.operator.eq(1) # don't get into infinite loop + comb += self.o.operator.eq(2) # don't get into infinite loop with m.Else(): comb += self.o.routeid.eq(0) # selects 2nd output in CombMuxOutPipe @@ -64,12 +64,16 @@ class SplitRouteStage: return self.o +class DecisionPipe(MaskCancellable): + def __init__(self, maskwid): + stage = SplitRouteStage() + MaskCancellable.__init__(self, stage, maskwid) + class RouteBackPipe(CombMuxOutPipe): """ routes data back to start of pipeline """ def __init__(self): - self.num_rows = 2 - stage = SplitRouteStage() + stage = PassThroughStage() CombMuxOutPipe.__init__(self, stage, n_len=2, maskwid=4, muxidname="routeid", routemask=True) @@ -79,7 +83,6 @@ class MergeRoutePipe(PriorityCombMuxInPipe): """ merges data coming from end of pipe (with operator now == 1) """ def __init__(self): - self.num_rows = 2 stage = PassThroughStage() PriorityCombMuxInPipe.__init__(self, stage, p_len=2, maskwid=4, routemask=True) @@ -114,6 +117,7 @@ class InputTest: yield rs.data_i.data.eq(op2) yield rs.data_i.idx.eq(i) yield rs.data_i.muxid.eq(muxid) + yield rs.data_i.operator.eq(1) yield rs.mask_i.eq(1) yield o_p_ready = yield rs.ready_o @@ -164,11 +168,11 @@ class InputTest: if len(self.do[muxid]) == 0: break - stall_range = randint(0, 3) - for j in range(randint(1,10)): - stall = randint(0, stall_range) != 0 - yield self.dut.n[0].ready_i.eq(stall) - yield + #stall_range = randint(0, 3) + #for j in range(randint(1,10)): + # stall = randint(0, stall_range) != 0 + # yield self.dut.n[0].ready_i.eq(stall) + # yield n = self.dut.n[muxid] yield n.ready_i.eq(1) @@ -183,7 +187,7 @@ class InputTest: out_i = yield n.data_o.idx out_v = yield n.data_o.data - print ("recv", out_muxid, out_i, hex(out_v), out_v) + print ("recv", out_muxid, out_i, hex(out_v), hex(out_v)) # see if this output has occurred already, delete it if it has assert muxid == out_muxid, \ @@ -193,7 +197,7 @@ class InputTest: continue assert out_i in self.do[muxid], "out_i %d not in array %s" % \ (out_i, repr(self.do[muxid])) - assert self.do[muxid][out_i] == out_v + 1 # check data + assert self.do[muxid][out_i] + 1 == out_v # check data del self.do[muxid][out_i] todel = self.sent[muxid].index(out_i) del self.sent[muxid][todel] @@ -227,11 +231,12 @@ class TestInOutPipe(Elaboratable): self.inpipe = TestPriorityMuxPipe(nr) # fan-in (combinatorial) self.mergein = MergeRoutePipe() # merge in feedback self.pipe1 = PassThroughPipe(nr) # stage 1 (clock-sync) - self.pipe2 = PassThroughPipe(nr) # stage 2 (clock-sync) + self.pipe2 = DecisionPipe(nr) # stage 2 (clock-sync) #self.pipe3 = PassThroughPipe(nr) # stage 3 (clock-sync) #self.pipe4 = PassThroughPipe(nr) # stage 4 (clock-sync) self.splitback = RouteBackPipe() # split back to mergein self.outpipe = TestMuxOutPipe(nr) # fan-out (combinatorial) + self.fifoback = PassThroughPipe(nr) # temp route-back store self.p = self.inpipe.p # kinda annoying, self.n = self.outpipe.n # use pipe in/out as this class in/out @@ -247,14 +252,16 @@ class TestInOutPipe(Elaboratable): #m.submodules.pipe4 = self.pipe4 m.submodules.splitback = self.splitback m.submodules.outpipe = self.outpipe + m.submodules.fifoback = self.fifoback - m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[0]) + m.d.comb += self.inpipe.n.connect_to_next(self.mergein.p[1]) 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.mergein.p[1]) + 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.splitback.n[0].connect_to_next(self.outpipe.p) return m @@ -269,13 +276,13 @@ def test1(): with open("test_inoutmux_feedback_pipe.il", "w") as f: f.write(vl) - tlen = 20 + tlen = 3 test = InputTest(dut, tlen) - run_simulation(dut, [test.rcv(1), test.rcv(0), - test.rcv(3), test.rcv(2), + run_simulation(dut, [test.rcv(0), test.rcv(1), + #test.rcv(3), test.rcv(2), test.send(0), test.send(1), - test.send(3), test.send(2), + #test.send(3), test.send(2), ], vcd_name="test_inoutmux_feedback_pipe.vcd") -- 2.30.2