add new Elaboratable
[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, Elaboratable
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 = ControlBase.elaborate(self, platform)
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(Elaboratable):
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, Elaboratable):
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, Elaboratable):
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 """ process the input data and returns it (adds 1)
624 """
625 return i + 1
626
627 def elaborate(self, platform):
628 m = Module()
629 m.d.sync += self.count.eq(self.count + 1)
630 return m
631
632
633 class ExampleBufDelayedPipe(BufferedHandshake):
634
635 def __init__(self):
636 stage = ExampleStageDelayCls(valid_trigger=2)
637 BufferedHandshake.__init__(self, stage, stage_ctl=True)
638
639 def elaborate(self, platform):
640 m = BufferedHandshake.elaborate(self, platform)
641 m.submodules.stage = self.stage
642 return m
643
644
645 def data_chain1():
646 data = []
647 for i in range(num_tests):
648 data.append(1<<((i*3)%15))
649 #data.append(randint(0, 1<<16-2))
650 #print (hex(data[-1]))
651 return data
652
653
654 def resultfn_12(o_data, expected, i, o):
655 res = expected + 1
656 assert o_data == res, \
657 "%d-%d data %x not match %x\n" \
658 % (i, o, o_data, res)
659
660
661 ######################################################################
662 # Test 13
663 ######################################################################
664
665 class ExampleUnBufDelayedPipe(BufferedHandshake):
666
667 def __init__(self):
668 stage = ExampleStageDelayCls(valid_trigger=3)
669 BufferedHandshake.__init__(self, stage, stage_ctl=True)
670
671 def elaborate(self, platform):
672 m = BufferedHandshake.elaborate(self, platform)
673 m.submodules.stage = self.stage
674 return m
675
676 ######################################################################
677 # Test 15
678 ######################################################################
679
680 class ExampleBufModeAdd1Pipe(SimpleHandshake):
681
682 def __init__(self):
683 stage = ExampleStageCls()
684 SimpleHandshake.__init__(self, stage)
685
686
687 ######################################################################
688 # Test 16
689 ######################################################################
690
691 class ExampleBufModeUnBufPipe(ControlBase):
692
693 def elaborate(self, platform):
694 m = ControlBase.elaborate(self, platform)
695
696 pipe1 = ExampleBufModeAdd1Pipe()
697 pipe2 = ExampleBufAdd1Pipe()
698
699 m.submodules.pipe1 = pipe1
700 m.submodules.pipe2 = pipe2
701
702 m.d.comb += self.connect([pipe1, pipe2])
703
704 return m
705
706 ######################################################################
707 # Test 17
708 ######################################################################
709
710 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2):
711
712 def __init__(self):
713 stage = ExampleStageCls()
714 UnbufferedPipeline2.__init__(self, stage)
715
716
717 ######################################################################
718 # Test 18
719 ######################################################################
720
721 class PassThroughTest(PassThroughHandshake):
722
723 def iospecfn(self):
724 return Signal(16, "out")
725
726 def __init__(self):
727 stage = PassThroughStage(self.iospecfn)
728 PassThroughHandshake.__init__(self, stage)
729
730 def resultfn_identical(o_data, expected, i, o):
731 res = expected
732 assert o_data == res, \
733 "%d-%d data %x not match %x\n" \
734 % (i, o, o_data, res)
735
736
737 ######################################################################
738 # Test 19
739 ######################################################################
740
741 class ExamplePassAdd1Pipe(PassThroughHandshake):
742
743 def __init__(self):
744 stage = ExampleStageCls()
745 PassThroughHandshake.__init__(self, stage)
746
747
748 class ExampleBufPassThruPipe(ControlBase):
749
750 def elaborate(self, platform):
751 m = ControlBase.elaborate(self, platform)
752
753 # XXX currently fails: any other permutation works fine.
754 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
755 # also fails using UnbufferedPipeline as well
756 pipe1 = ExampleBufModeAdd1Pipe()
757 pipe2 = ExamplePassAdd1Pipe()
758
759 m.submodules.pipe1 = pipe1
760 m.submodules.pipe2 = pipe2
761
762 m.d.comb += self.connect([pipe1, pipe2])
763
764 return m
765
766
767 ######################################################################
768 # Test 20
769 ######################################################################
770
771 def iospecfn():
772 return Signal(16, name="d_in")
773
774 class FIFOTest16(FIFOControl):
775
776 def __init__(self):
777 stage = PassThroughStage(iospecfn)
778 FIFOControl.__init__(self, 2, stage)
779
780
781 ######################################################################
782 # Test 21
783 ######################################################################
784
785 class ExampleFIFOPassThruPipe1(ControlBase):
786
787 def elaborate(self, platform):
788 m = ControlBase.elaborate(self, platform)
789
790 pipe1 = FIFOTest16()
791 pipe2 = ExamplePassAdd1Pipe()
792
793 m.submodules.pipe1 = pipe1
794 m.submodules.pipe2 = pipe2
795
796 m.d.comb += self.connect([pipe1, pipe2])
797
798 return m
799
800
801 ######################################################################
802 # Test 22
803 ######################################################################
804
805 class Example2OpRecord(RecordObject):
806 def __init__(self):
807 RecordObject.__init__(self)
808 self.op1 = Signal(16)
809 self.op2 = Signal(16)
810
811
812 class ExampleAddRecordObjectStage(StageCls):
813
814 def ispec(self):
815 """ returns an instance of an Example2OpRecord.
816 """
817 return Example2OpRecord()
818
819 def ospec(self):
820 """ returns an output signal which will happen to contain the sum
821 of the two inputs
822 """
823 return Signal(16)
824
825 def process(self, i):
826 """ process the input data (sums the values in the tuple) and returns it
827 """
828 return i.op1 + i.op2
829
830
831 class ExampleRecordHandshakeAddClass(SimpleHandshake):
832
833 def __init__(self):
834 addstage = ExampleAddRecordObjectStage()
835 SimpleHandshake.__init__(self, stage=addstage)
836
837
838 ######################################################################
839 # Test 23
840 ######################################################################
841
842 def iospecfnrecord():
843 return Example2OpRecord()
844
845 class FIFOTestRecordControl(FIFOControl):
846
847 def __init__(self):
848 stage = PassThroughStage(iospecfnrecord)
849 FIFOControl.__init__(self, 2, stage)
850
851
852 class ExampleFIFORecordObjectPipe(ControlBase):
853
854 def elaborate(self, platform):
855 m = ControlBase.elaborate(self, platform)
856
857 pipe1 = FIFOTestRecordControl()
858 pipe2 = ExampleRecordHandshakeAddClass()
859
860 m.submodules.pipe1 = pipe1
861 m.submodules.pipe2 = pipe2
862
863 m.d.comb += self.connect([pipe1, pipe2])
864
865 return m
866
867
868 ######################################################################
869 # Test 24
870 ######################################################################
871
872 class FIFOTestRecordAddStageControl(FIFOControl):
873
874 def __init__(self):
875 stage = ExampleAddRecordObjectStage()
876 FIFOControl.__init__(self, 2, stage)
877
878
879
880 ######################################################################
881 # Test 25
882 ######################################################################
883
884 class FIFOTestAdd16(FIFOControl):
885
886 def __init__(self):
887 stage = ExampleStageCls()
888 FIFOControl.__init__(self, 2, stage)
889
890
891 class ExampleFIFOAdd2Pipe(ControlBase):
892
893 def elaborate(self, platform):
894 m = ControlBase.elaborate(self, platform)
895
896 pipe1 = FIFOTestAdd16()
897 pipe2 = FIFOTestAdd16()
898
899 m.submodules.pipe1 = pipe1
900 m.submodules.pipe2 = pipe2
901
902 m.d.comb += self.connect([pipe1, pipe2])
903
904 return m
905
906
907 ######################################################################
908 # Test 26
909 ######################################################################
910
911 def iospecfn24():
912 return (Signal(16, name="src1"), Signal(16, name="src2"))
913
914 class FIFOTest2x16(FIFOControl):
915
916 def __init__(self):
917 stage = PassThroughStage(iospecfn2)
918 FIFOControl.__init__(self, 2, stage)
919
920
921 ######################################################################
922 # Test 997
923 ######################################################################
924
925 class ExampleBufPassThruPipe2(ControlBase):
926
927 def elaborate(self, platform):
928 m = ControlBase.elaborate(self, platform)
929
930 # XXX currently fails: any other permutation works fine.
931 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
932 # also fails using UnbufferedPipeline as well
933 #pipe1 = ExampleUnBufAdd1Pipe()
934 #pipe2 = ExampleBufAdd1Pipe()
935 pipe1 = ExampleBufAdd1Pipe()
936 pipe2 = ExamplePassAdd1Pipe()
937
938 m.submodules.pipe1 = pipe1
939 m.submodules.pipe2 = pipe2
940
941 m.d.comb += self.connect([pipe1, pipe2])
942
943 return m
944
945
946 ######################################################################
947 # Test 998
948 ######################################################################
949
950 class ExampleBufPipe3(ControlBase):
951 """ Example of how to do delayed pipeline, where the stage signals
952 whether it is ready.
953 """
954
955 def elaborate(self, platform):
956 m = ControlBase.elaborate(self, platform)
957
958 pipe1 = ExampleBufDelayedPipe()
959 pipe2 = ExampleBufPipe()
960
961 m.submodules.pipe1 = pipe1
962 m.submodules.pipe2 = pipe2
963
964 m.d.comb += self.connect([pipe1, pipe2])
965
966 return m
967
968 ######################################################################
969 # Test 999 - XXX FAILS
970 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
971 ######################################################################
972
973 class ExampleBufAdd1Pipe(BufferedHandshake):
974
975 def __init__(self):
976 stage = ExampleStageCls()
977 BufferedHandshake.__init__(self, stage)
978
979
980 class ExampleUnBufAdd1Pipe(UnbufferedPipeline):
981
982 def __init__(self):
983 stage = ExampleStageCls()
984 UnbufferedPipeline.__init__(self, stage)
985
986
987 class ExampleBufUnBufPipe(ControlBase):
988
989 def elaborate(self, platform):
990 m = ControlBase.elaborate(self, platform)
991
992 # XXX currently fails: any other permutation works fine.
993 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
994 # also fails using UnbufferedPipeline as well
995 #pipe1 = ExampleUnBufAdd1Pipe()
996 #pipe2 = ExampleBufAdd1Pipe()
997 pipe1 = ExampleBufAdd1Pipe()
998 pipe2 = ExampleUnBufAdd1Pipe()
999
1000 m.submodules.pipe1 = pipe1
1001 m.submodules.pipe2 = pipe2
1002
1003 m.d.comb += self.connect([pipe1, pipe2])
1004
1005 return m
1006
1007
1008 ######################################################################
1009 # Unit Tests
1010 ######################################################################
1011
1012 num_tests = 10
1013
1014 if __name__ == '__main__':
1015 if False:
1016 print ("test 1")
1017 dut = ExampleBufPipe()
1018 run_simulation(dut, tbench(dut), vcd_name="test_bufpipe.vcd")
1019
1020 print ("test 2")
1021 dut = ExampleBufPipe2()
1022 run_simulation(dut, tbench2(dut), vcd_name="test_bufpipe2.vcd")
1023 ports = [dut.p.i_valid, dut.n.i_ready,
1024 dut.n.o_valid, dut.p.o_ready] + \
1025 [dut.p.i_data] + [dut.n.o_data]
1026 vl = rtlil.convert(dut, ports=ports)
1027 with open("test_bufpipe2.il", "w") as f:
1028 f.write(vl)
1029
1030
1031 print ("test 3")
1032 dut = ExampleBufPipe()
1033 test = Test3(dut, resultfn_3)
1034 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe3.vcd")
1035
1036 print ("test 3.5")
1037 dut = ExamplePipeline()
1038 test = Test3(dut, resultfn_3)
1039 run_simulation(dut, [test.send, test.rcv], vcd_name="test_combpipe3.vcd")
1040
1041 print ("test 4")
1042 dut = ExampleBufPipe2()
1043 run_simulation(dut, tbench4(dut), vcd_name="test_bufpipe4.vcd")
1044
1045 print ("test 5")
1046 dut = ExampleBufPipeAdd()
1047 test = Test5(dut, resultfn_5, stage_ctl=True)
1048 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe5.vcd")
1049
1050 print ("test 6")
1051 dut = ExampleLTPipeline()
1052 test = Test5(dut, resultfn_6)
1053 run_simulation(dut, [test.send, test.rcv], vcd_name="test_ltcomb6.vcd")
1054
1055 ports = [dut.p.i_valid, dut.n.i_ready,
1056 dut.n.o_valid, dut.p.o_ready] + \
1057 list(dut.p.i_data) + [dut.n.o_data]
1058 vl = rtlil.convert(dut, ports=ports)
1059 with open("test_ltcomb_pipe.il", "w") as f:
1060 f.write(vl)
1061
1062 print ("test 7")
1063 dut = ExampleAddRecordPipe()
1064 data=data_dict()
1065 test = Test5(dut, resultfn_7, data=data)
1066 ports = [dut.p.i_valid, dut.n.i_ready,
1067 dut.n.o_valid, dut.p.o_ready,
1068 dut.p.i_data.src1, dut.p.i_data.src2,
1069 dut.n.o_data.src1, dut.n.o_data.src2]
1070 vl = rtlil.convert(dut, ports=ports)
1071 with open("test_recordcomb_pipe.il", "w") as f:
1072 f.write(vl)
1073 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
1074
1075 print ("test 8")
1076 dut = ExampleBufPipeAddClass()
1077 data=data_2op()
1078 test = Test5(dut, resultfn_8, data=data)
1079 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe8.vcd")
1080
1081 print ("test 9")
1082 dut = ExampleBufPipeChain2()
1083 ports = [dut.p.i_valid, dut.n.i_ready,
1084 dut.n.o_valid, dut.p.o_ready] + \
1085 [dut.p.i_data] + [dut.n.o_data]
1086 vl = rtlil.convert(dut, ports=ports)
1087 with open("test_bufpipechain2.il", "w") as f:
1088 f.write(vl)
1089
1090 data = data_chain2()
1091 test = Test5(dut, resultfn_9, data=data)
1092 run_simulation(dut, [test.send, test.rcv],
1093 vcd_name="test_bufpipechain2.vcd")
1094
1095 print ("test 10")
1096 dut = ExampleLTBufferedPipeDerived()
1097 test = Test5(dut, resultfn_6)
1098 run_simulation(dut, [test.send, test.rcv], vcd_name="test_ltbufpipe10.vcd")
1099 vl = rtlil.convert(dut, ports=ports)
1100 with open("test_ltbufpipe10.il", "w") as f:
1101 f.write(vl)
1102
1103 print ("test 11")
1104 dut = ExampleAddRecordPlaceHolderPipe()
1105 data=data_placeholder()
1106 test = Test5(dut, resultfn_test11, data=data)
1107 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
1108
1109
1110 print ("test 12")
1111 dut = ExampleBufDelayedPipe()
1112 data = data_chain1()
1113 test = Test5(dut, resultfn_12, data=data)
1114 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe12.vcd")
1115 ports = [dut.p.i_valid, dut.n.i_ready,
1116 dut.n.o_valid, dut.p.o_ready] + \
1117 [dut.p.i_data] + [dut.n.o_data]
1118 vl = rtlil.convert(dut, ports=ports)
1119 with open("test_bufpipe12.il", "w") as f:
1120 f.write(vl)
1121
1122 print ("test 13")
1123 dut = ExampleUnBufDelayedPipe()
1124 data = data_chain1()
1125 test = Test5(dut, resultfn_12, data=data)
1126 run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe13.vcd")
1127 ports = [dut.p.i_valid, dut.n.i_ready,
1128 dut.n.o_valid, dut.p.o_ready] + \
1129 [dut.p.i_data] + [dut.n.o_data]
1130 vl = rtlil.convert(dut, ports=ports)
1131 with open("test_unbufpipe13.il", "w") as f:
1132 f.write(vl)
1133
1134 print ("test 15")
1135 dut = ExampleBufModeAdd1Pipe()
1136 data = data_chain1()
1137 test = Test5(dut, resultfn_12, data=data)
1138 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf15.vcd")
1139 ports = [dut.p.i_valid, dut.n.i_ready,
1140 dut.n.o_valid, dut.p.o_ready] + \
1141 [dut.p.i_data] + [dut.n.o_data]
1142 vl = rtlil.convert(dut, ports=ports)
1143 with open("test_bufunbuf15.il", "w") as f:
1144 f.write(vl)
1145
1146 print ("test 16")
1147 dut = ExampleBufModeUnBufPipe()
1148 data = data_chain1()
1149 test = Test5(dut, resultfn_9, data=data)
1150 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf16.vcd")
1151 ports = [dut.p.i_valid, dut.n.i_ready,
1152 dut.n.o_valid, dut.p.o_ready] + \
1153 [dut.p.i_data] + [dut.n.o_data]
1154 vl = rtlil.convert(dut, ports=ports)
1155 with open("test_bufunbuf16.il", "w") as f:
1156 f.write(vl)
1157
1158 print ("test 17")
1159 dut = ExampleUnBufAdd1Pipe2()
1160 data = data_chain1()
1161 test = Test5(dut, resultfn_12, data=data)
1162 run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe17.vcd")
1163 ports = [dut.p.i_valid, dut.n.i_ready,
1164 dut.n.o_valid, dut.p.o_ready] + \
1165 [dut.p.i_data] + [dut.n.o_data]
1166 vl = rtlil.convert(dut, ports=ports)
1167 with open("test_unbufpipe17.il", "w") as f:
1168 f.write(vl)
1169
1170 print ("test 18")
1171 dut = PassThroughTest()
1172 data = data_chain1()
1173 test = Test5(dut, resultfn_identical, data=data)
1174 run_simulation(dut, [test.send, test.rcv], vcd_name="test_passthru18.vcd")
1175 ports = [dut.p.i_valid, dut.n.i_ready,
1176 dut.n.o_valid, dut.p.o_ready] + \
1177 [dut.p.i_data] + [dut.n.o_data]
1178 vl = rtlil.convert(dut, ports=ports)
1179 with open("test_passthru18.il", "w") as f:
1180 f.write(vl)
1181
1182 print ("test 19")
1183 dut = ExampleBufPassThruPipe()
1184 data = data_chain1()
1185 test = Test5(dut, resultfn_9, data=data)
1186 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass19.vcd")
1187 ports = [dut.p.i_valid, dut.n.i_ready,
1188 dut.n.o_valid, dut.p.o_ready] + \
1189 [dut.p.i_data] + [dut.n.o_data]
1190 vl = rtlil.convert(dut, ports=ports)
1191 with open("test_bufpass19.il", "w") as f:
1192 f.write(vl)
1193
1194 print ("test 20")
1195 dut = FIFOTest16()
1196 data = data_chain1()
1197 test = Test5(dut, resultfn_identical, data=data)
1198 run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifo20.vcd")
1199 ports = [dut.p.i_valid, dut.n.i_ready,
1200 dut.n.o_valid, dut.p.o_ready] + \
1201 [dut.p.i_data] + [dut.n.o_data]
1202 vl = rtlil.convert(dut, ports=ports)
1203 with open("test_fifo20.il", "w") as f:
1204 f.write(vl)
1205
1206 print ("test 21")
1207 dut = ExampleFIFOPassThruPipe1()
1208 data = data_chain1()
1209 test = Test5(dut, resultfn_12, data=data)
1210 run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifopass21.vcd")
1211 ports = [dut.p.i_valid, dut.n.i_ready,
1212 dut.n.o_valid, dut.p.o_ready] + \
1213 [dut.p.i_data] + [dut.n.o_data]
1214 vl = rtlil.convert(dut, ports=ports)
1215 with open("test_fifopass21.il", "w") as f:
1216 f.write(vl)
1217
1218 print ("test 22")
1219 dut = ExampleRecordHandshakeAddClass()
1220 data=data_2op()
1221 test = Test5(dut, resultfn_8, data=data)
1222 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord22.vcd")
1223 ports = [dut.p.i_valid, dut.n.i_ready,
1224 dut.n.o_valid, dut.p.o_ready] + \
1225 [dut.p.i_data.op1, dut.p.i_data.op2] + \
1226 [dut.n.o_data]
1227 vl = rtlil.convert(dut, ports=ports)
1228 with open("test_addrecord22.il", "w") as f:
1229 f.write(vl)
1230
1231 print ("test 23")
1232 dut = ExampleFIFORecordObjectPipe()
1233 data=data_2op()
1234 test = Test5(dut, resultfn_8, data=data)
1235 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord23.vcd")
1236 ports = [dut.p.i_valid, dut.n.i_ready,
1237 dut.n.o_valid, dut.p.o_ready] + \
1238 [dut.p.i_data.op1, dut.p.i_data.op2] + \
1239 [dut.n.o_data]
1240 vl = rtlil.convert(dut, ports=ports)
1241 with open("test_addrecord23.il", "w") as f:
1242 f.write(vl)
1243
1244 print ("test 24")
1245 dut = FIFOTestRecordAddStageControl()
1246 data=data_2op()
1247 test = Test5(dut, resultfn_8, data=data)
1248 ports = [dut.p.i_valid, dut.n.i_ready,
1249 dut.n.o_valid, dut.p.o_ready] + \
1250 [dut.p.i_data.op1, dut.p.i_data.op2] + \
1251 [dut.n.o_data]
1252 vl = rtlil.convert(dut, ports=ports)
1253 with open("test_addrecord24.il", "w") as f:
1254 f.write(vl)
1255 run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord24.vcd")
1256
1257 print ("test 25")
1258 dut = ExampleFIFOAdd2Pipe()
1259 data = data_chain1()
1260 test = Test5(dut, resultfn_9, data=data)
1261 run_simulation(dut, [test.send, test.rcv], vcd_name="test_add2pipe25.vcd")
1262 ports = [dut.p.i_valid, dut.n.i_ready,
1263 dut.n.o_valid, dut.p.o_ready] + \
1264 [dut.p.i_data] + [dut.n.o_data]
1265 vl = rtlil.convert(dut, ports=ports)
1266 with open("test_add2pipe25.il", "w") as f:
1267 f.write(vl)
1268
1269 print ("test 997")
1270 dut = ExampleBufPassThruPipe2()
1271 data = data_chain1()
1272 test = Test5(dut, resultfn_9, data=data)
1273 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass997.vcd")
1274 ports = [dut.p.i_valid, dut.n.i_ready,
1275 dut.n.o_valid, dut.p.o_ready] + \
1276 [dut.p.i_data] + [dut.n.o_data]
1277 vl = rtlil.convert(dut, ports=ports)
1278 with open("test_bufpass997.il", "w") as f:
1279 f.write(vl)
1280
1281 print ("test 998 (fails, bug)")
1282 dut = ExampleBufPipe3()
1283 data = data_chain1()
1284 test = Test5(dut, resultfn_9, data=data)
1285 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe14.vcd")
1286 ports = [dut.p.i_valid, dut.n.i_ready,
1287 dut.n.o_valid, dut.p.o_ready] + \
1288 [dut.p.i_data] + [dut.n.o_data]
1289 vl = rtlil.convert(dut, ports=ports)
1290 with open("test_bufpipe14.il", "w") as f:
1291 f.write(vl)
1292
1293 print ("test 999 (expected to fail, which is a bug)")
1294 dut = ExampleBufUnBufPipe()
1295 data = data_chain1()
1296 test = Test5(dut, resultfn_9, data=data)
1297 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf999.vcd")
1298 ports = [dut.p.i_valid, dut.n.i_ready,
1299 dut.n.o_valid, dut.p.o_ready] + \
1300 [dut.p.i_data] + [dut.n.o_data]
1301 vl = rtlil.convert(dut, ports=ports)
1302 with open("test_bufunbuf999.il", "w") as f:
1303 f.write(vl)
1304