pass in flatten/processing function into _connect_in/out
[ieee754fpu.git] / src / add / test_buf_pipe.py
1 """ Unit tests for Buffered and Unbuffered pipelines
2
3 contains useful worked examples of how to use the Pipeline API,
4 including:
5
6 * Combinatorial Stage "Chaining"
7 * class-based data stages
8 * nmigen module-based data stages
9 * special nmigen module-based data stage, where the stage *is* the module
10 * Record-based data stages
11 * static-class data stages
12 * multi-stage pipelines (and how to connect them)
13 * how to *use* the pipelines (see Test5) - how to get data in and out
14
15 """
16
17 from nmigen import Module, Signal, Mux, Const
18 from nmigen.hdl.rec import Record
19 from nmigen.compat.sim import run_simulation
20 from nmigen.cli import verilog, rtlil
21
22 from example_buf_pipe import ExampleBufPipe, ExampleBufPipeAdd
23 from example_buf_pipe import ExamplePipeline, UnbufferedPipeline
24 from example_buf_pipe import ExampleStageCls
25 from example_buf_pipe import PrevControl, NextControl, BufferedHandshake
26 from example_buf_pipe import StageChain, ControlBase, StageCls
27 from singlepipe import UnbufferedPipeline2
28 from singlepipe import SimpleHandshake
29 from singlepipe import PassThroughHandshake
30 from singlepipe import PassThroughStage
31 from singlepipe import FIFOtest
32
33 from random import randint, seed
34
35 #seed(4)
36
37
38 def check_o_n_valid(dut, val):
39 o_n_valid = yield dut.n.o_valid
40 assert o_n_valid == val
41
42 def check_o_n_valid2(dut, val):
43 o_n_valid = yield dut.n.o_valid
44 assert o_n_valid == val
45
46
47 def testbench(dut):
48 #yield dut.i_p_rst.eq(1)
49 yield dut.n.i_ready.eq(0)
50 yield dut.p.o_ready.eq(0)
51 yield
52 yield
53 #yield dut.i_p_rst.eq(0)
54 yield dut.n.i_ready.eq(1)
55 yield dut.p.i_data.eq(5)
56 yield dut.p.i_valid.eq(1)
57 yield
58
59 yield dut.p.i_data.eq(7)
60 yield from check_o_n_valid(dut, 0) # effects of i_p_valid delayed
61 yield
62 yield from check_o_n_valid(dut, 1) # ok *now* i_p_valid effect is felt
63
64 yield dut.p.i_data.eq(2)
65 yield
66 yield dut.n.i_ready.eq(0) # begin going into "stall" (next stage says ready)
67 yield dut.p.i_data.eq(9)
68 yield
69 yield dut.p.i_valid.eq(0)
70 yield dut.p.i_data.eq(12)
71 yield
72 yield dut.p.i_data.eq(32)
73 yield dut.n.i_ready.eq(1)
74 yield
75 yield from check_o_n_valid(dut, 1) # buffer still needs to output
76 yield
77 yield from check_o_n_valid(dut, 1) # buffer still needs to output
78 yield
79 yield from check_o_n_valid(dut, 0) # buffer outputted, *now* we're done.
80 yield
81
82
83 def testbench2(dut):
84 #yield dut.p.i_rst.eq(1)
85 yield dut.n.i_ready.eq(0)
86 #yield dut.p.o_ready.eq(0)
87 yield
88 yield
89 #yield dut.p.i_rst.eq(0)
90 yield dut.n.i_ready.eq(1)
91 yield dut.p.i_data.eq(5)
92 yield dut.p.i_valid.eq(1)
93 yield
94
95 yield dut.p.i_data.eq(7)
96 yield from check_o_n_valid2(dut, 0) # effects of i_p_valid delayed 2 clocks
97 yield
98 yield from check_o_n_valid2(dut, 0) # effects of i_p_valid delayed 2 clocks
99
100 yield dut.p.i_data.eq(2)
101 yield
102 yield from check_o_n_valid2(dut, 1) # ok *now* i_p_valid effect is felt
103 yield dut.n.i_ready.eq(0) # begin going into "stall" (next stage says ready)
104 yield dut.p.i_data.eq(9)
105 yield
106 yield dut.p.i_valid.eq(0)
107 yield dut.p.i_data.eq(12)
108 yield
109 yield dut.p.i_data.eq(32)
110 yield dut.n.i_ready.eq(1)
111 yield
112 yield from check_o_n_valid2(dut, 1) # buffer still needs to output
113 yield
114 yield from check_o_n_valid2(dut, 1) # buffer still needs to output
115 yield
116 yield from check_o_n_valid2(dut, 1) # buffer still needs to output
117 yield
118 yield from check_o_n_valid2(dut, 0) # buffer outputted, *now* we're done.
119 yield
120 yield
121 yield
122
123
124 class Test3:
125 def __init__(self, dut, resultfn):
126 self.dut = dut
127 self.resultfn = resultfn
128 self.data = []
129 for i in range(num_tests):
130 #data.append(randint(0, 1<<16-1))
131 self.data.append(i+1)
132 self.i = 0
133 self.o = 0
134
135 def send(self):
136 while self.o != len(self.data):
137 send_range = randint(0, 3)
138 for j in range(randint(1,10)):
139 if send_range == 0:
140 send = True
141 else:
142 send = randint(0, send_range) != 0
143 o_p_ready = yield self.dut.p.o_ready
144 if not o_p_ready:
145 yield
146 continue
147 if send and self.i != len(self.data):
148 yield self.dut.p.i_valid.eq(1)
149 yield self.dut.p.i_data.eq(self.data[self.i])
150 self.i += 1
151 else:
152 yield self.dut.p.i_valid.eq(0)
153 yield
154
155 def rcv(self):
156 while self.o != len(self.data):
157 stall_range = randint(0, 3)
158 for j in range(randint(1,10)):
159 stall = randint(0, stall_range) != 0
160 yield self.dut.n.i_ready.eq(stall)
161 yield
162 o_n_valid = yield self.dut.n.o_valid
163 i_n_ready = yield self.dut.n.i_ready_test
164 if not o_n_valid or not i_n_ready:
165 continue
166 o_data = yield self.dut.n.o_data
167 self.resultfn(o_data, self.data[self.o], self.i, self.o)
168 self.o += 1
169 if self.o == len(self.data):
170 break
171
172 def test3_resultfn(o_data, expected, i, o):
173 assert o_data == expected + 1, \
174 "%d-%d data %x not match %x\n" \
175 % (i, o, o_data, expected)
176
177 def data_placeholder():
178 data = []
179 for i in range(num_tests):
180 d = PlaceHolder()
181 d.src1 = randint(0, 1<<16-1)
182 d.src2 = randint(0, 1<<16-1)
183 data.append(d)
184 return data
185
186 def data_dict():
187 data = []
188 for i in range(num_tests):
189 data.append({'src1': randint(0, 1<<16-1),
190 'src2': randint(0, 1<<16-1)})
191 return data
192
193
194 class Test5:
195 def __init__(self, dut, resultfn, data=None, stage_ctl=False):
196 self.dut = dut
197 self.resultfn = resultfn
198 self.stage_ctl = stage_ctl
199 if data:
200 self.data = data
201 else:
202 self.data = []
203 for i in range(num_tests):
204 self.data.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
205 self.i = 0
206 self.o = 0
207
208 def send(self):
209 while self.o != len(self.data):
210 send_range = randint(0, 3)
211 for j in range(randint(1,10)):
212 if send_range == 0:
213 send = True
214 else:
215 send = randint(0, send_range) != 0
216 #send = True
217 o_p_ready = yield self.dut.p.o_ready
218 if not o_p_ready:
219 yield
220 continue
221 if send and self.i != len(self.data):
222 yield self.dut.p.i_valid.eq(1)
223 for v in self.dut.set_input(self.data[self.i]):
224 yield v
225 self.i += 1
226 else:
227 yield self.dut.p.i_valid.eq(0)
228 yield
229
230 def rcv(self):
231 while self.o != len(self.data):
232 stall_range = randint(0, 3)
233 for j in range(randint(1,10)):
234 ready = randint(0, stall_range) != 0
235 #ready = True
236 yield self.dut.n.i_ready.eq(ready)
237 yield
238 o_n_valid = yield self.dut.n.o_valid
239 i_n_ready = yield self.dut.n.i_ready_test
240 if not o_n_valid or not i_n_ready:
241 continue
242 if isinstance(self.dut.n.o_data, Record):
243 o_data = {}
244 dod = self.dut.n.o_data
245 for k, v in dod.fields.items():
246 o_data[k] = yield v
247 else:
248 o_data = yield self.dut.n.o_data
249 self.resultfn(o_data, self.data[self.o], self.i, self.o)
250 self.o += 1
251 if self.o == len(self.data):
252 break
253
254 def test5_resultfn(o_data, expected, i, o):
255 res = expected[0] + expected[1]
256 assert o_data == res, \
257 "%d-%d data %x not match %s\n" \
258 % (i, o, o_data, repr(expected))
259
260 def testbench4(dut):
261 data = []
262 for i in range(num_tests):
263 #data.append(randint(0, 1<<16-1))
264 data.append(i+1)
265 i = 0
266 o = 0
267 while True:
268 stall = randint(0, 3) != 0
269 send = randint(0, 5) != 0
270 yield dut.n.i_ready.eq(stall)
271 o_p_ready = yield dut.p.o_ready
272 if o_p_ready:
273 if send and i != len(data):
274 yield dut.p.i_valid.eq(1)
275 yield dut.p.i_data.eq(data[i])
276 i += 1
277 else:
278 yield dut.p.i_valid.eq(0)
279 yield
280 o_n_valid = yield dut.n.o_valid
281 i_n_ready = yield dut.n.i_ready_test
282 if o_n_valid and i_n_ready:
283 o_data = yield dut.n.o_data
284 assert o_data == data[o] + 2, "%d-%d data %x not match %x\n" \
285 % (i, o, o_data, data[o])
286 o += 1
287 if o == len(data):
288 break
289
290 ######################################################################
291 # Test 2 and 4
292 ######################################################################
293
294 class ExampleBufPipe2(ControlBase):
295 """ Example of how to do chained pipeline stages.
296 """
297
298 def elaborate(self, platform):
299 m = Module()
300
301 pipe1 = ExampleBufPipe()
302 pipe2 = ExampleBufPipe()
303
304 m.submodules.pipe1 = pipe1
305 m.submodules.pipe2 = pipe2
306
307 m.d.comb += self.connect([pipe1, pipe2])
308
309 return m
310
311
312 ######################################################################
313 # Test 9
314 ######################################################################
315
316 class ExampleBufPipeChain2(BufferedHandshake):
317 """ connects two stages together as a *single* combinatorial stage.
318 """
319 def __init__(self):
320 stage1 = ExampleStageCls()
321 stage2 = ExampleStageCls()
322 combined = StageChain([stage1, stage2])
323 BufferedHandshake.__init__(self, combined)
324
325
326 def data_chain2():
327 data = []
328 for i in range(num_tests):
329 data.append(randint(0, 1<<16-2))
330 return data
331
332
333 def test9_resultfn(o_data, expected, i, o):
334 res = expected + 2
335 assert o_data == res, \
336 "%d-%d received data %x not match expected %x\n" \
337 % (i, o, o_data, res)
338
339
340 ######################################################################
341 # Test 6 and 10
342 ######################################################################
343
344 class SetLessThan:
345 def __init__(self, width, signed):
346 self.m = Module()
347 self.src1 = Signal((width, signed), name="src1")
348 self.src2 = Signal((width, signed), name="src2")
349 self.output = Signal(width, name="out")
350
351 def elaborate(self, platform):
352 self.m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0))
353 return self.m
354
355
356 class LTStage(StageCls):
357 """ module-based stage example
358 """
359 def __init__(self):
360 self.slt = SetLessThan(16, True)
361
362 def ispec(self):
363 return (Signal(16, name="sig1"), Signal(16, "sig2"))
364
365 def ospec(self):
366 return Signal(16, "out")
367
368 def setup(self, m, i):
369 self.o = Signal(16)
370 m.submodules.slt = self.slt
371 m.d.comb += self.slt.src1.eq(i[0])
372 m.d.comb += self.slt.src2.eq(i[1])
373 m.d.comb += self.o.eq(self.slt.output)
374
375 def process(self, i):
376 return self.o
377
378
379 class LTStageDerived(SetLessThan, StageCls):
380 """ special version of a nmigen module where the module is also a stage
381
382 shows that you don't actually need to combinatorially connect
383 to the outputs, or add the module as a submodule: just return
384 the module output parameter(s) from the Stage.process() function
385 """
386
387 def __init__(self):
388 SetLessThan.__init__(self, 16, True)
389
390 def ispec(self):
391 return (Signal(16), Signal(16))
392
393 def ospec(self):
394 return Signal(16)
395
396 def setup(self, m, i):
397 m.submodules.slt = self
398 m.d.comb += self.src1.eq(i[0])
399 m.d.comb += self.src2.eq(i[1])
400
401 def process(self, i):
402 return self.output
403
404
405 class ExampleLTPipeline(UnbufferedPipeline):
406 """ an example of how to use the unbuffered pipeline.
407 """
408
409 def __init__(self):
410 stage = LTStage()
411 UnbufferedPipeline.__init__(self, stage)
412
413
414 class ExampleLTBufferedPipeDerived(BufferedHandshake):
415 """ an example of how to use the buffered pipeline.
416 """
417
418 def __init__(self):
419 stage = LTStageDerived()
420 BufferedHandshake.__init__(self, stage)
421
422
423 def test6_resultfn(o_data, expected, i, o):
424 res = 1 if expected[0] < expected[1] else 0
425 assert o_data == res, \
426 "%d-%d data %x not match %s\n" \
427 % (i, o, o_data, repr(expected))
428
429
430 ######################################################################
431 # Test 7
432 ######################################################################
433
434 class ExampleAddRecordStage(StageCls):
435 """ example use of a Record
436 """
437
438 record_spec = [('src1', 16), ('src2', 16)]
439 def ispec(self):
440 """ returns a Record using the specification
441 """
442 return Record(self.record_spec)
443
444 def ospec(self):
445 return Record(self.record_spec)
446
447 def process(self, i):
448 """ process the input data, returning a dictionary with key names
449 that exactly match the Record's attributes.
450 """
451 return {'src1': i.src1 + 1,
452 'src2': i.src2 + 1}
453
454 ######################################################################
455 # Test 11
456 ######################################################################
457
458 class ExampleAddRecordPlaceHolderStage(StageCls):
459 """ example use of a Record, with a placeholder as the processing result
460 """
461
462 record_spec = [('src1', 16), ('src2', 16)]
463 def ispec(self):
464 """ returns a Record using the specification
465 """
466 return Record(self.record_spec)
467
468 def ospec(self):
469 return Record(self.record_spec)
470
471 def process(self, i):
472 """ process the input data, returning a PlaceHolder class instance
473 with attributes that exactly match those of the Record.
474 """
475 o = PlaceHolder()
476 o.src1 = i.src1 + 1
477 o.src2 = i.src2 + 1
478 return o
479
480
481 class PlaceHolder: pass
482
483
484 class ExampleAddRecordPipe(UnbufferedPipeline):
485 """ an example of how to use the combinatorial pipeline.
486 """
487
488 def __init__(self):
489 stage = ExampleAddRecordStage()
490 UnbufferedPipeline.__init__(self, stage)
491
492
493 def test7_resultfn(o_data, expected, i, o):
494 res = (expected['src1'] + 1, expected['src2'] + 1)
495 assert o_data['src1'] == res[0] and o_data['src2'] == res[1], \
496 "%d-%d data %s not match %s\n" \
497 % (i, o, repr(o_data), repr(expected))
498
499
500 class ExampleAddRecordPlaceHolderPipe(UnbufferedPipeline):
501 """ an example of how to use the combinatorial pipeline.
502 """
503
504 def __init__(self):
505 stage = ExampleAddRecordPlaceHolderStage()
506 UnbufferedPipeline.__init__(self, stage)
507
508
509 def test11_resultfn(o_data, expected, i, o):
510 res1 = expected.src1 + 1
511 res2 = expected.src2 + 1
512 assert o_data['src1'] == res1 and o_data['src2'] == res2, \
513 "%d-%d data %s not match %s\n" \
514 % (i, o, repr(o_data), repr(expected))
515
516
517 ######################################################################
518 # Test 8
519 ######################################################################
520
521
522 class Example2OpClass:
523 """ an example of a class used to store 2 operands.
524 requires an eq function, to conform with the pipeline stage API
525 """
526
527 def __init__(self):
528 self.op1 = Signal(16)
529 self.op2 = Signal(16)
530
531 def eq(self, i):
532 return [self.op1.eq(i.op1), self.op2.eq(i.op2)]
533
534
535 class ExampleAddClassStage(StageCls):
536 """ an example of how to use the buffered pipeline, as a class instance
537 """
538
539 def ispec(self):
540 """ returns an instance of an Example2OpClass.
541 """
542 return Example2OpClass()
543
544 def ospec(self):
545 """ returns an output signal which will happen to contain the sum
546 of the two inputs
547 """
548 return Signal(16)
549
550 def process(self, i):
551 """ process the input data (sums the values in the tuple) and returns it
552 """
553 return i.op1 + i.op2
554
555
556 class ExampleBufPipeAddClass(BufferedHandshake):
557 """ an example of how to use the buffered pipeline, using a class instance
558 """
559
560 def __init__(self):
561 addstage = ExampleAddClassStage()
562 BufferedHandshake.__init__(self, addstage)
563
564
565 class TestInputAdd:
566 """ the eq function, called by set_input, needs an incoming object
567 that conforms to the Example2OpClass.eq function requirements
568 easiest way to do that is to create a class that has the exact
569 same member layout (self.op1, self.op2) as Example2OpClass
570 """
571 def __init__(self, op1, op2):
572 self.op1 = op1
573 self.op2 = op2
574
575
576 def test8_resultfn(o_data, expected, i, o):
577 res = expected.op1 + expected.op2 # these are a TestInputAdd instance
578 assert o_data == res, \
579 "%d-%d data %x not match %s\n" \
580 % (i, o, o_data, repr(expected))
581
582 def data_2op():
583 data = []
584 for i in range(num_tests):
585 data.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
586 return data
587
588
589 ######################################################################
590 # Test 12
591 ######################################################################
592
593 class ExampleStageDelayCls(StageCls):
594 """ an example of how to use the buffered pipeline, in a static class
595 fashion
596 """
597
598 def __init__(self, valid_trigger=2):
599 self.count = Signal(2)
600 self.valid_trigger = valid_trigger
601
602 def ispec(self):
603 return Signal(16, name="example_input_signal")
604
605 def ospec(self):
606 return Signal(16, name="example_output_signal")
607
608 @property
609 def d_ready(self):
610 return (self.count == 1)# | (self.count == 3)
611 return Const(1)
612
613 def d_valid(self, i_ready):
614 return self.count == self.valid_trigger
615 return Const(1)
616
617 def process(self, i):
618 """ process the input data and returns it (adds 1)
619 """
620 return i + 1
621
622 def elaborate(self, platform):
623 m = Module()
624 m.d.sync += self.count.eq(self.count + 1)
625 return m
626
627
628 class ExampleBufDelayedPipe(BufferedHandshake):
629
630 def __init__(self):
631 stage = ExampleStageDelayCls(valid_trigger=2)
632 BufferedHandshake.__init__(self, stage, stage_ctl=True)
633
634 def elaborate(self, platform):
635 m = BufferedHandshake.elaborate(self, platform)
636 m.submodules.stage = self.stage
637 return m
638
639
640 def data_chain1():
641 data = []
642 for i in range(num_tests):
643 data.append(1<<((i*3)%15))
644 #data.append(randint(0, 1<<16-2))
645 #print (hex(data[-1]))
646 return data
647
648
649 def test12_resultfn(o_data, expected, i, o):
650 res = expected + 1
651 assert o_data == res, \
652 "%d-%d data %x not match %x\n" \
653 % (i, o, o_data, res)
654
655
656 ######################################################################
657 # Test 13
658 ######################################################################
659
660 class ExampleUnBufDelayedPipe(BufferedHandshake):
661
662 def __init__(self):
663 stage = ExampleStageDelayCls(valid_trigger=3)
664 BufferedHandshake.__init__(self, stage, stage_ctl=True)
665
666 def elaborate(self, platform):
667 m = BufferedHandshake.elaborate(self, platform)
668 m.submodules.stage = self.stage
669 return m
670
671 ######################################################################
672 # Test 15
673 ######################################################################
674
675 class ExampleBufModeAdd1Pipe(SimpleHandshake):
676
677 def __init__(self):
678 stage = ExampleStageCls()
679 SimpleHandshake.__init__(self, stage)
680
681
682 ######################################################################
683 # Test 16
684 ######################################################################
685
686 class ExampleBufModeUnBufPipe(ControlBase):
687
688 def elaborate(self, platform):
689 m = ControlBase._elaborate(self, platform)
690
691 pipe1 = ExampleBufModeAdd1Pipe()
692 pipe2 = ExampleBufAdd1Pipe()
693
694 m.submodules.pipe1 = pipe1
695 m.submodules.pipe2 = pipe2
696
697 m.d.comb += self.connect([pipe1, pipe2])
698
699 return m
700
701 ######################################################################
702 # Test 17
703 ######################################################################
704
705 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2):
706
707 def __init__(self):
708 stage = ExampleStageCls()
709 UnbufferedPipeline2.__init__(self, stage)
710
711
712 ######################################################################
713 # Test 18
714 ######################################################################
715
716 class PassThroughTest(PassThroughHandshake):
717
718 def iospecfn(self):
719 return Signal(16, "out")
720
721 def __init__(self):
722 stage = PassThroughStage(self.iospecfn)
723 PassThroughHandshake.__init__(self, stage)
724
725 def test_identical_resultfn(o_data, expected, i, o):
726 res = expected
727 assert o_data == res, \
728 "%d-%d data %x not match %x\n" \
729 % (i, o, o_data, res)
730
731
732 ######################################################################
733 # Test 19
734 ######################################################################
735
736 class ExamplePassAdd1Pipe(PassThroughHandshake):
737
738 def __init__(self):
739 stage = ExampleStageCls()
740 PassThroughHandshake.__init__(self, stage)
741
742
743 class ExampleBufPassThruPipe(ControlBase):
744
745 def elaborate(self, platform):
746 m = ControlBase._elaborate(self, platform)
747
748 # XXX currently fails: any other permutation works fine.
749 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
750 # also fails using UnbufferedPipeline as well
751 pipe1 = ExampleBufModeAdd1Pipe()
752 pipe2 = ExamplePassAdd1Pipe()
753
754 m.submodules.pipe1 = pipe1
755 m.submodules.pipe2 = pipe2
756
757 m.d.comb += self.connect([pipe1, pipe2])
758
759 return m
760
761
762 ######################################################################
763 # Test 20
764 ######################################################################
765
766 def iospecfn():
767 return Signal(16, name="din")
768
769 class FIFOTest16(FIFOtest):
770
771
772 def __init__(self):
773 FIFOtest.__init__(self, iospecfn, 16, 2)
774
775
776 ######################################################################
777 # Test 21
778 ######################################################################
779
780 class ExampleFIFOPassThruPipe1(ControlBase):
781
782 def elaborate(self, platform):
783 m = ControlBase._elaborate(self, platform)
784
785 pipe1 = FIFOTest16()
786 pipe2 = ExamplePassAdd1Pipe()
787
788 m.submodules.pipe1 = pipe1
789 m.submodules.pipe2 = pipe2
790
791 m.d.comb += self.connect([pipe1, pipe2])
792
793 return m
794
795
796 ######################################################################
797 # Test 997
798 ######################################################################
799
800 class ExampleBufPassThruPipe2(ControlBase):
801
802 def elaborate(self, platform):
803 m = ControlBase._elaborate(self, platform)
804
805 # XXX currently fails: any other permutation works fine.
806 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
807 # also fails using UnbufferedPipeline as well
808 #pipe1 = ExampleUnBufAdd1Pipe()
809 #pipe2 = ExampleBufAdd1Pipe()
810 pipe1 = ExampleBufAdd1Pipe()
811 pipe2 = ExamplePassAdd1Pipe()
812
813 m.submodules.pipe1 = pipe1
814 m.submodules.pipe2 = pipe2
815
816 m.d.comb += self.connect([pipe1, pipe2])
817
818 return m
819
820
821 ######################################################################
822 # Test 998
823 ######################################################################
824
825 class ExampleBufPipe3(ControlBase):
826 """ Example of how to do delayed pipeline, where the stage signals
827 whether it is ready.
828 """
829
830 def elaborate(self, platform):
831 m = ControlBase._elaborate(self, platform)
832
833 pipe1 = ExampleBufDelayedPipe()
834 pipe2 = ExampleBufPipe()
835
836 m.submodules.pipe1 = pipe1
837 m.submodules.pipe2 = pipe2
838
839 m.d.comb += self.connect([pipe1, pipe2])
840
841 return m
842
843 ######################################################################
844 # Test 999 - XXX FAILS
845 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
846 ######################################################################
847
848 class ExampleBufAdd1Pipe(BufferedHandshake):
849
850 def __init__(self):
851 stage = ExampleStageCls()
852 BufferedHandshake.__init__(self, stage)
853
854
855 class ExampleUnBufAdd1Pipe(UnbufferedPipeline):
856
857 def __init__(self):
858 stage = ExampleStageCls()
859 UnbufferedPipeline.__init__(self, stage)
860
861
862 class ExampleBufUnBufPipe(ControlBase):
863
864 def elaborate(self, platform):
865 m = ControlBase._elaborate(self, platform)
866
867 # XXX currently fails: any other permutation works fine.
868 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
869 # also fails using UnbufferedPipeline as well
870 #pipe1 = ExampleUnBufAdd1Pipe()
871 #pipe2 = ExampleBufAdd1Pipe()
872 pipe1 = ExampleBufAdd1Pipe()
873 pipe2 = ExampleUnBufAdd1Pipe()
874
875 m.submodules.pipe1 = pipe1
876 m.submodules.pipe2 = pipe2
877
878 m.d.comb += self.connect([pipe1, pipe2])
879
880 return m
881
882
883 ######################################################################
884 # Unit Tests
885 ######################################################################
886
887 num_tests = 10
888
889 if __name__ == '__main__':
890 print ("test 1")
891 dut = ExampleBufPipe()
892 run_simulation(dut, testbench(dut), vcd_name="test_bufpipe.vcd")
893
894 print ("test 2")
895 dut = ExampleBufPipe2()
896 run_simulation(dut, testbench2(dut), vcd_name="test_bufpipe2.vcd")
897 ports = [dut.p.i_valid, dut.n.i_ready,
898 dut.n.o_valid, dut.p.o_ready] + \
899 [dut.p.i_data] + [dut.n.o_data]
900 vl = rtlil.convert(dut, ports=ports)
901 with open("test_bufpipe2.il", "w") as f:
902 f.write(vl)
903
904
905 print ("test 3")
906 dut = ExampleBufPipe()
907 test = Test3(dut, test3_resultfn)
908 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe3.vcd")
909
910 print ("test 3.5")
911 dut = ExamplePipeline()
912 test = Test3(dut, test3_resultfn)
913 run_simulation(dut, [test.send, test.rcv], vcd_name="test_combpipe3.vcd")
914
915 print ("test 4")
916 dut = ExampleBufPipe2()
917 run_simulation(dut, testbench4(dut), vcd_name="test_bufpipe4.vcd")
918
919 print ("test 5")
920 dut = ExampleBufPipeAdd()
921 test = Test5(dut, test5_resultfn, stage_ctl=True)
922 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe5.vcd")
923
924 print ("test 6")
925 dut = ExampleLTPipeline()
926 test = Test5(dut, test6_resultfn)
927 run_simulation(dut, [test.send, test.rcv], vcd_name="test_ltcomb6.vcd")
928
929 ports = [dut.p.i_valid, dut.n.i_ready,
930 dut.n.o_valid, dut.p.o_ready] + \
931 list(dut.p.i_data) + [dut.n.o_data]
932 vl = rtlil.convert(dut, ports=ports)
933 with open("test_ltcomb_pipe.il", "w") as f:
934 f.write(vl)
935
936 print ("test 7")
937 dut = ExampleAddRecordPipe()
938 data=data_dict()
939 test = Test5(dut, test7_resultfn, data=data)
940 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
941
942 ports = [dut.p.i_valid, dut.n.i_ready,
943 dut.n.o_valid, dut.p.o_ready,
944 dut.p.i_data.src1, dut.p.i_data.src2,
945 dut.n.o_data.src1, dut.n.o_data.src2]
946 vl = rtlil.convert(dut, ports=ports)
947 with open("test_recordcomb_pipe.il", "w") as f:
948 f.write(vl)
949
950 print ("test 8")
951 dut = ExampleBufPipeAddClass()
952 data=data_2op()
953 test = Test5(dut, test8_resultfn, data=data)
954 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe8.vcd")
955
956 print ("test 9")
957 dut = ExampleBufPipeChain2()
958 ports = [dut.p.i_valid, dut.n.i_ready,
959 dut.n.o_valid, dut.p.o_ready] + \
960 [dut.p.i_data] + [dut.n.o_data]
961 vl = rtlil.convert(dut, ports=ports)
962 with open("test_bufpipechain2.il", "w") as f:
963 f.write(vl)
964
965 data = data_chain2()
966 test = Test5(dut, test9_resultfn, data=data)
967 run_simulation(dut, [test.send, test.rcv],
968 vcd_name="test_bufpipechain2.vcd")
969
970 print ("test 10")
971 dut = ExampleLTBufferedPipeDerived()
972 test = Test5(dut, test6_resultfn)
973 run_simulation(dut, [test.send, test.rcv], vcd_name="test_ltbufpipe10.vcd")
974 vl = rtlil.convert(dut, ports=ports)
975 with open("test_ltbufpipe10.il", "w") as f:
976 f.write(vl)
977
978 print ("test 11")
979 dut = ExampleAddRecordPlaceHolderPipe()
980 data=data_placeholder()
981 test = Test5(dut, test11_resultfn, data=data)
982 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
983
984
985 print ("test 12")
986 dut = ExampleBufDelayedPipe()
987 data = data_chain1()
988 test = Test5(dut, test12_resultfn, data=data)
989 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe12.vcd")
990 ports = [dut.p.i_valid, dut.n.i_ready,
991 dut.n.o_valid, dut.p.o_ready] + \
992 [dut.p.i_data] + [dut.n.o_data]
993 vl = rtlil.convert(dut, ports=ports)
994 with open("test_bufpipe12.il", "w") as f:
995 f.write(vl)
996
997 print ("test 13")
998 dut = ExampleUnBufDelayedPipe()
999 data = data_chain1()
1000 test = Test5(dut, test12_resultfn, data=data)
1001 run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe13.vcd")
1002 ports = [dut.p.i_valid, dut.n.i_ready,
1003 dut.n.o_valid, dut.p.o_ready] + \
1004 [dut.p.i_data] + [dut.n.o_data]
1005 vl = rtlil.convert(dut, ports=ports)
1006 with open("test_unbufpipe13.il", "w") as f:
1007 f.write(vl)
1008
1009 print ("test 15")
1010 dut = ExampleBufModeAdd1Pipe()
1011 data = data_chain1()
1012 test = Test5(dut, test12_resultfn, data=data)
1013 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf15.vcd")
1014 ports = [dut.p.i_valid, dut.n.i_ready,
1015 dut.n.o_valid, dut.p.o_ready] + \
1016 [dut.p.i_data] + [dut.n.o_data]
1017 vl = rtlil.convert(dut, ports=ports)
1018 with open("test_bufunbuf15.il", "w") as f:
1019 f.write(vl)
1020
1021 print ("test 16")
1022 dut = ExampleBufModeUnBufPipe()
1023 data = data_chain1()
1024 test = Test5(dut, test9_resultfn, data=data)
1025 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf16.vcd")
1026 ports = [dut.p.i_valid, dut.n.i_ready,
1027 dut.n.o_valid, dut.p.o_ready] + \
1028 [dut.p.i_data] + [dut.n.o_data]
1029 vl = rtlil.convert(dut, ports=ports)
1030 with open("test_bufunbuf16.il", "w") as f:
1031 f.write(vl)
1032
1033 print ("test 17")
1034 dut = ExampleUnBufAdd1Pipe2()
1035 data = data_chain1()
1036 test = Test5(dut, test12_resultfn, data=data)
1037 run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe17.vcd")
1038 ports = [dut.p.i_valid, dut.n.i_ready,
1039 dut.n.o_valid, dut.p.o_ready] + \
1040 [dut.p.i_data] + [dut.n.o_data]
1041 vl = rtlil.convert(dut, ports=ports)
1042 with open("test_unbufpipe17.il", "w") as f:
1043 f.write(vl)
1044
1045 print ("test 18")
1046 dut = PassThroughTest()
1047 data = data_chain1()
1048 test = Test5(dut, test_identical_resultfn, data=data)
1049 run_simulation(dut, [test.send, test.rcv], vcd_name="test_passthru18.vcd")
1050 ports = [dut.p.i_valid, dut.n.i_ready,
1051 dut.n.o_valid, dut.p.o_ready] + \
1052 [dut.p.i_data] + [dut.n.o_data]
1053 vl = rtlil.convert(dut, ports=ports)
1054 with open("test_passthru18.il", "w") as f:
1055 f.write(vl)
1056
1057 print ("test 19")
1058 dut = ExampleBufPassThruPipe()
1059 data = data_chain1()
1060 test = Test5(dut, test9_resultfn, data=data)
1061 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass19.vcd")
1062 ports = [dut.p.i_valid, dut.n.i_ready,
1063 dut.n.o_valid, dut.p.o_ready] + \
1064 [dut.p.i_data] + [dut.n.o_data]
1065 vl = rtlil.convert(dut, ports=ports)
1066 with open("test_bufpass19.il", "w") as f:
1067 f.write(vl)
1068
1069 print ("test 20")
1070 dut = FIFOTest16()
1071 data = data_chain1()
1072 test = Test5(dut, test_identical_resultfn, data=data)
1073 run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifo20.vcd")
1074 ports = [dut.p.i_valid, dut.n.i_ready,
1075 dut.n.o_valid, dut.p.o_ready] + \
1076 [dut.p.i_data] + [dut.n.o_data]
1077 vl = rtlil.convert(dut, ports=ports)
1078 with open("test_fifo20.il", "w") as f:
1079 f.write(vl)
1080
1081 print ("test 21")
1082 dut = ExampleFIFOPassThruPipe1()
1083 data = data_chain1()
1084 test = Test5(dut, test12_resultfn, data=data)
1085 run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifopass21.vcd")
1086 ports = [dut.p.i_valid, dut.n.i_ready,
1087 dut.n.o_valid, dut.p.o_ready] + \
1088 [dut.p.i_data] + [dut.n.o_data]
1089 vl = rtlil.convert(dut, ports=ports)
1090 with open("test_fifopass21.il", "w") as f:
1091 f.write(vl)
1092
1093 print ("test 997")
1094 dut = ExampleBufPassThruPipe2()
1095 data = data_chain1()
1096 test = Test5(dut, test9_resultfn, data=data)
1097 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass997.vcd")
1098 ports = [dut.p.i_valid, dut.n.i_ready,
1099 dut.n.o_valid, dut.p.o_ready] + \
1100 [dut.p.i_data] + [dut.n.o_data]
1101 vl = rtlil.convert(dut, ports=ports)
1102 with open("test_bufpass997.il", "w") as f:
1103 f.write(vl)
1104
1105 print ("test 998 (fails, bug)")
1106 dut = ExampleBufPipe3()
1107 data = data_chain1()
1108 test = Test5(dut, test9_resultfn, data=data)
1109 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe14.vcd")
1110 ports = [dut.p.i_valid, dut.n.i_ready,
1111 dut.n.o_valid, dut.p.o_ready] + \
1112 [dut.p.i_data] + [dut.n.o_data]
1113 vl = rtlil.convert(dut, ports=ports)
1114 with open("test_bufpipe14.il", "w") as f:
1115 f.write(vl)
1116
1117 print ("test 999 (expected to fail, which is a bug)")
1118 dut = ExampleBufUnBufPipe()
1119 data = data_chain1()
1120 test = Test5(dut, test9_resultfn, data=data)
1121 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf999.vcd")
1122 ports = [dut.p.i_valid, dut.n.i_ready,
1123 dut.n.o_valid, dut.p.o_ready] + \
1124 [dut.p.i_data] + [dut.n.o_data]
1125 vl = rtlil.convert(dut, ports=ports)
1126 with open("test_bufunbuf999.il", "w") as f:
1127 f.write(vl)
1128