self.i_valid = Signal(i_width, name="p_i_valid") # prev >>in self
self.o_ready = Signal(name="p_o_ready") # prev <<out self
- def connect_in(self, prev):
+ def _connect_in(self, prev):
""" helper function to connect stage to an input source. do not
use to connect stage-to-stage!
"""
eq(nxt.i_data, self.o_data),
]
- def connect_out(self, nxt):
+ def _connect_out(self, nxt):
""" helper function to connect stage to an output source. do not
use to connect stage-to-stage!
"""
"""
return self.n.connect_to_next(nxt.p)
- def connect_in(self, prev):
+ def _connect_in(self, prev):
""" helper function to connect stage to an input source. do not
use to connect stage-to-stage!
"""
- return self.p.connect_in(prev.p)
+ return self.p._connect_in(prev.p)
- def connect_out(self, nxt):
+ def _connect_out(self, nxt):
""" helper function to connect stage to an output source. do not
use to connect stage-to-stage!
"""
- return self.n.connect_out(nxt.n)
+ return self.n._connect_out(nxt.n)
+
+ def connect(self, m, pipechain):
+ """ connects a chain (list) of Pipeline instances together and
+ links them to this ControlBase instance:
+
+ in <----> self <---> out
+ | ^
+ v |
+ [pipe1, pipe2, pipe3, pipe4]
+ | ^ | ^ | ^
+ v | v | v |
+ out---in out--in out---in
+
+ Also takes care of allocating i_data/o_data, by looking up
+ the data spec for each end of the pipechain.
+
+ Basically this function is the direct equivalent of StageChain,
+ except that unlike StageChain, the Pipeline logic is followed.
+
+ Just as StageChain presents an object that conforms to the
+ Stage API from a list of objects that also conform to the
+ Stage API, an object that calls this Pipeline connect function
+ has the exact same pipeline API as the list of pipline objects
+ it is called with.
+
+ Thus it becomes possible to build up larger chains recursively.
+ More complex chains (multi-input, multi-output) will have to be
+ done manually.
+ """
+ eqs = [] # collated list of assignment statements
+
+ # connect inter-chain
+ for i in range(len(pipechain)-1):
+ pipe1 = pipechain[i]
+ pipe2 = pipechain[i+1]
+ eqs += pipe1.connect_to_next(pipe2)
+
+ # connect front of chain to ourselves
+ front = pipechain[0]
+ self.p.i_data = front.stage.ispec()
+ eqs += front._connect_in(self)
+
+ # connect end of chain to ourselves
+ end = pipechain[-1]
+ self.n.o_data = end.stage.ospec()
+ eqs += end._connect_out(self)
+
+ # activate the assignments
+ m.d.comb += eqs
def set_input(self, i):
""" helper function to set the input data
def __init__(self):
ControlBase.__init__(self)
- # input / output
- self.p.i_data = Signal(32) # >>in - comes in from the PREVIOUS stage
- self.n.o_data = Signal(32) # out>> - goes out to the NEXT stage
-
self.pipe1 = ExampleBufPipe()
self.pipe2 = ExampleBufPipe()
m.submodules.pipe1 = self.pipe1
m.submodules.pipe2 = self.pipe2
- # connect inter-pipe input/output valid/ready/data
- m.d.comb += self.pipe1.connect_to_next(self.pipe2)
-
- # inputs/outputs to the module: pipe1 connections here (LHS)
- m.d.comb += self.pipe1.connect_in(self)
-
- # now pipe2 connections (RHS)
- m.d.comb += self.pipe2.connect_out(self)
+ self.connect(m, [self.pipe1, self.pipe2])
return m
print ("test 2")
dut = ExampleBufPipe2()
run_simulation(dut, testbench2(dut), vcd_name="test_bufpipe2.vcd")
+ ports = [dut.p.i_valid, dut.n.i_ready,
+ dut.n.o_valid, dut.p.o_ready] + \
+ [dut.p.i_data] + [dut.n.o_data]
+ vl = rtlil.convert(dut, ports=ports)
+ with open("test_bufpipe2.il", "w") as f:
+ f.write(vl)
+
print ("test 3")
dut = ExampleBufPipe()