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