1 """ key strategic example showing how to do multi-input fan-in into a
2 multi-stage pipeline, then multi-output fanout.
4 the multiplex ID from the fan-in is passed in to the pipeline, preserved,
5 and used as a routing ID on the fanout.
8 from random
import randint
10 from nmigen
import Module
, Signal
, Cat
, Value
11 from nmigen
.compat
.sim
import run_simulation
12 from nmigen
.cli
import verilog
, rtlil
14 from multipipe
import CombMultiOutPipeline
15 from multipipe
import CombMultiInPipeline
, InputPriorityArbiter
16 from singlepipe
import UnbufferedPipeline
19 class PriorityUnbufferedPipeline(CombMultiInPipeline
):
20 def __init__(self
, stage
, p_len
):
21 p_mux
= InputPriorityArbiter(self
, p_len
)
22 CombMultiInPipeline
.__init
__(self
, stage
, p_len
=p_len
, p_mux
=p_mux
)
25 return self
.p_mux
.ports()
26 #return UnbufferedPipeline.ports(self) + self.p_mux.ports()
29 class MuxUnbufferedPipeline(CombMultiOutPipeline
):
30 def __init__(self
, stage
, n_len
):
31 # HACK: stage is also the n-way multiplexer
32 CombMultiOutPipeline
.__init
__(self
, stage
, n_len
=n_len
, n_mux
=stage
)
34 # HACK: n-mux is also the stage... so set the muxid equal to input mid
35 stage
.m_id
= self
.p
.i_data
.mid
38 return self
.p_mux
.ports()
41 class PassData
: # (Value):
43 self
.mid
= Signal(2, reset_less
=True)
44 self
.idx
= Signal(8, reset_less
=True)
45 self
.data
= Signal(16, reset_less
=True)
47 def _rhs_signals(self
):
52 for elem_bits
, elem_sign
in (elem
.shape() for elem
in self
.ports()):
53 bits
= max(bits
, elem_bits
+ elem_sign
)
54 sign
= max(sign
, elem_sign
)
58 return [self
.mid
.eq(i
.mid
), self
.idx
.eq(i
.idx
), self
.data
.eq(i
.data
)]
61 return [self
.mid
, self
.idx
, self
.data
]
64 class PassThroughStage
:
68 return self
.ispec() # same as ospec
71 return i
# pass-through
75 class PassThroughPipe(UnbufferedPipeline
):
77 UnbufferedPipeline
.__init
__(self
, PassThroughStage())
81 def __init__(self
, dut
):
86 for mid
in range(dut
.num_rows
):
89 for i
in range(self
.tlen
):
90 self
.di
[mid
][i
] = randint(0, 255) + (mid
<<8)
91 self
.do
[mid
][i
] = self
.di
[mid
][i
]
94 for i
in range(self
.tlen
):
97 yield rs
.i_valid
.eq(1)
98 yield rs
.i_data
.data
.eq(op2
)
99 yield rs
.i_data
.idx
.eq(i
)
100 yield rs
.i_data
.mid
.eq(mid
)
102 o_p_ready
= yield rs
.o_ready
105 o_p_ready
= yield rs
.o_ready
107 print ("send", mid
, i
, hex(op2
))
109 yield rs
.i_valid
.eq(0)
110 # wait random period of time before queueing another value
111 for i
in range(randint(0, 3)):
114 yield rs
.i_valid
.eq(0)
117 print ("send ended", mid
)
119 ## wait random period of time before queueing another value
120 #for i in range(randint(0, 3)):
123 #send_range = randint(0, 3)
127 # send = randint(0, send_range) != 0
131 #stall_range = randint(0, 3)
132 #for j in range(randint(1,10)):
133 # stall = randint(0, stall_range) != 0
134 # yield self.dut.n[0].i_ready.eq(stall)
137 yield n
.i_ready
.eq(1)
139 o_n_valid
= yield n
.o_valid
140 i_n_ready
= yield n
.i_ready
141 if not o_n_valid
or not i_n_ready
:
144 out_mid
= yield n
.o_data
.mid
145 out_i
= yield n
.o_data
.idx
146 out_v
= yield n
.o_data
.data
148 print ("recv", out_mid
, out_i
, hex(out_v
))
150 # see if this output has occurred already, delete it if it has
151 assert mid
== out_mid
, "out_mid %d not correct %d" % (out_mid
, mid
)
152 assert out_i
in self
.do
[mid
], "out_i %d not in array %s" % \
153 (out_i
, repr(self
.do
[mid
]))
154 assert self
.do
[mid
][out_i
] == out_v
# pass-through data
155 del self
.do
[mid
][out_i
]
157 # check if there's any more outputs
158 if len(self
.do
[mid
]) == 0:
160 print ("recv ended", mid
)
163 class TestPriorityMuxPipe(PriorityUnbufferedPipeline
):
164 def __init__(self
, num_rows
):
165 self
.num_rows
= num_rows
166 stage
= PassThroughStage()
167 PriorityUnbufferedPipeline
.__init
__(self
, stage
, p_len
=self
.num_rows
)
171 for i
in range(len(self
.p
)):
172 res
+= [self
.p
[i
].i_valid
, self
.p
[i
].o_ready
] + \
173 self
.p
[i
].i_data
.ports()
174 res
+= [self
.n
.i_ready
, self
.n
.o_valid
] + \
175 self
.n
.o_data
.ports()
181 def __init__(self
, dut
):
186 for i
in range(self
.tlen
* dut
.num_rows
):
190 mid
= randint(0, dut
.num_rows
-1)
191 data
= randint(0, 255) + (mid
<<8)
194 for i
in range(self
.tlen
* dut
.num_rows
):
198 yield rs
.i_valid
.eq(1)
199 yield rs
.i_data
.data
.eq(op2
)
200 yield rs
.i_data
.mid
.eq(mid
)
202 o_p_ready
= yield rs
.o_ready
205 o_p_ready
= yield rs
.o_ready
207 print ("send", mid
, i
, hex(op2
))
209 yield rs
.i_valid
.eq(0)
210 # wait random period of time before queueing another value
211 for i
in range(randint(0, 3)):
214 yield rs
.i_valid
.eq(0)
217 class TestMuxOutPipe(MuxUnbufferedPipeline
):
218 def __init__(self
, num_rows
):
219 self
.num_rows
= num_rows
220 stage
= PassThroughStage()
221 MuxUnbufferedPipeline
.__init
__(self
, stage
, n_len
=self
.num_rows
)
224 res
= [self
.p
.i_valid
, self
.p
.o_ready
] + \
225 self
.p
.i_data
.ports()
226 for i
in range(len(self
.n
)):
227 res
+= [self
.n
[i
].i_ready
, self
.n
[i
].o_valid
] + \
228 self
.n
[i
].o_data
.ports()
233 def __init__(self
, num_rows
=4):
234 self
.num_rows
= num_rows
235 self
.inpipe
= TestPriorityMuxPipe(num_rows
)
236 self
.pipe1
= PassThroughPipe()
237 self
.pipe2
= PassThroughPipe()
238 self
.outpipe
= TestMuxOutPipe(num_rows
)
240 self
.p
= self
.inpipe
.p
241 self
.n
= self
.outpipe
.n
242 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
244 def elaborate(self
, platform
):
246 m
.submodules
.inpipe
= self
.inpipe
247 m
.submodules
.pipe1
= self
.pipe1
248 m
.submodules
.pipe2
= self
.pipe2
249 m
.submodules
.outpipe
= self
.outpipe
251 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.pipe1
.p
)
252 m
.d
.comb
+= self
.pipe1
.connect_to_next(self
.pipe2
)
253 m
.d
.comb
+= self
.pipe1
.connect_to_next(self
.outpipe
)
261 if __name__
== '__main__':
262 dut
= TestInOutPipe()
263 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
264 with
open("test_inoutmux_pipe.il", "w") as f
:
266 #run_simulation(dut, testbench(dut), vcd_name="test_inputgroup.vcd")
268 test
= InputTest(dut
)
269 run_simulation(dut
, [test
.rcv(1), test
.rcv(0),
270 test
.rcv(3), test
.rcv(2),
271 test
.send(0), test
.send(1),
272 test
.send(3), test
.send(2),
274 vcd_name
="test_inoutmux_pipe.vcd")