* data_i : an input - MUST be added by the USER of this class
"""
- def __init__(self, i_width=1, stage_ctl=False, maskwid=0):
+ def __init__(self, i_width=1, stage_ctl=False, maskwid=0, offs=0):
self.stage_ctl = stage_ctl
self.maskwid = maskwid
if maskwid:
self.mask_i = Signal(maskwid) # prev >>in self
+ self.stop_i = Signal(maskwid) # prev >>in self
self.valid_i = Signal(i_width, name="p_valid_i") # prev >>in self
self._ready_o = Signal(name="p_ready_o") # prev <<out self
self.data_i = None # XXX MUST BE ADDED BY USER
return self.s_ready_o # set dynamically by stage
return self._ready_o # return this when not under dynamic control
- def _connect_in(self, prev, direct=False, fn=None, do_data=True):
+ def _connect_in(self, prev, direct=False, fn=None,
+ do_data=True, do_stop=True):
""" internal helper function to connect stage to an input source.
do not use to connect stage-to-stage!
"""
prev.ready_o.eq(self.ready_o)]
if self.maskwid:
res.append(self.mask_i.eq(prev.mask_i))
+ if do_stop:
+ res.append(self.stop_i.eq(prev.stop_i))
if do_data is False:
return res
data_i = fn(prev.data_i) if fn is not None else prev.data_i
yield self.ready_o
if self.maskwid:
yield self.mask_i
+ yield self.stop_i
if hasattr(self.data_i, "ports"):
yield from self.data_i.ports()
elif isinstance(self.data_i, Sequence):
self.maskwid = maskwid
if maskwid:
self.mask_o = Signal(maskwid) # self out>> next
+ self.stop_o = Signal(maskwid) # self out>> next
self.valid_o = Signal(name="n_valid_o") # self out>> next
self.ready_i = Signal(name="n_ready_i") # self <<in next
self.data_o = None # XXX MUST BE ADDED BY USER
return self.ready_i & self.d_valid
return self.ready_i
- def connect_to_next(self, nxt, do_data=True):
+ def connect_to_next(self, nxt, do_data=True, do_stop=True):
""" helper function to connect to the next stage data/valid/ready.
data/valid is passed *TO* nxt, and ready comes *IN* from nxt.
use this when connecting stage-to-stage
self.ready_i.eq(nxt.ready_o)]
if self.maskwid:
res.append(nxt.mask_i.eq(self.mask_o))
+ if do_stop:
+ res.append(nxt.stop_i.eq(self.stop_o))
if do_data:
res.append(nmoperator.eq(nxt.data_i, self.data_o))
return res
- def _connect_out(self, nxt, direct=False, fn=None, do_data=True):
+ def _connect_out(self, nxt, direct=False, fn=None,
+ do_data=True, do_stop=True):
""" internal helper function to connect stage to an output source.
do not use to connect stage-to-stage!
"""
self.ready_i.eq(ready_i)]
if self.maskwid:
res.append(nxt.mask_o.eq(self.mask_o))
+ if do_stop:
+ res.append(nxt.stop_o.eq(self.stop_o))
if not do_data:
return res
data_o = fn(nxt.data_o) if fn is not None else nxt.data_o
yield self.valid_o
if self.maskwid:
yield self.mask_o
+ yield self.stop_o
if hasattr(self.data_o, "ports"):
yield from self.data_o.ports()
elif isinstance(self.data_o, Sequence):
class MultiInControlBase(Elaboratable):
""" Common functions for Pipeline API
"""
- def __init__(self, in_multi=None, p_len=1, maskmode=False):
+ def __init__(self, in_multi=None, p_len=1, masklen=0):
""" 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)
+ print ("multi_in", masklen, p_len)
p = []
for i in range(p_len):
- p.append(PrevControl(in_multi, maskwid=maskwid))
+ p.append(PrevControl(in_multi, maskwid=masklen))
self.p = Array(p)
- self.n = NextControl(maskwid=maskwid)
+ self.n = NextControl(maskwid=masklen*p_len)
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, maskmode=False):
+ def __init__(self, n_len=1, in_multi=None, masklen=0):
""" 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)
- maskwid = n_len if maskmode else 0
- self.p = PrevControl(in_multi, maskwid=maskwid)
+ self.p = PrevControl(in_multi, maskwid=masklen*n_len)
n = []
for i in range(n_len):
- n.append(NextControl(maskwid=maskwid))
+ n.append(NextControl(maskwid=masklen))
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, maskmode=False):
- MultiOutControlBase.__init__(self, n_len=n_len, maskmode=maskmode)
+ def __init__(self, stage, n_len, n_mux, masklen=0):
+ MultiOutControlBase.__init__(self, n_len=n_len, masklen=masklen)
self.stage = stage
- self.maskmode = maskmode
+ self.masklen = masklen
self.n_mux = n_mux
# set up the input and output data
m.d.comb += self.p.ready_o.eq(~data_valid | self.n[muxid].ready_i)
m.d.comb += data_valid.eq(p_valid_i | \
(~self.n[muxid].ready_i & data_valid))
+ if self.masklen:
+ ml = [] # accumulate output masks
+ for i in range(len(self.n)):
+ ml.append(self.n[i].mask_o)
+ with m.If(pv):
+ m.d.comb += Cat(*ml).eq(self.p.mask_i)
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, maskmode=False):
- MultiInControlBase.__init__(self, p_len=p_len, maskmode=maskmode)
+ def __init__(self, stage, p_len, p_mux, masklen=0):
+ MultiInControlBase.__init__(self, p_len=p_len, masklen=masklen)
self.stage = stage
- self.maskmode = maskmode
+ self.masklen = masklen
self.p_mux = p_mux
# set up the input and output data
m.d.comb += data_valid[mid].eq(p_valid_i[mid] | \
(n_ready_in[mid] & data_valid[mid]))
+ ml = [] # accumulate output masks
for i in range(p_len):
vr = Signal(reset_less=True)
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)
+ if self.masklen:
+ mlen = len(self.p[i].mask_i)
+ s = mlen*i
+ e = mlen*(i+1)
+ ml.append(Mux(vr, self.p[i].mask_i, Const(0, mlen)))
+ if self.masklen:
+ m.d.comb += self.n.mask_o.eq(Cat(*ml))
m.d.comb += eq(self.n.data_o, self.process(r_data[mid]))
class CombMuxOutPipe(CombMultiOutPipeline):
- def __init__(self, stage, n_len, maskmode=False):
+ def __init__(self, stage, n_len, masklen=0):
# HACK: stage is also the n-way multiplexer
CombMultiOutPipeline.__init__(self, stage, n_len=n_len,
- n_mux=stage, maskmode=maskmode)
+ n_mux=stage, masklen=masklen)
# 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, maskmode=False):
+ def __init__(self, stage, p_len=2, masklen=0):
p_mux = InputPriorityArbiter(self, p_len)
CombMultiInPipeline.__init__(self, stage, p_len, p_mux,
- maskmode=maskmode)
+ masklen=masklen)
if __name__ == '__main__':
# is NOT "normal" for the Stage API.
p_valid_i = Signal(reset_less=True)
#print ("self.p.data_i", self.p.data_i)
- m.d.comb += p_valid_i.eq(((self.p.mask_i & ~self.cancelmask).bool()))
+ m.d.comb += p_valid_i.eq(((self.p.mask_i & ~self.p.stop_i).bool()))
# 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
#m.d.comb += self.p._ready_o.eq(self.n.ready_i_test)
m.d.comb += self.p._ready_o.eq(Const(1))
+ # always pass on stop (as combinatorial: single signal)
+ m.d.comb += self.n.stop_o.eq(self.p.stop_i)
+
return self.m
class PassThroughPipe(MaskCancellable):
- def __init__(self, maskwid, cancelmask):
- self.cancelmask = cancelmask
+ def __init__(self, maskwid):
MaskCancellable.__init__(self, PassThroughStage(), maskwid)
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 rs.mask_i.eq(1)
yield
o_p_ready = yield rs.ready_o
while not o_p_ready:
class TestPriorityMuxPipe(PriorityCombMuxInPipe):
- def __init__(self, num_rows, cancelmask):
+ def __init__(self, num_rows):
self.num_rows = num_rows
- self.cancelmask = cancelmask
stage = PassThroughStage()
PriorityCombMuxInPipe.__init__(self, stage,
- p_len=self.num_rows, maskmode=True)
+ p_len=self.num_rows, masklen=1)
class OutputTest:
class TestMuxOutPipe(CombMuxOutPipe):
- def __init__(self, num_rows, cancelmask):
+ def __init__(self, num_rows):
self.num_rows = num_rows
- self.cancelmask = cancelmask
stage = PassThroughStage()
CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows,
- maskmode=True)
+ masklen=1)
class TestInOutPipe(Elaboratable):
def __init__(self, num_rows=4):
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.inpipe = TestPriorityMuxPipe(nr) # fan-in (combinatorial)
+ self.pipe1 = PassThroughPipe(nr) # stage 1 (clock-sync)
+ self.pipe2 = PassThroughPipe(nr) # stage 2 (clock-sync)
+ self.outpipe = TestMuxOutPipe(nr) # fan-out (combinatorial)
self.p = self.inpipe.p # kinda annoying,
self.n = self.outpipe.n # use pipe in/out as this class in/out