X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fnmutil%2Fsinglepipe.py;h=4880a819f22caf361a276083a40e618a9b538383;hb=7ed56e7508dc40ca98f59bd7eccc9402048efd22;hp=7ffd61c9db179ff54218e7b6d6588002ec8e195a;hpb=b68dcaf9245a006bff0d39d922d13a9353e79222;p=ieee754fpu.git diff --git a/src/nmutil/singlepipe.py b/src/nmutil/singlepipe.py index 7ffd61c9..4880a819 100644 --- a/src/nmutil/singlepipe.py +++ b/src/nmutil/singlepipe.py @@ -1,10 +1,20 @@ """ Pipeline API. For multi-input and multi-output variants, see multipipe. Associated development bugs: + * http://bugs.libre-riscv.org/show_bug.cgi?id=148 * http://bugs.libre-riscv.org/show_bug.cgi?id=64 * http://bugs.libre-riscv.org/show_bug.cgi?id=57 - Important: see Stage API (stageapi.py) in combination with below + Important: see Stage API (stageapi.py) and IO Control API + (iocontrol.py) in combination with below. This module + "combines" the Stage API with the IO Control API to create + the Pipeline API. + + The one critically important key difference between StageAPI and + PipelineAPI: + + * StageAPI: combinatorial (NO REGISTERS / LATCHES PERMITTED) + * PipelineAPI: synchronous registers / latches get added here RecordBasedStage: ---------------- @@ -489,11 +499,13 @@ class MaskCancellable(ControlBase): def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) - r_mask = Signal(len(self.p.mask_i), reset_less=True) + mask_r = Signal(len(self.p.mask_i), reset_less=True) + data_r = _spec(self.stage.ospec, "data_r") + m.d.comb += nmoperator.eq(data_r, self._postprocess(self.data_r)) with m.If(self.latchmode): r_busy = Signal() - result = _spec(self.stage.ospec, "r_tmp") + r_latch = _spec(self.stage.ospec, "r_latch") # establish if the data should be passed on. cancellation is # a global signal. @@ -514,26 +526,27 @@ class MaskCancellable(ControlBase): # 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) + m.d.sync += mask_r.eq(Mux(p_valid_i, maskedout, 0)) + m.d.comb += self.n.mask_o.eq(mask_r) # always pass on stop (as combinatorial: single signal) m.d.comb += self.n.stop_o.eq(self.p.stop_i) - data_o = self._postprocess(result) # XXX TBD, does nothing right now + stor = Signal(reset_less=True) + m.d.comb += stor.eq(p_valid_i_p_ready_o | n_ready_i) + with m.If(stor): + # store result of processing in combinatorial temporary + m.d.sync += nmoperator.eq(r_latch, data_r) + # 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)] + # output set combinatorially from latch + m.d.comb += nmoperator.eq(self.n.data_o, r_latch) m.d.comb += self.n.valid_o.eq(r_busy) # if next is ready, so is previous @@ -542,13 +555,14 @@ class MaskCancellable(ControlBase): with m.Else(): # pass everything straight through. p connected to n: data, # valid, mask, everything. this is "effectively" just a - # StageChain (except now dynamically selectable) - data_o = self._postprocess(self.data_r) + # StageChain: MaskCancellable is doing "nothing" except + # combinatorially passing everything through + # (except now it's *dynamically selectable* whether to do that) 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 += nmoperator.eq(self.n.data_o, data_r) return self.m @@ -938,14 +952,14 @@ class FIFOControl(ControlBase): m.submodules.fn = fn = NextControl() fn.valid_o, fn.ready_i, fn.data_o = fifo.readable, fifo.re, fifo.dout connections = fn._connect_out(self.n, fn=nmoperator.cat) + valid_eq, ready_eq, data_o = connections # ok ok so we can't just do the ready/valid eqs straight: # first 2 from connections are the ready/valid, 3rd is data. if self.fwft: - m.d.comb += connections[:2] # combinatorial on next ready/valid + m.d.comb += [valid_eq, ready_eq] # combinatorial on next ready/valid else: - m.d.sync += connections[:2] # non-fwft mode needs sync - data_o = connections[2] # get the data + m.d.sync += [valid_eq, ready_eq] # non-fwft mode needs sync data_o = self._postprocess(data_o) # XXX TBD, does nothing right now m.d.comb += data_o