From 5557cca9eb84ea801ea20feabb5d005e232cb6d9 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 7 Aug 2019 01:15:16 +0100 Subject: [PATCH] respect Ready/Valid signalling (stall capability) in MaskCancellable this will be needed for pipeline bypassing --- src/nmutil/singlepipe.py | 74 ++++++++++++++++++- .../test/test_inout_unary_mux_cancel_pipe.py | 11 +-- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/nmutil/singlepipe.py b/src/nmutil/singlepipe.py index 7f146585..31943f05 100644 --- a/src/nmutil/singlepipe.py +++ b/src/nmutil/singlepipe.py @@ -404,8 +404,11 @@ class BufferedHandshake(ControlBase): return self.m -class MaskCancellable(ControlBase): - """ Mask-activated Cancellable pipeline +class MaskNoDelayCancellable(ControlBase): + """ Mask-activated Cancellable pipeline (that does not respect "ready") + + Based on (identical behaviour to) SimpleHandshake. + TODO: decide whether to merge *into* SimpleHandshake. Argument: stage. see Stage API above @@ -418,7 +421,6 @@ class MaskCancellable(ControlBase): def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False): ControlBase.__init__(self, stage, in_multi, stage_ctl, maskwid) - def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) @@ -455,6 +457,72 @@ class MaskCancellable(ControlBase): return self.m +class MaskCancellable(ControlBase): + """ Mask-activated Cancellable pipeline + + Argument: stage. see Stage API above + + stage-1 p.valid_i >>in stage n.valid_o out>> stage+1 + stage-1 p.ready_o <>in stage n.data_o out>> stage+1 + | | + +--process->--^ + """ + def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False): + ControlBase.__init__(self, stage, in_multi, stage_ctl, maskwid) + + def elaborate(self, platform): + self.m = m = ControlBase.elaborate(self, platform) + + r_busy = Signal() + result = _spec(self.stage.ospec, "r_tmp") + + # establish if the data should be passed on. cancellation is + # a global signal. + p_valid_i = Signal(reset_less=True) + #print ("self.p.data_i", self.p.data_i) + maskedout = Signal(len(self.p.mask_i), reset_less=True) + m.d.comb += maskedout.eq(self.p.mask_i & ~self.p.stop_i) + + # establish some combinatorial temporaries + n_ready_i = Signal(reset_less=True, name="n_i_rdy_data") + p_valid_i_p_ready_o = Signal(reset_less=True) + m.d.comb += [p_valid_i.eq(self.p.valid_i_test & maskedout.bool()), + n_ready_i.eq(self.n.ready_i_test), + p_valid_i_p_ready_o.eq(p_valid_i & self.p.ready_o), + ] + + # store result of processing in combinatorial temporary + m.d.comb += nmoperator.eq(result, self.data_r) + + # if idmask nonzero, mask gets passed on (and register set). + # register is left as-is if idmask is zero, but out-mask is set to zero + # note however: only the *uncancelled* mask bits get passed on + m.d.sync += self.n.mask_o.eq(Mux(p_valid_i, maskedout, 0)) + + # always pass on stop (as combinatorial: single signal) + m.d.comb += self.n.stop_o.eq(self.p.stop_i) + + # previous valid and ready + with m.If(p_valid_i_p_ready_o): + data_o = self._postprocess(result) # XXX TBD, does nothing right now + m.d.sync += [r_busy.eq(1), # output valid + nmoperator.eq(self.n.data_o, data_o), # update output + ] + # previous invalid or not ready, however next is accepting + with m.Elif(n_ready_i): + data_o = self._postprocess(result) # XXX TBD, does nothing right now + m.d.sync += [nmoperator.eq(self.n.data_o, data_o)] + # TODO: could still send data here (if there was any) + #m.d.sync += self.n.valid_o.eq(0) # ...so set output invalid + m.d.sync += r_busy.eq(0) # ...so set output invalid + + m.d.comb += self.n.valid_o.eq(r_busy) + # if next is ready, so is previous + m.d.comb += self.p._ready_o.eq(n_ready_i) + + return self.m + class SimpleHandshake(ControlBase): """ simple handshake control. data and strobe signals travel in sync. diff --git a/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py b/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py index 235eafe3..6a594eb1 100644 --- a/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py +++ b/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py @@ -123,11 +123,12 @@ 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) yield -- 2.30.2