From b9ac5a5e51f895091f8d0109571976b3a241f4ae Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 15 Aug 2019 17:51:20 +0100 Subject: [PATCH] add dynamic comb/sync mode to MaskCancellable --- src/nmutil/multipipe.py | 2 +- src/nmutil/singlepipe.py | 108 ++++++++++++++++++------------- src/nmutil/test/test_buf_pipe.py | 48 +++++++++++++- 3 files changed, 110 insertions(+), 48 deletions(-) diff --git a/src/nmutil/multipipe.py b/src/nmutil/multipipe.py index b6eb0cd7..b4995326 100644 --- a/src/nmutil/multipipe.py +++ b/src/nmutil/multipipe.py @@ -320,7 +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(~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) diff --git a/src/nmutil/singlepipe.py b/src/nmutil/singlepipe.py index ba4acfbe..3a04fbf9 100644 --- a/src/nmutil/singlepipe.py +++ b/src/nmutil/singlepipe.py @@ -469,58 +469,78 @@ class MaskCancellable(ControlBase): | | +--process->--^ """ - def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False): + def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False, + dynamic=False): ControlBase.__init__(self, stage, in_multi, stage_ctl, maskwid) + self.dynamic = dynamic + if dynamic: + self.latchmode = Signal() + else: + self.latchmode = Const(1) 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)) + r_mask = Signal(len(self.p.mask_i), reset_less=True) + + with m.If(self.latchmode): + 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), + ] + + # 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 += r_mask.eq(Mux(p_valid_i, maskedout, 0)) + m.d.comb += self.n.mask_o.eq(r_mask) + + # always pass on stop (as combinatorial: single signal) + m.d.comb += self.n.stop_o.eq(self.p.stop_i) - # 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 + # previous valid and ready + with m.If(p_valid_i_p_ready_o): + # store result of processing in combinatorial temporary + m.d.sync += nmoperator.eq(result, self.data_r) + m.d.sync += r_busy.eq(1) # output valid + # previous invalid or not ready, however next is accepting + with m.Elif(n_ready_i): + # 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.sync += nmoperator.eq(result, self.data_r) + + m.d.comb += [nmoperator.eq(self.n.data_o, data_o)] + + 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) + + with m.Else(): + # pass everything straight through. p connected to n: data, + # valid, mask, everything. + data_o = self._postprocess(self.data_r) + m.d.comb += self.n.valid_o.eq(self.p.valid_i_test) + m.d.comb += self.p._ready_o.eq(self.n.ready_i_test) + m.d.comb += self.n.stop_o.eq(self.p.stop_i) + m.d.comb += self.n.mask_o.eq(self.p.mask_i) + m.d.comb += nmoperator.eq(self.n.data_o, data_o) - 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 diff --git a/src/nmutil/test/test_buf_pipe.py b/src/nmutil/test/test_buf_pipe.py index dcd2b458..d489b652 100644 --- a/src/nmutil/test/test_buf_pipe.py +++ b/src/nmutil/test/test_buf_pipe.py @@ -1130,12 +1130,39 @@ class MaskCancellablePipe(MaskCancellable): """ connects two stages together as a *single* combinatorial stage. """ - def __init__(self): - self.cancelmask = Signal(16) + def __init__(self, dynamic=False): stage1 = ExampleMaskCancellable() stage2 = ExampleMaskCancellable() combined = StageChain([stage1, stage2]) - MaskCancellable.__init__(self, combined, 16) + MaskCancellable.__init__(self, combined, 16, dynamic=dynamic) + + +class MaskCancellablePipe1(MaskCancellable): + + """ connects a stage to a cancellable pipe with "dynamic" mode on. + """ + def __init__(self, dynamic=True): + stage = ExampleMaskCancellable() + MaskCancellable.__init__(self, stage, 16, dynamic=dynamic) + + +class MaskCancellableDynamic(ControlBase): + + def __init__(self): + ControlBase.__init__(self, None, maskwid=16) + + def elaborate(self, platform): + m = ControlBase.elaborate(self, platform) + + pipe1 = MaskCancellablePipe1() + pipe2 = MaskCancellablePipe1() + + m.submodules.pipe1 = pipe1 + m.submodules.pipe2 = pipe2 + + m.d.comb += self.connect([pipe1, pipe2]) + + return m def data_chain0(): @@ -1175,6 +1202,20 @@ def test0(): run_simulation(dut, [test.send, test.rcv], vcd_name="test_maskchain0.vcd") +def test0_1(): + print ("test 0.1") + dut = MaskCancellableDynamic() + ports = [dut.p.valid_i, dut.n.ready_i, + dut.n.valid_o, dut.p.ready_o] #+ \ + #dut.p.data_i.ports() + dut.n.data_o.ports() + vl = rtlil.convert(dut, ports=ports) + with open("test_maskchain0_dynamic.il", "w") as f: + f.write(vl) + data = data_chain0() + test = TestMask(dut, resultfn_0, 16, data=data) + run_simulation(dut, [test.send, test.rcv], + vcd_name="test_maskchain0_dynamic.vcd") + def notworking1(): print ("test 1") dut = ExampleBufPipe() @@ -1494,3 +1535,4 @@ def test999(): if __name__ == '__main__': test0() + test0_1() -- 2.30.2