reset_less=True)
return Signal.like(value, name=rname, reset_less=True)
+def get_assigns(_assigns):
+ assigns = []
+ for e in _assigns:
+ if isinstance(e, ObjectProxy):
+ assigns += get_assigns(e._assigns)
+ else:
+ assigns.append(e)
+ return assigns
+
+
def get_eqs(_eqs):
eqs = []
for e in _eqs:
self.name = name
self._pipemode = pipemode
self._eqs = []
+ self._assigns = []
self._preg_map = {}
@classmethod
elif self._m:
print ("OP !pipemode assign", new_pipereg, value, type(value))
self._m.d.comb += eq(new_pipereg, value)
+ else:
+ print ("OP !pipemode !m", new_pipereg, value, type(value))
+ self._assigns += eq(new_pipereg, value)
class PipelineStage:
print ("make current", self._stagename, m)
self._pipemode = pipemode
self._eqs = []
+ self._assigns = []
def __getattr__(self, name):
try:
self._preg_map[next_stage][name] = new_pipereg
if self._pipemode:
self._eqs.append(value)
- print ("pipemode: append", new_pipereg, value)
+ assign = eq(new_pipereg, value)
+ print ("pipemode: append", new_pipereg, value, assign)
+ if isinstance(value, ObjectProxy):
+ print ("OP, assigns:", value._assigns)
+ self._assigns += value._assigns
#self._m.d.comb += assign
- else:
+ self._assigns += assign
+ elif self._m:
print ("!pipemode: assign", new_pipereg, value)
assign = eq(new_pipereg, value)
self._m.d.sync += assign
+ else:
+ print ("!pipemode !m: defer assign", new_pipereg, value)
+ assign = eq(new_pipereg, value)
+ self._assigns += assign
class AutoStage(StageCls):
- def __init__(self, inspecs, outspecs, eqs):
- self.inspecs, self.outspecs, self.eqs = inspecs, outspecs, eqs
- self.o = self.ospec()
+ def __init__(self, inspecs, outspecs, eqs, assigns):
+ self.inspecs, self.outspecs = inspecs, outspecs
+ self.eqs, self.assigns = eqs, assigns
+ #self.o = self.ospec()
def ispec(self): return self.like(self.inspecs)
def ospec(self): return self.like(self.outspecs)
def like(self, specs):
def process(self, i):
print ("stage process", i)
- return self.o
+ return self.eqs
def setup(self, m, i):
print ("stage setup", i)
- m.d.sync += eq(i, self.eqs)
- m.d.comb += eq(self.o, i)
+ #m.d.comb += eq(self.o, i)
+
+
+class AutoPipe(UnbufferedPipeline):
+ def __init__(self, stage, assigns):
+ UnbufferedPipeline.__init__(self, stage)
+ self.assigns = assigns
+
+ def elaborate(self, platform):
+ m = UnbufferedPipeline.elaborate(self, platform)
+ m.d.comb += self.assigns
+ print ("assigns", self.assigns)
+ return m
class PipeManager:
@contextmanager
def Stage(self, name, prev=None, ispec=None):
print ("start stage", name)
- stage = PipelineStage(name, self.m, prev, self.pipemode, ispec=ispec)
+ stage = PipelineStage(name, None, prev, self.pipemode, ispec=ispec)
try:
- yield stage, stage._m
+ yield stage, self.m #stage._m
finally:
pass
if self.pipemode:
inspecs = self.get_specs(stage, name)
outspecs = self.get_specs(stage, '__nextstage__', liked=True)
eqs = get_eqs(stage._eqs)
+ assigns = get_assigns(stage._assigns)
print ("stage eqs", name, eqs)
- s = AutoStage(inspecs, outspecs, eqs)
+ print ("stage assigns", name, assigns)
+ s = AutoStage(inspecs, outspecs, eqs, assigns)
self.stages.append(s)
- print ("end stage", name, "\n")
+ print ("end stage", name, self.pipemode, "\n")
def get_specs(self, stage, name, liked=False):
if name in stage._preg_map:
if self.pipetype == 'buffered':
p = BufferedPipeline(s)
else:
- p = UnbufferedPipeline(s)
+ p = AutoPipe(s, s.assigns)
pipes.append(p)
self.m.submodules += p
m = Module()
- o = ObjectProxy(m, pipemode=False)
+ o = ObjectProxy(None, pipemode=False)
o.a = Signal(4)
o.b = Signal(4)
- self.obj = o
+ self._obj = o
localv2 = Signal(4)
m.d.sync += localv2.eq(localv2 + 3)
with PipeManager(m, pipemode=True) as pipe:
with pipe.Stage("first",
- ispec=[self._loopback, self.obj]) as (p, m):
+ ispec=[self._loopback, self._obj]) as (p, m):
p.n = ~self._loopback
- p.o = self.obj
+ p.o = self._obj
with pipe.Stage("second", p) as (p, m):
#p.n = ~self._loopback + 2
p.n = p.n + Const(2)
- o = ObjectProxy(m, pipemode=False)
+ o = ObjectProxy(None, pipemode=False)
o.a = p.n
o.b = p.o.b + p.n + Const(5)
p.o = o
localv = Signal(4)
m.d.comb += localv.eq(2)
p.n = p.n << localv
- o = ObjectProxy(m, pipemode=False)
+ o = ObjectProxy(None, pipemode=False)
o.b = p.n + p.o.b + p.o.a
p.o = o
* add i_data member to PrevControl (p) and
* add o_data member to NextControl (n)
"""
-
# set up input and output IO ACK (prev/next ready/valid)
self.p = PrevControl(in_multi)
self.n = NextControl()
self.n.o_data = stage.ospec()
def elaborate(self, platform):
- m = Module()
+
+ self.m = Module()
result = self.stage.ospec()
r_data = self.stage.ospec()
if hasattr(self.stage, "setup"):
- self.stage.setup(m, self.p.i_data)
+ self.stage.setup(self.m, self.p.i_data)
# establish some combinatorial temporaries
o_n_validn = Signal(reset_less=True)
i_p_valid_o_p_ready = Signal(reset_less=True)
p_i_valid = Signal(reset_less=True)
- m.d.comb += [p_i_valid.eq(self.p.i_valid_logic()),
+ self.m.d.comb += [p_i_valid.eq(self.p.i_valid_logic()),
o_n_validn.eq(~self.n.o_valid),
i_p_valid_o_p_ready.eq(p_i_valid & self.p.o_ready),
]
# store result of processing in combinatorial temporary
- m.d.comb += eq(result, self.stage.process(self.p.i_data))
+ self.m.d.comb += eq(result, self.stage.process(self.p.i_data))
# if not in stall condition, update the temporary register
- with m.If(self.p.o_ready): # not stalled
- m.d.sync += eq(r_data, result) # update buffer
+ with self.m.If(self.p.o_ready): # not stalled
+ self.m.d.sync += eq(r_data, result) # update buffer
- with m.If(self.n.i_ready): # next stage is ready
- with m.If(self.p.o_ready): # not stalled
+ with self.m.If(self.n.i_ready): # next stage is ready
+ with self.m.If(self.p.o_ready): # not stalled
# nothing in buffer: send (processed) input direct to output
- m.d.sync += [self.n.o_valid.eq(p_i_valid),
- eq(self.n.o_data, result), # update output
+ self.m.d.sync += [self.n.o_valid.eq(p_i_valid),
+ eq(self.n.o_data, result), # update output
]
- with m.Else(): # p.o_ready is false, and something is in buffer.
+ with self.m.Else(): # p.o_ready is false, and something in buffer
# Flush the [already processed] buffer to the output port.
- m.d.sync += [self.n.o_valid.eq(1), # declare reg empty
- eq(self.n.o_data, r_data), # flush buffer
- self.p.o_ready.eq(1), # clear stall condition
+ self.m.d.sync += [self.n.o_valid.eq(1), # declare reg empty
+ eq(self.n.o_data, r_data), # flush buffer
+ self.p.o_ready.eq(1), # clear stall
]
# ignore input, since p.o_ready is also false.
# (n.i_ready) is false here: next stage is ready
- with m.Elif(o_n_validn): # next stage being told "ready"
- m.d.sync += [self.n.o_valid.eq(p_i_valid),
- self.p.o_ready.eq(1), # Keep the buffer empty
- eq(self.n.o_data, result), # set output data
+ with self.m.Elif(o_n_validn): # next stage being told "ready"
+ self.m.d.sync += [self.n.o_valid.eq(p_i_valid),
+ self.p.o_ready.eq(1), # Keep the buffer empty
+ eq(self.n.o_data, result), # set output data
]
# (n.i_ready) false and (n.o_valid) true:
- with m.Elif(i_p_valid_o_p_ready):
+ with self.m.Elif(i_p_valid_o_p_ready):
# If next stage *is* ready, and not stalled yet, accept input
- m.d.sync += self.p.o_ready.eq(~(p_i_valid & self.n.o_valid))
+ self.m.d.sync += self.p.o_ready.eq(~(p_i_valid & self.n.o_valid))
- return m
+ return self.m
class UnbufferedPipeline(ControlBase):
self.n.o_data = stage.ospec() # output type
def elaborate(self, platform):
- m = Module()
+ self.m = Module()
data_valid = Signal() # is data valid or not
r_data = self.stage.ispec() # input type
if hasattr(self.stage, "setup"):
- self.stage.setup(m, r_data)
+ self.stage.setup(self.m, r_data)
# some temporarie
p_i_valid = Signal(reset_less=True)
pv = Signal(reset_less=True)
- m.d.comb += p_i_valid.eq(self.p.i_valid_logic())
- m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready)
+ self.m.d.comb += p_i_valid.eq(self.p.i_valid_logic())
+ self.m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready)
- m.d.comb += self.n.o_valid.eq(data_valid)
- m.d.comb += self.p.o_ready.eq(~data_valid | self.n.i_ready)
- m.d.sync += data_valid.eq(p_i_valid | \
+ self.m.d.comb += self.n.o_valid.eq(data_valid)
+ self.m.d.comb += self.p.o_ready.eq(~data_valid | self.n.i_ready)
+ self.m.d.sync += data_valid.eq(p_i_valid | \
(~self.n.i_ready & data_valid))
- with m.If(pv):
- m.d.sync += eq(r_data, self.p.i_data)
- m.d.comb += eq(self.n.o_data, self.stage.process(r_data))
- return m
+ with self.m.If(pv):
+ self.m.d.sync += eq(r_data, self.p.i_data)
+ self.m.d.comb += eq(self.n.o_data, self.stage.process(r_data))
+ return self.m
class PassThroughStage(StageCls):
class SetLessThan:
def __init__(self, width, signed):
- self.src1 = Signal((width, signed))
- self.src2 = Signal((width, signed))
- self.output = Signal(width)
+ self.m = Module()
+ self.src1 = Signal((width, signed), name="src1")
+ self.src2 = Signal((width, signed), name="src2")
+ self.output = Signal(width, name="out")
def elaborate(self, platform):
- m = Module()
- m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0))
- return m
+ self.m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0))
+ return self.m
class LTStage(StageCls):
self.slt = SetLessThan(16, True)
def ispec(self):
- return (Signal(16), Signal(16))
+ return (Signal(16, name="sig1"), Signal(16, "sig2"))
def ospec(self):
- return Signal(16)
+ return Signal(16, "out")
def setup(self, m, i):
self.o = Signal(16)