class MultiInControlBase(Elaboratable):
""" Common functions for Pipeline API
"""
- def __init__(self, in_multi=None, p_len=1):
+ def __init__(self, in_multi=None, p_len=1, maskmode=False):
""" Multi-input Control class. Conforms to same API as ControlBase...
mostly. has additional indices to the *multiple* input stages
* add data_o member to NextControl
"""
# set up input and output IO ACK (prev/next ready/valid)
+ maskwid = p_len if maskmode else 0
+ print ("multi_in", maskwid, maskmode, p_len)
p = []
for i in range(p_len):
- p.append(PrevControl(in_multi))
+ p.append(PrevControl(in_multi, maskwid=maskwid))
self.p = Array(p)
- self.n = NextControl()
+ self.n = NextControl(maskwid=maskwid)
def connect_to_next(self, nxt, p_idx=0):
""" helper function to connect to the next stage data/valid/ready.
class MultiOutControlBase(Elaboratable):
""" Common functions for Pipeline API
"""
- def __init__(self, n_len=1, in_multi=None):
+ def __init__(self, n_len=1, in_multi=None, maskmode=False):
""" Multi-output Control class. Conforms to same API as ControlBase...
mostly. has additional indices to the multiple *output* stages
[MultiInControlBase has multiple *input* stages]
"""
# set up input and output IO ACK (prev/next ready/valid)
- self.p = PrevControl(in_multi)
+ maskwid = n_len if maskmode else 0
+ self.p = PrevControl(in_multi, maskwid=maskwid)
n = []
for i in range(n_len):
- n.append(NextControl())
+ n.append(NextControl(maskwid=maskwid))
self.n = Array(n)
def connect_to_next(self, nxt, n_idx=0):
n.data_o : stage output data array. shaped according to ospec
"""
- def __init__(self, stage, n_len, n_mux):
- MultiOutControlBase.__init__(self, n_len=n_len)
+ def __init__(self, stage, n_len, n_mux, maskmode=False):
+ MultiOutControlBase.__init__(self, n_len=n_len, maskmode=maskmode)
self.stage = stage
+ self.maskmode = maskmode
self.n_mux = n_mux
# set up the input and output data
m.d.comb += data_valid.eq(p_valid_i | \
(~self.n[muxid].ready_i & data_valid))
with m.If(pv):
+ if self.maskmode:
+ m.d.comb += self.n[muxid].mask_o.eq(self.p.mask_i)
m.d.comb += eq(r_data, self.p.data_i)
m.d.comb += eq(self.n[muxid].data_o, self.process(r_data))
SYNCHRONOUSLY.
"""
- def __init__(self, stage, p_len, p_mux):
- MultiInControlBase.__init__(self, p_len=p_len)
+ def __init__(self, stage, p_len, p_mux, maskmode=False):
+ MultiInControlBase.__init__(self, p_len=p_len, maskmode=maskmode)
self.stage = stage
+ self.maskmode = maskmode
self.p_mux = p_mux
# set up the input and output data
m.d.comb += vr.eq(self.p[i].valid_i & self.p[i].ready_o)
with m.If(vr):
m.d.comb += eq(r_data[i], self.p[i].data_i)
+ if self.maskmode:
+ m.d.comb += self.n.mask_o.eq(self.p[i].mask_i)
m.d.comb += eq(self.n.data_o, self.process(r_data[mid]))
class CombMuxOutPipe(CombMultiOutPipeline):
- def __init__(self, stage, n_len):
+ def __init__(self, stage, n_len, maskmode=False):
# HACK: stage is also the n-way multiplexer
- CombMultiOutPipeline.__init__(self, stage, n_len=n_len, n_mux=stage)
+ CombMultiOutPipeline.__init__(self, stage, n_len=n_len,
+ n_mux=stage, maskmode=maskmode)
# HACK: n-mux is also the stage... so set the muxid equal to input muxid
print ("combmuxout", self.p.data_i.muxid)
""" an example of how to use the combinatorial pipeline.
"""
- def __init__(self, stage, p_len=2):
+ def __init__(self, stage, p_len=2, maskmode=False):
p_mux = InputPriorityArbiter(self, p_len)
- CombMultiInPipeline.__init__(self, stage, p_len, p_mux)
+ CombMultiInPipeline.__init__(self, stage, p_len, p_mux,
+ maskmode=maskmode)
if __name__ == '__main__':
""" key strategic example showing how to do multi-input fan-in into a
- multi-stage pipeline, then multi-output fanout.
+ multi-stage pipeline, then multi-output fanout, with an unary muxid
+ and cancellation
the multiplex ID from the fan-in is passed in to the pipeline, preserved,
and used as a routing ID on the fanout.
from nmutil.multipipe import CombMultiOutPipeline, CombMuxOutPipe
from nmutil.multipipe import PriorityCombMuxInPipe
-from nmutil.singlepipe import SimpleHandshake, RecordObject, Object
+from nmutil.singlepipe import MaskCancellable, RecordObject, Object
class PassData2(RecordObject):
-class PassThroughPipe(SimpleHandshake):
- def __init__(self):
- SimpleHandshake.__init__(self, PassThroughStage())
+class PassThroughPipe(MaskCancellable):
+ def __init__(self, maskwid, cancelmask):
+ self.cancelmask = cancelmask
+ MaskCancellable.__init__(self, PassThroughStage(), maskwid)
class InputTest:
self.dut = dut
self.di = {}
self.do = {}
- self.tlen = 100
+ self.tlen = 10
for muxid in range(dut.num_rows):
self.di[muxid] = {}
self.do[muxid] = {}
yield rs.data_i.data.eq(op2)
yield rs.data_i.idx.eq(i)
yield rs.data_i.muxid.eq(muxid)
+ yield rs.mask_i.eq(1<<muxid)
yield
o_p_ready = yield rs.ready_o
while not o_p_ready:
class TestPriorityMuxPipe(PriorityCombMuxInPipe):
- def __init__(self, num_rows):
+ def __init__(self, num_rows, cancelmask):
self.num_rows = num_rows
+ self.cancelmask = cancelmask
stage = PassThroughStage()
- PriorityCombMuxInPipe.__init__(self, stage, p_len=self.num_rows)
+ PriorityCombMuxInPipe.__init__(self, stage,
+ p_len=self.num_rows, maskmode=True)
class OutputTest:
self.dut = dut
self.di = []
self.do = {}
- self.tlen = 100
+ self.tlen = 10
for i in range(self.tlen * dut.num_rows):
if i < dut.num_rows:
muxid = i
class TestMuxOutPipe(CombMuxOutPipe):
- def __init__(self, num_rows):
+ def __init__(self, num_rows, cancelmask):
self.num_rows = num_rows
+ self.cancelmask = cancelmask
stage = PassThroughStage()
- CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows)
+ CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows,
+ maskmode=True)
class TestInOutPipe(Elaboratable):
def __init__(self, num_rows=4):
- self.num_rows = num_rows
- self.inpipe = TestPriorityMuxPipe(num_rows) # fan-in (combinatorial)
- self.pipe1 = PassThroughPipe() # stage 1 (clock-sync)
- self.pipe2 = PassThroughPipe() # stage 2 (clock-sync)
- self.outpipe = TestMuxOutPipe(num_rows) # fan-out (combinatorial)
+ self.num_rows = nr = num_rows
+ self.cancelmask = cm = Signal(nr) # cancellation mask
+ self.inpipe = TestPriorityMuxPipe(nr, cm) # fan-in (combinatorial)
+ self.pipe1 = PassThroughPipe(nr, cm) # stage 1 (clock-sync)
+ self.pipe2 = PassThroughPipe(nr, cm) # stage 2 (clock-sync)
+ self.outpipe = TestMuxOutPipe(nr, cm) # fan-out (combinatorial)
self.p = self.inpipe.p # kinda annoying,
self.n = self.outpipe.n # use pipe in/out as this class in/out