from abc import ABCMeta, abstractmethod
from collections.abc import Sequence
+from queue import Queue
class RecordObject(Record):
return eqs
+ def _postprocess(self, i): # XXX DISABLED
+ return i # RETURNS INPUT
+ if hasattr(self.stage, "postprocess"):
+ return self.stage.postprocess(i)
+ return i
+
def set_input(self, i):
""" helper function to set the input data
"""
# data pass-through conditions
with self.m.If(npnn):
+ o_data = self._postprocess(result)
self.m.d.sync += [self.n.o_valid.eq(p_i_valid), # valid if p_valid
- eq(self.n.o_data, result), # update output
+ eq(self.n.o_data, o_data), # update output
]
# buffer flush conditions (NOTE: can override data passthru conditions)
with self.m.If(nir_por_n): # not stalled
# Flush the [already processed] buffer to the output port.
+ o_data = self._postprocess(r_data)
self.m.d.sync += [self.n.o_valid.eq(1), # reg empty
- eq(self.n.o_data, r_data), # flush buffer
+ eq(self.n.o_data, o_data), # flush buffer
]
# output ready conditions
self.m.d.sync += self.p._o_ready.eq(nir_novn | por_pivn)
# previous valid and ready
with m.If(p_i_valid_p_o_ready):
+ o_data = self._postprocess(result)
m.d.sync += [r_busy.eq(1), # output valid
- eq(self.n.o_data, result), # update output
+ eq(self.n.o_data, o_data), # update output
]
# previous invalid or not ready, however next is accepting
with m.Elif(n_i_ready):
- m.d.sync += [eq(self.n.o_data, result)]
+ o_data = self._postprocess(result)
+ m.d.sync += [eq(self.n.o_data, o_data)]
# TODO: could still send data here (if there was any)
#m.d.sync += self.n.o_valid.eq(0) # ...so set output invalid
m.d.sync += r_busy.eq(0) # ...so set output invalid
with m.If(pv):
m.d.sync += eq(r_data, self.stage.process(self.p.i_data))
- m.d.comb += eq(self.n.o_data, r_data)
+ o_data = self._postprocess(r_data)
+ m.d.comb += eq(self.n.o_data, o_data)
return self.m
-
class UnbufferedPipeline2(ControlBase):
""" A simple pipeline stage with single-clock synchronisation
and two-way valid/ready synchronised signalling.
m.d.comb += self.p._o_ready.eq(~buf_full)
m.d.sync += buf_full.eq(~self.n.i_ready_test & self.n.o_valid)
- odata = Mux(buf_full, buf, self.stage.process(self.p.i_data))
- m.d.comb += eq(self.n.o_data, odata)
+ o_data = Mux(buf_full, buf, self.stage.process(self.p.i_data))
+ o_data = self._postprocess(o_data)
+ m.d.comb += eq(self.n.o_data, o_data)
m.d.sync += eq(buf, self.n.o_data)
return self.m
def elaborate(self, platform):
self.m = m = ControlBase._elaborate(self, platform)
+ r_data = self.stage.ospec() # output type
+
# temporaries
p_i_valid = Signal(reset_less=True)
pvr = Signal(reset_less=True)
m.d.comb += self.p.o_ready.eq(~self.n.o_valid | self.n.i_ready_test)
m.d.sync += self.n.o_valid.eq(p_i_valid | ~self.p.o_ready)
- odata = Mux(pvr, self.stage.process(self.p.i_data), self.n.o_data)
- m.d.sync += eq(self.n.o_data, odata)
+ odata = Mux(pvr, self.stage.process(self.p.i_data), r_data)
+ m.d.sync += eq(r_data, odata)
+ r_data = self._postprocess(r_data)
+ m.d.comb += eq(self.n.o_data, r_data)
return m
i_data -> fifo.din -> FIFO -> fifo.dout -> o_data
"""
- def __init__(self, depth, stage, fwft=True, buffered=False):
+ def __init__(self, depth, stage, in_multi=None, stage_ctl=False,
+ fwft=True, buffered=False, pipe=False):
""" FIFO Control
* depth: number of entries in the FIFO
depth += 1
self.fwft = fwft
self.buffered = buffered
+ self.pipe = pipe
self.fdepth = depth
- ControlBase.__init__(self, stage=stage)
+ ControlBase.__init__(self, stage, in_multi, stage_ctl)
def elaborate(self, platform):
self.m = m = ControlBase._elaborate(self, platform)
if self.buffered:
fifo = SyncFIFOBuffered(fwidth, self.fdepth)
else:
- fifo = SyncFIFO(fwidth, self.fdepth, fwft=self.fwft)
+ fifo = Queue(fwidth, self.fdepth, fwft=self.fwft, pipe=self.pipe)
m.submodules.fifo = fifo
# store result of processing in combinatorial temporary
m.d.comb += connections
else:
m.d.sync += connections # unbuffered fwft mode needs sync
- m.d.comb += flatten(self.n.o_data).eq(fifo.dout)
+ o_data = flatten(self.n.o_data).eq(fifo.dout)
+ o_data = self._postprocess(o_data)
+ m.d.comb += o_data
return m
+
+
+# aka "RegStage".
+class UnbufferedPipeline(FIFOControl):
+ def __init__(self, stage, in_multi=None, stage_ctl=False):
+ FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl,
+ fwft=True, pipe=False)
+
+# aka "BreakReadyStage" XXX had to set fwft=True to get it to work
+class PassThroughHandshake(FIFOControl):
+ def __init__(self, stage, in_multi=None, stage_ctl=False):
+ FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl,
+ fwft=True, pipe=True)
+
+# this is *probably* BufferedHandshake, although test #997 now succeeds.
+class BufferedHandshake(FIFOControl):
+ def __init__(self, stage, in_multi=None, stage_ctl=False):
+ FIFOControl.__init__(self, 2, stage, in_multi, stage_ctl,
+ fwft=True, pipe=False)
+
+
+# this is *probably* SimpleHandshake (note: memory cell size=0)
+class SimpleHandshake(FIFOControl):
+ def __init__(self, stage, in_multi=None, stage_ctl=False):
+ FIFOControl.__init__(self, 0, stage, in_multi, stage_ctl,
+ fwft=True, pipe=False)