1 from nmigen
import Module
, Signal
, Mux
2 from nmigen
.hdl
.rec
import Record
3 from nmigen
.compat
.sim
import run_simulation
4 from nmigen
.cli
import verilog
, rtlil
6 from example_buf_pipe
import ExampleBufPipe
, ExampleBufPipeAdd
7 from example_buf_pipe
import ExampleCombPipe
, CombPipe
8 from example_buf_pipe
import PrevControl
, NextControl
, BufferedPipeline
9 from random
import randint
12 def check_o_n_valid(dut
, val
):
13 o_n_valid
= yield dut
.n
.o_valid
14 assert o_n_valid
== val
18 #yield dut.i_p_rst.eq(1)
19 yield dut
.n
.i_ready
.eq(0)
20 yield dut
.p
.o_ready
.eq(0)
23 #yield dut.i_p_rst.eq(0)
24 yield dut
.n
.i_ready
.eq(1)
25 yield dut
.p
.i_data
.eq(5)
26 yield dut
.p
.i_valid
.eq(1)
29 yield dut
.p
.i_data
.eq(7)
30 yield from check_o_n_valid(dut
, 0) # effects of i_p_valid delayed
32 yield from check_o_n_valid(dut
, 1) # ok *now* i_p_valid effect is felt
34 yield dut
.p
.i_data
.eq(2)
36 yield dut
.n
.i_ready
.eq(0) # begin going into "stall" (next stage says ready)
37 yield dut
.p
.i_data
.eq(9)
39 yield dut
.p
.i_valid
.eq(0)
40 yield dut
.p
.i_data
.eq(12)
42 yield dut
.p
.i_data
.eq(32)
43 yield dut
.n
.i_ready
.eq(1)
45 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
47 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
49 yield from check_o_n_valid(dut
, 0) # buffer outputted, *now* we're done.
54 #yield dut.p.i_rst.eq(1)
55 yield dut
.n
.i_ready
.eq(0)
56 #yield dut.p.o_ready.eq(0)
59 #yield dut.p.i_rst.eq(0)
60 yield dut
.n
.i_ready
.eq(1)
61 yield dut
.p
.i_data
.eq(5)
62 yield dut
.p
.i_valid
.eq(1)
65 yield dut
.p
.i_data
.eq(7)
66 yield from check_o_n_valid(dut
, 0) # effects of i_p_valid delayed 2 clocks
68 yield from check_o_n_valid(dut
, 0) # effects of i_p_valid delayed 2 clocks
70 yield dut
.p
.i_data
.eq(2)
72 yield from check_o_n_valid(dut
, 1) # ok *now* i_p_valid effect is felt
73 yield dut
.n
.i_ready
.eq(0) # begin going into "stall" (next stage says ready)
74 yield dut
.p
.i_data
.eq(9)
76 yield dut
.p
.i_valid
.eq(0)
77 yield dut
.p
.i_data
.eq(12)
79 yield dut
.p
.i_data
.eq(32)
80 yield dut
.n
.i_ready
.eq(1)
82 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
84 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
86 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
88 yield from check_o_n_valid(dut
, 0) # buffer outputted, *now* we're done.
95 def __init__(self
, dut
, resultfn
):
97 self
.resultfn
= resultfn
99 for i
in range(num_tests
):
100 #data.append(randint(0, 1<<16-1))
101 self
.data
.append(i
+1)
106 while self
.o
!= len(self
.data
):
107 send_range
= randint(0, 3)
108 for j
in range(randint(1,10)):
112 send
= randint(0, send_range
) != 0
113 o_p_ready
= yield self
.dut
.p
.o_ready
117 if send
and self
.i
!= len(self
.data
):
118 yield self
.dut
.p
.i_valid
.eq(1)
119 yield self
.dut
.p
.i_data
.eq(self
.data
[self
.i
])
122 yield self
.dut
.p
.i_valid
.eq(0)
126 while self
.o
!= len(self
.data
):
127 stall_range
= randint(0, 3)
128 for j
in range(randint(1,10)):
129 stall
= randint(0, stall_range
) != 0
130 yield self
.dut
.n
.i_ready
.eq(stall
)
132 o_n_valid
= yield self
.dut
.n
.o_valid
133 i_n_ready
= yield self
.dut
.n
.i_ready
134 if not o_n_valid
or not i_n_ready
:
136 o_data
= yield self
.dut
.n
.o_data
137 self
.resultfn(o_data
, self
.data
[self
.o
], self
.i
, self
.o
)
139 if self
.o
== len(self
.data
):
142 def test3_resultfn(o_data
, expected
, i
, o
):
143 assert o_data
== expected
+ 1, \
144 "%d-%d data %x not match %x\n" \
145 % (i
, o
, o_data
, expected
)
149 for i
in range(num_tests
):
150 data
.append({'src1': randint(0, 1<<16-1),
151 'src2': randint(0, 1<<16-1)})
156 def __init__(self
, dut
, resultfn
, data
=None):
158 self
.resultfn
= resultfn
163 for i
in range(num_tests
):
164 self
.data
.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
169 while self
.o
!= len(self
.data
):
170 send_range
= randint(0, 3)
171 for j
in range(randint(1,10)):
175 send
= randint(0, send_range
) != 0
176 o_p_ready
= yield self
.dut
.p
.o_ready
180 if send
and self
.i
!= len(self
.data
):
181 yield self
.dut
.p
.i_valid
.eq(1)
182 for v
in self
.dut
.set_input(self
.data
[self
.i
]):
186 yield self
.dut
.p
.i_valid
.eq(0)
190 while self
.o
!= len(self
.data
):
191 stall_range
= randint(0, 3)
192 for j
in range(randint(1,10)):
193 stall
= randint(0, stall_range
) != 0
194 yield self
.dut
.n
.i_ready
.eq(stall
)
196 o_n_valid
= yield self
.dut
.n
.o_valid
197 i_n_ready
= yield self
.dut
.n
.i_ready
198 if not o_n_valid
or not i_n_ready
:
200 if isinstance(self
.dut
.n
.o_data
, Record
):
202 dod
= self
.dut
.n
.o_data
203 for k
, v
in dod
.fields
.items():
206 o_data
= yield self
.dut
.n
.o_data
207 self
.resultfn(o_data
, self
.data
[self
.o
], self
.i
, self
.o
)
209 if self
.o
== len(self
.data
):
212 def test5_resultfn(o_data
, expected
, i
, o
):
213 res
= expected
[0] + expected
[1]
214 assert o_data
== res
, \
215 "%d-%d data %x not match %s\n" \
216 % (i
, o
, o_data
, repr(expected
))
220 for i
in range(num_tests
):
221 #data.append(randint(0, 1<<16-1))
226 stall
= randint(0, 3) != 0
227 send
= randint(0, 5) != 0
228 yield dut
.n
.i_ready
.eq(stall
)
229 o_p_ready
= yield dut
.p
.o_ready
231 if send
and i
!= len(data
):
232 yield dut
.p
.i_valid
.eq(1)
233 yield dut
.p
.i_data
.eq(data
[i
])
236 yield dut
.p
.i_valid
.eq(0)
238 o_n_valid
= yield dut
.n
.o_valid
239 i_n_ready
= yield dut
.n
.i_ready
240 if o_n_valid
and i_n_ready
:
241 o_data
= yield dut
.n
.o_data
242 assert o_data
== data
[o
] + 2, "%d-%d data %x not match %x\n" \
243 % (i
, o
, o_data
, data
[o
])
249 class ExampleBufPipe2
:
251 connect these: ------|---------------|
253 i_p_valid >>in pipe1 o_n_valid out>> i_p_valid >>in pipe2
254 o_p_ready <<out pipe1 i_n_ready <<in o_p_ready <<out pipe2
255 p_i_data >>in pipe1 p_i_data out>> n_o_data >>in pipe2
258 self
.pipe1
= ExampleBufPipe()
259 self
.pipe2
= ExampleBufPipe()
262 self
.p
= PrevControl()
263 self
.p
.i_data
= Signal(32) # >>in - comes in from the PREVIOUS stage
266 self
.n
= NextControl()
267 self
.n
.o_data
= Signal(32) # out>> - goes out to the NEXT stage
269 def elaborate(self
, platform
):
271 m
.submodules
.pipe1
= self
.pipe1
272 m
.submodules
.pipe2
= self
.pipe2
274 # connect inter-pipe input/output valid/ready/data
275 m
.d
.comb
+= self
.pipe1
.connect_to_next(self
.pipe2
)
277 # inputs/outputs to the module: pipe1 connections here (LHS)
278 m
.d
.comb
+= self
.pipe1
.connect_in(self
)
280 # now pipe2 connections (RHS)
281 m
.d
.comb
+= self
.pipe2
.connect_out(self
)
286 def __init__(self
, width
, signed
):
287 self
.src1
= Signal((width
, signed
))
288 self
.src2
= Signal((width
, signed
))
289 self
.output
= Signal(width
)
291 def elaborate(self
, platform
):
293 m
.d
.comb
+= self
.output
.eq(Mux(self
.src1
< self
.src2
, 1, 0))
299 self
.slt
= SetLessThan(16, True)
302 return (Signal(16), Signal(16))
307 def setup(self
, m
, i
):
309 m
.submodules
.slt
= self
.slt
310 m
.d
.comb
+= self
.slt
.src1
.eq(i
[0])
311 m
.d
.comb
+= self
.slt
.src2
.eq(i
[1])
312 m
.d
.comb
+= self
.o
.eq(self
.slt
.output
)
314 def process(self
, i
):
318 class ExampleLTCombPipe(CombPipe
):
319 """ an example of how to use the combinatorial pipeline.
324 CombPipe
.__init
__(self
, stage
)
327 def test6_resultfn(o_data
, expected
, i
, o
):
328 res
= 1 if expected
[0] < expected
[1] else 0
329 assert o_data
== res
, \
330 "%d-%d data %x not match %s\n" \
331 % (i
, o
, o_data
, repr(expected
))
334 class ExampleAddRecordStage
:
335 """ example use of a Record
338 record_spec
= [('src1', 16), ('src2', 16)]
340 """ returns a tuple of input signals which will be the incoming data
342 return Record(self
.record_spec
)
345 return Record(self
.record_spec
)
347 def process(self
, i
):
348 """ process the input data (sums the values in the tuple) and returns it
350 return {'src1': i
.src1
+ 1,
354 class ExampleAddRecordPipe(CombPipe
):
355 """ an example of how to use the combinatorial pipeline.
359 stage
= ExampleAddRecordStage()
360 CombPipe
.__init
__(self
, stage
)
363 def test7_resultfn(o_data
, expected
, i
, o
):
364 res
= (expected
['src1'] + 1, expected
['src2'] + 1)
365 assert o_data
['src1'] == res
[0] and o_data
['src2'] == res
[1], \
366 "%d-%d data %s not match %s\n" \
367 % (i
, o
, repr(o_data
), repr(expected
))
370 class Example2OpClass
:
371 """ an example of a class used to store 2 operands.
372 requires an eq function, to conform with the pipeline stage API
376 self
.op1
= Signal(16)
377 self
.op2
= Signal(16)
380 return [self
.op1
.eq(i
.op1
), self
.op2
.eq(i
.op2
)]
383 class ExampleAddClassStage
:
384 """ an example of how to use the buffered pipeline, as a class instance
388 """ returns an instance of an Example2OpClass.
390 return Example2OpClass()
393 """ returns an output signal which will happen to contain the sum
398 def process(self
, i
):
399 """ process the input data (sums the values in the tuple) and returns it
404 class ExampleBufPipeAddClass(BufferedPipeline
):
405 """ an example of how to use the buffered pipeline, using a class instance
409 addstage
= ExampleAddClassStage()
410 BufferedPipeline
.__init
__(self
, addstage
)
414 def __init__(self
, op1
, op2
):
419 def test8_resultfn(o_data
, expected
, i
, o
):
420 res
= expected
.op1
+ expected
.op2
421 assert o_data
== res
, \
422 "%d-%d data %x not match %s\n" \
423 % (i
, o
, o_data
, repr(expected
))
427 for i
in range(num_tests
):
428 data
.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
434 if __name__
== '__main__':
436 dut
= ExampleBufPipe()
437 run_simulation(dut
, testbench(dut
), vcd_name
="test_bufpipe.vcd")
440 dut
= ExampleBufPipe2()
441 run_simulation(dut
, testbench2(dut
), vcd_name
="test_bufpipe2.vcd")
444 dut
= ExampleBufPipe()
445 test
= Test3(dut
, test3_resultfn
)
446 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
449 dut
= ExampleCombPipe()
450 test
= Test3(dut
, test3_resultfn
)
451 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
454 dut
= ExampleBufPipe2()
455 run_simulation(dut
, testbench4(dut
), vcd_name
="test_bufpipe4.vcd")
458 dut
= ExampleBufPipeAdd()
459 test
= Test5(dut
, test5_resultfn
)
460 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe5.vcd")
463 dut
= ExampleLTCombPipe()
464 test
= Test5(dut
, test6_resultfn
)
465 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
467 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
468 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
469 list(dut
.p
.i_data
) + [dut
.n
.o_data
]
470 vl
= rtlil
.convert(dut
, ports
=ports
)
471 with
open("test_ltcomb_pipe.il", "w") as f
:
475 dut
= ExampleAddRecordPipe()
477 test
= Test5(dut
, test7_resultfn
, data
=data
)
478 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
480 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
481 dut
.n
.o_valid
, dut
.p
.o_ready
,
482 dut
.p
.i_data
.src1
, dut
.p
.i_data
.src2
,
483 dut
.n
.o_data
.src1
, dut
.n
.o_data
.src2
]
484 vl
= rtlil
.convert(dut
, ports
=ports
)
485 with
open("test_recordcomb_pipe.il", "w") as f
:
489 dut
= ExampleBufPipeAddClass()
491 test
= Test5(dut
, test8_resultfn
, data
=data
)
492 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")