2dae49ea779c0beecbd073ba5e384760ad16f028
1 """ Unit tests for Buffered and Unbuffered pipelines
3 contains useful worked examples of how to use the Pipeline API,
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
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
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
34 from random
import randint
, seed
39 def check_o_n_valid(dut
, val
):
40 o_n_valid
= yield dut
.n
.o_valid
41 assert o_n_valid
== val
43 def check_o_n_valid2(dut
, val
):
44 o_n_valid
= yield dut
.n
.o_valid
45 assert o_n_valid
== val
49 #yield dut.i_p_rst.eq(1)
50 yield dut
.n
.i_ready
.eq(0)
51 #yield dut.p.ready_o.eq(0)
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)
60 yield dut
.p
.i_data
.eq(7)
61 yield from check_o_n_valid(dut
, 0) # effects of i_p_valid delayed
63 yield from check_o_n_valid(dut
, 1) # ok *now* i_p_valid effect is felt
65 yield dut
.p
.i_data
.eq(2)
67 yield dut
.n
.i_ready
.eq(0) # begin going into "stall" (next stage says ready)
68 yield dut
.p
.i_data
.eq(9)
70 yield dut
.p
.i_valid
.eq(0)
71 yield dut
.p
.i_data
.eq(12)
73 yield dut
.p
.i_data
.eq(32)
74 yield dut
.n
.i_ready
.eq(1)
76 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
78 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
80 yield from check_o_n_valid(dut
, 0) # buffer outputted, *now* we're done.
85 #yield dut.p.i_rst.eq(1)
86 yield dut
.n
.i_ready
.eq(0)
87 #yield dut.p.ready_o.eq(0)
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)
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
99 yield from check_o_n_valid2(dut
, 0) # effects of i_p_valid delayed 2 clocks
101 yield dut
.p
.i_data
.eq(2)
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)
107 yield dut
.p
.i_valid
.eq(0)
108 yield dut
.p
.i_data
.eq(12)
110 yield dut
.p
.i_data
.eq(32)
111 yield dut
.n
.i_ready
.eq(1)
113 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
115 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
117 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
119 yield from check_o_n_valid2(dut
, 0) # buffer outputted, *now* we're done.
126 def __init__(self
, dut
, resultfn
):
128 self
.resultfn
= resultfn
130 for i
in range(num_tests
):
131 #data.append(randint(0, 1<<16-1))
132 self
.data
.append(i
+1)
137 while self
.o
!= len(self
.data
):
138 send_range
= randint(0, 3)
139 for j
in range(randint(1,10)):
143 send
= randint(0, send_range
) != 0
144 o_p_ready
= yield self
.dut
.p
.ready_o
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
])
153 yield self
.dut
.p
.i_valid
.eq(0)
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
)
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
:
167 o_data
= yield self
.dut
.n
.o_data
168 self
.resultfn(o_data
, self
.data
[self
.o
], self
.i
, self
.o
)
170 if self
.o
== len(self
.data
):
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
)
178 def data_placeholder():
180 for i
in range(num_tests
):
182 d
.src1
= randint(0, 1<<16-1)
183 d
.src2
= randint(0, 1<<16-1)
189 for i
in range(num_tests
):
190 data
.append({'src1': randint(0, 1<<16-1),
191 'src2': randint(0, 1<<16-1)})
196 def __init__(self
, dut
, resultfn
, data
=None, stage_ctl
=False):
198 self
.resultfn
= resultfn
199 self
.stage_ctl
= stage_ctl
204 for i
in range(num_tests
):
205 self
.data
.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
210 while self
.o
!= len(self
.data
):
211 send_range
= randint(0, 3)
212 for j
in range(randint(1,10)):
216 send
= randint(0, send_range
) != 0
218 o_p_ready
= yield self
.dut
.p
.ready_o
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
]):
228 yield self
.dut
.p
.i_valid
.eq(0)
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
237 yield self
.dut
.n
.i_ready
.eq(ready
)
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
:
243 if isinstance(self
.dut
.n
.o_data
, Record
):
245 dod
= self
.dut
.n
.o_data
246 for k
, v
in dod
.fields
.items():
249 o_data
= yield self
.dut
.n
.o_data
250 self
.resultfn(o_data
, self
.data
[self
.o
], self
.i
, self
.o
)
252 if self
.o
== len(self
.data
):
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
))
263 for i
in range(num_tests
):
264 #data.append(randint(0, 1<<16-1))
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
.ready_o
274 if send
and i
!= len(data
):
275 yield dut
.p
.i_valid
.eq(1)
276 yield dut
.p
.i_data
.eq(data
[i
])
279 yield dut
.p
.i_valid
.eq(0)
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
])
291 ######################################################################
293 ######################################################################
295 class ExampleBufPipe2(ControlBase
):
296 """ Example of how to do chained pipeline stages.
299 def elaborate(self
, platform
):
300 m
= ControlBase
.elaborate(self
, platform
)
302 pipe1
= ExampleBufPipe()
303 pipe2
= ExampleBufPipe()
305 m
.submodules
.pipe1
= pipe1
306 m
.submodules
.pipe2
= pipe2
308 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
313 ######################################################################
315 ######################################################################
317 class ExampleBufPipeChain2(BufferedHandshake
):
318 """ connects two stages together as a *single* combinatorial stage.
321 stage1
= ExampleStageCls()
322 stage2
= ExampleStageCls()
323 combined
= StageChain([stage1
, stage2
])
324 BufferedHandshake
.__init
__(self
, combined
)
329 for i
in range(num_tests
):
330 data
.append(randint(0, 1<<16-2))
334 def resultfn_9(o_data
, expected
, i
, o
):
336 assert o_data
== res
, \
337 "%d-%d received data %x not match expected %x\n" \
338 % (i
, o
, o_data
, res
)
341 ######################################################################
343 ######################################################################
345 class SetLessThan(Elaboratable
):
346 def __init__(self
, width
, signed
):
348 self
.src1
= Signal((width
, signed
), name
="src1")
349 self
.src2
= Signal((width
, signed
), name
="src2")
350 self
.output
= Signal(width
, name
="out")
352 def elaborate(self
, platform
):
353 self
.m
.d
.comb
+= self
.output
.eq(Mux(self
.src1
< self
.src2
, 1, 0))
357 class LTStage(StageCls
):
358 """ module-based stage example
361 self
.slt
= SetLessThan(16, True)
363 def ispec(self
, name
):
364 return (Signal(16, name
="%s_sig1" % name
),
365 Signal(16, name
="%s_sig2" % name
))
367 def ospec(self
, name
):
368 return Signal(16, "%s_out" % name
)
370 def setup(self
, m
, i
):
372 m
.submodules
.slt
= self
.slt
373 m
.d
.comb
+= self
.slt
.src1
.eq(i
[0])
374 m
.d
.comb
+= self
.slt
.src2
.eq(i
[1])
375 m
.d
.comb
+= self
.o
.eq(self
.slt
.output
)
377 def process(self
, i
):
381 class LTStageDerived(SetLessThan
, StageCls
, Elaboratable
):
382 """ special version of a nmigen module where the module is also a stage
384 shows that you don't actually need to combinatorially connect
385 to the outputs, or add the module as a submodule: just return
386 the module output parameter(s) from the Stage.process() function
390 SetLessThan
.__init
__(self
, 16, True)
393 return (Signal(16), Signal(16))
398 def setup(self
, m
, i
):
399 m
.submodules
.slt
= self
400 m
.d
.comb
+= self
.src1
.eq(i
[0])
401 m
.d
.comb
+= self
.src2
.eq(i
[1])
403 def process(self
, i
):
407 class ExampleLTPipeline(UnbufferedPipeline
):
408 """ an example of how to use the unbuffered pipeline.
413 UnbufferedPipeline
.__init
__(self
, stage
)
416 class ExampleLTBufferedPipeDerived(BufferedHandshake
):
417 """ an example of how to use the buffered pipeline.
421 stage
= LTStageDerived()
422 BufferedHandshake
.__init
__(self
, stage
)
425 def resultfn_6(o_data
, expected
, i
, o
):
426 res
= 1 if expected
[0] < expected
[1] else 0
427 assert o_data
== res
, \
428 "%d-%d data %x not match %s\n" \
429 % (i
, o
, o_data
, repr(expected
))
432 ######################################################################
434 ######################################################################
436 class ExampleAddRecordStage(StageCls
):
437 """ example use of a Record
440 record_spec
= [('src1', 16), ('src2', 16)]
442 """ returns a Record using the specification
444 return Record(self
.record_spec
)
447 return Record(self
.record_spec
)
449 def process(self
, i
):
450 """ process the input data, returning a dictionary with key names
451 that exactly match the Record's attributes.
453 return {'src1': i
.src1
+ 1,
456 ######################################################################
458 ######################################################################
460 class ExampleAddRecordPlaceHolderStage(StageCls
):
461 """ example use of a Record, with a placeholder as the processing result
464 record_spec
= [('src1', 16), ('src2', 16)]
466 """ returns a Record using the specification
468 return Record(self
.record_spec
)
471 return Record(self
.record_spec
)
473 def process(self
, i
):
474 """ process the input data, returning a PlaceHolder class instance
475 with attributes that exactly match those of the Record.
483 class PlaceHolder
: pass
486 class ExampleAddRecordPipe(UnbufferedPipeline
):
487 """ an example of how to use the combinatorial pipeline.
491 stage
= ExampleAddRecordStage()
492 UnbufferedPipeline
.__init
__(self
, stage
)
495 def resultfn_7(o_data
, expected
, i
, o
):
496 res
= (expected
['src1'] + 1, expected
['src2'] + 1)
497 assert o_data
['src1'] == res
[0] and o_data
['src2'] == res
[1], \
498 "%d-%d data %s not match %s\n" \
499 % (i
, o
, repr(o_data
), repr(expected
))
502 class ExampleAddRecordPlaceHolderPipe(UnbufferedPipeline
):
503 """ an example of how to use the combinatorial pipeline.
507 stage
= ExampleAddRecordPlaceHolderStage()
508 UnbufferedPipeline
.__init
__(self
, stage
)
511 def resultfn_test11(o_data
, expected
, i
, o
):
512 res1
= expected
.src1
+ 1
513 res2
= expected
.src2
+ 1
514 assert o_data
['src1'] == res1
and o_data
['src2'] == res2
, \
515 "%d-%d data %s not match %s\n" \
516 % (i
, o
, repr(o_data
), repr(expected
))
519 ######################################################################
521 ######################################################################
524 class Example2OpClass
:
525 """ an example of a class used to store 2 operands.
526 requires an eq function, to conform with the pipeline stage API
530 self
.op1
= Signal(16)
531 self
.op2
= Signal(16)
534 return [self
.op1
.eq(i
.op1
), self
.op2
.eq(i
.op2
)]
537 class ExampleAddClassStage(StageCls
):
538 """ an example of how to use the buffered pipeline, as a class instance
542 """ returns an instance of an Example2OpClass.
544 return Example2OpClass()
547 """ returns an output signal which will happen to contain the sum
552 def process(self
, i
):
553 """ process the input data (sums the values in the tuple) and returns it
558 class ExampleBufPipeAddClass(BufferedHandshake
):
559 """ an example of how to use the buffered pipeline, using a class instance
563 addstage
= ExampleAddClassStage()
564 BufferedHandshake
.__init
__(self
, addstage
)
568 """ the eq function, called by set_input, needs an incoming object
569 that conforms to the Example2OpClass.eq function requirements
570 easiest way to do that is to create a class that has the exact
571 same member layout (self.op1, self.op2) as Example2OpClass
573 def __init__(self
, op1
, op2
):
578 def resultfn_8(o_data
, expected
, i
, o
):
579 res
= expected
.op1
+ expected
.op2
# these are a TestInputAdd instance
580 assert o_data
== res
, \
581 "%d-%d data %s res %x not match %s\n" \
582 % (i
, o
, repr(o_data
), res
, repr(expected
))
586 for i
in range(num_tests
):
587 data
.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
591 ######################################################################
593 ######################################################################
595 class ExampleStageDelayCls(StageCls
, Elaboratable
):
596 """ an example of how to use the buffered pipeline, in a static class
600 def __init__(self
, valid_trigger
=2):
601 self
.count
= Signal(2)
602 self
.valid_trigger
= valid_trigger
605 return Signal(16, name
="example_input_signal")
608 return Signal(16, name
="example_output_signal")
612 """ data is ready to be accepted when this is true
614 return (self
.count
== 1)# | (self.count == 3)
617 def d_valid(self
, i_ready
):
618 """ data is valid at output when this is true
620 return self
.count
== self
.valid_trigger
623 def process(self
, i
):
624 """ process the input data and returns it (adds 1)
628 def elaborate(self
, platform
):
630 m
.d
.sync
+= self
.count
.eq(self
.count
+ 1)
634 class ExampleBufDelayedPipe(BufferedHandshake
):
637 stage
= ExampleStageDelayCls(valid_trigger
=2)
638 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
640 def elaborate(self
, platform
):
641 m
= BufferedHandshake
.elaborate(self
, platform
)
642 m
.submodules
.stage
= self
.stage
648 for i
in range(num_tests
):
649 data
.append(1<<((i
*3)%15))
650 #data.append(randint(0, 1<<16-2))
651 #print (hex(data[-1]))
655 def resultfn_12(o_data
, expected
, i
, o
):
657 assert o_data
== res
, \
658 "%d-%d data %x not match %x\n" \
659 % (i
, o
, o_data
, res
)
662 ######################################################################
664 ######################################################################
666 class ExampleUnBufDelayedPipe(BufferedHandshake
):
669 stage
= ExampleStageDelayCls(valid_trigger
=3)
670 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
672 def elaborate(self
, platform
):
673 m
= BufferedHandshake
.elaborate(self
, platform
)
674 m
.submodules
.stage
= self
.stage
677 ######################################################################
679 ######################################################################
681 class ExampleBufModeAdd1Pipe(SimpleHandshake
):
684 stage
= ExampleStageCls()
685 SimpleHandshake
.__init
__(self
, stage
)
688 ######################################################################
690 ######################################################################
692 class ExampleBufModeUnBufPipe(ControlBase
):
694 def elaborate(self
, platform
):
695 m
= ControlBase
.elaborate(self
, platform
)
697 pipe1
= ExampleBufModeAdd1Pipe()
698 pipe2
= ExampleBufAdd1Pipe()
700 m
.submodules
.pipe1
= pipe1
701 m
.submodules
.pipe2
= pipe2
703 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
707 ######################################################################
709 ######################################################################
711 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2
):
714 stage
= ExampleStageCls()
715 UnbufferedPipeline2
.__init__(self
, stage
)
718 ######################################################################
720 ######################################################################
722 class PassThroughTest(PassThroughHandshake
):
725 return Signal(16, "out")
728 stage
= PassThroughStage(self
.iospecfn
)
729 PassThroughHandshake
.__init
__(self
, stage
)
731 def resultfn_identical(o_data
, expected
, i
, o
):
733 assert o_data
== res
, \
734 "%d-%d data %x not match %x\n" \
735 % (i
, o
, o_data
, res
)
738 ######################################################################
740 ######################################################################
742 class ExamplePassAdd1Pipe(PassThroughHandshake
):
745 stage
= ExampleStageCls()
746 PassThroughHandshake
.__init
__(self
, stage
)
749 class ExampleBufPassThruPipe(ControlBase
):
751 def elaborate(self
, platform
):
752 m
= ControlBase
.elaborate(self
, platform
)
754 # XXX currently fails: any other permutation works fine.
755 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
756 # also fails using UnbufferedPipeline as well
757 pipe1
= ExampleBufModeAdd1Pipe()
758 pipe2
= ExamplePassAdd1Pipe()
760 m
.submodules
.pipe1
= pipe1
761 m
.submodules
.pipe2
= pipe2
763 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
768 ######################################################################
770 ######################################################################
773 return Signal(16, name
="d_in")
775 class FIFOTest16(FIFOControl
):
778 stage
= PassThroughStage(iospecfn
)
779 FIFOControl
.__init
__(self
, 2, stage
)
782 ######################################################################
784 ######################################################################
786 class ExampleFIFOPassThruPipe1(ControlBase
):
788 def elaborate(self
, platform
):
789 m
= ControlBase
.elaborate(self
, platform
)
792 pipe2
= ExamplePassAdd1Pipe()
794 m
.submodules
.pipe1
= pipe1
795 m
.submodules
.pipe2
= pipe2
797 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
802 ######################################################################
804 ######################################################################
806 class Example2OpRecord(RecordObject
):
808 RecordObject
.__init
__(self
)
809 self
.op1
= Signal(16)
810 self
.op2
= Signal(16)
813 class ExampleAddRecordObjectStage(StageCls
):
816 """ returns an instance of an Example2OpRecord.
818 return Example2OpRecord()
821 """ returns an output signal which will happen to contain the sum
826 def process(self
, i
):
827 """ process the input data (sums the values in the tuple) and returns it
832 class ExampleRecordHandshakeAddClass(SimpleHandshake
):
835 addstage
= ExampleAddRecordObjectStage()
836 SimpleHandshake
.__init
__(self
, stage
=addstage
)
839 ######################################################################
841 ######################################################################
843 def iospecfnrecord():
844 return Example2OpRecord()
846 class FIFOTestRecordControl(FIFOControl
):
849 stage
= PassThroughStage(iospecfnrecord
)
850 FIFOControl
.__init
__(self
, 2, stage
)
853 class ExampleFIFORecordObjectPipe(ControlBase
):
855 def elaborate(self
, platform
):
856 m
= ControlBase
.elaborate(self
, platform
)
858 pipe1
= FIFOTestRecordControl()
859 pipe2
= ExampleRecordHandshakeAddClass()
861 m
.submodules
.pipe1
= pipe1
862 m
.submodules
.pipe2
= pipe2
864 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
869 ######################################################################
871 ######################################################################
873 class FIFOTestRecordAddStageControl(FIFOControl
):
876 stage
= ExampleAddRecordObjectStage()
877 FIFOControl
.__init
__(self
, 2, stage
)
881 ######################################################################
883 ######################################################################
885 class FIFOTestAdd16(FIFOControl
):
888 stage
= ExampleStageCls()
889 FIFOControl
.__init
__(self
, 2, stage
)
892 class ExampleFIFOAdd2Pipe(ControlBase
):
894 def elaborate(self
, platform
):
895 m
= ControlBase
.elaborate(self
, platform
)
897 pipe1
= FIFOTestAdd16()
898 pipe2
= FIFOTestAdd16()
900 m
.submodules
.pipe1
= pipe1
901 m
.submodules
.pipe2
= pipe2
903 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
908 ######################################################################
910 ######################################################################
913 return (Signal(16, name
="src1"), Signal(16, name
="src2"))
915 class FIFOTest2x16(FIFOControl
):
918 stage
= PassThroughStage(iospecfn2
)
919 FIFOControl
.__init
__(self
, 2, stage
)
922 ######################################################################
924 ######################################################################
926 class ExampleBufPassThruPipe2(ControlBase
):
928 def elaborate(self
, platform
):
929 m
= ControlBase
.elaborate(self
, platform
)
931 # XXX currently fails: any other permutation works fine.
932 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
933 # also fails using UnbufferedPipeline as well
934 #pipe1 = ExampleUnBufAdd1Pipe()
935 #pipe2 = ExampleBufAdd1Pipe()
936 pipe1
= ExampleBufAdd1Pipe()
937 pipe2
= ExamplePassAdd1Pipe()
939 m
.submodules
.pipe1
= pipe1
940 m
.submodules
.pipe2
= pipe2
942 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
947 ######################################################################
949 ######################################################################
951 class ExampleBufPipe3(ControlBase
):
952 """ Example of how to do delayed pipeline, where the stage signals
956 def elaborate(self
, platform
):
957 m
= ControlBase
.elaborate(self
, platform
)
959 pipe1
= ExampleBufDelayedPipe()
960 pipe2
= ExampleBufPipe()
962 m
.submodules
.pipe1
= pipe1
963 m
.submodules
.pipe2
= pipe2
965 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
969 ######################################################################
970 # Test 999 - XXX FAILS
971 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
972 ######################################################################
974 class ExampleBufAdd1Pipe(BufferedHandshake
):
977 stage
= ExampleStageCls()
978 BufferedHandshake
.__init
__(self
, stage
)
981 class ExampleUnBufAdd1Pipe(UnbufferedPipeline
):
984 stage
= ExampleStageCls()
985 UnbufferedPipeline
.__init
__(self
, stage
)
988 class ExampleBufUnBufPipe(ControlBase
):
990 def elaborate(self
, platform
):
991 m
= ControlBase
.elaborate(self
, platform
)
993 # XXX currently fails: any other permutation works fine.
994 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
995 # also fails using UnbufferedPipeline as well
996 #pipe1 = ExampleUnBufAdd1Pipe()
997 #pipe2 = ExampleBufAdd1Pipe()
998 pipe1
= ExampleBufAdd1Pipe()
999 pipe2
= ExampleUnBufAdd1Pipe()
1001 m
.submodules
.pipe1
= pipe1
1002 m
.submodules
.pipe2
= pipe2
1004 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1009 ######################################################################
1011 ######################################################################
1015 if __name__
== '__main__':
1018 dut
= ExampleBufPipe()
1019 run_simulation(dut
, tbench(dut
), vcd_name
="test_bufpipe.vcd")
1022 dut
= ExampleBufPipe2()
1023 run_simulation(dut
, tbench2(dut
), vcd_name
="test_bufpipe2.vcd")
1024 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1025 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1026 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1027 vl
= rtlil
.convert(dut
, ports
=ports
)
1028 with
open("test_bufpipe2.il", "w") as f
:
1033 dut
= ExampleBufPipe()
1034 test
= Test3(dut
, resultfn_3
)
1035 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
1038 dut
= ExamplePipeline()
1039 test
= Test3(dut
, resultfn_3
)
1040 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
1043 dut
= ExampleBufPipe2()
1044 run_simulation(dut
, tbench4(dut
), vcd_name
="test_bufpipe4.vcd")
1047 dut
= ExampleBufPipeAdd()
1048 test
= Test5(dut
, resultfn_5
, stage_ctl
=True)
1049 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe5.vcd")
1052 dut
= ExampleLTPipeline()
1053 test
= Test5(dut
, resultfn_6
)
1054 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
1056 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1057 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1058 list(dut
.p
.i_data
) + [dut
.n
.o_data
]
1059 vl
= rtlil
.convert(dut
, ports
=ports
)
1060 with
open("test_ltcomb_pipe.il", "w") as f
:
1064 dut
= ExampleAddRecordPipe()
1066 test
= Test5(dut
, resultfn_7
, data
=data
)
1067 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1068 dut
.n
.o_valid
, dut
.p
.ready_o
,
1069 dut
.p
.i_data
.src1
, dut
.p
.i_data
.src2
,
1070 dut
.n
.o_data
.src1
, dut
.n
.o_data
.src2
]
1071 vl
= rtlil
.convert(dut
, ports
=ports
)
1072 with
open("test_recordcomb_pipe.il", "w") as f
:
1074 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1077 dut
= ExampleBufPipeAddClass()
1079 test
= Test5(dut
, resultfn_8
, data
=data
)
1080 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")
1083 dut
= ExampleBufPipeChain2()
1084 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1085 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1086 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1087 vl
= rtlil
.convert(dut
, ports
=ports
)
1088 with
open("test_bufpipechain2.il", "w") as f
:
1091 data
= data_chain2()
1092 test
= Test5(dut
, resultfn_9
, data
=data
)
1093 run_simulation(dut
, [test
.send
, test
.rcv
],
1094 vcd_name
="test_bufpipechain2.vcd")
1097 dut
= ExampleLTBufferedPipeDerived()
1098 test
= Test5(dut
, resultfn_6
)
1099 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltbufpipe10.vcd")
1100 vl
= rtlil
.convert(dut
, ports
=ports
)
1101 with
open("test_ltbufpipe10.il", "w") as f
:
1105 dut
= ExampleAddRecordPlaceHolderPipe()
1106 data
=data_placeholder()
1107 test
= Test5(dut
, resultfn_test11
, data
=data
)
1108 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1112 dut
= ExampleBufDelayedPipe()
1113 data
= data_chain1()
1114 test
= Test5(dut
, resultfn_12
, data
=data
)
1115 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe12.vcd")
1116 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1117 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1118 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1119 vl
= rtlil
.convert(dut
, ports
=ports
)
1120 with
open("test_bufpipe12.il", "w") as f
:
1124 dut
= ExampleUnBufDelayedPipe()
1125 data
= data_chain1()
1126 test
= Test5(dut
, resultfn_12
, data
=data
)
1127 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe13.vcd")
1128 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1129 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1130 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1131 vl
= rtlil
.convert(dut
, ports
=ports
)
1132 with
open("test_unbufpipe13.il", "w") as f
:
1136 dut
= ExampleBufModeAdd1Pipe()
1137 data
= data_chain1()
1138 test
= Test5(dut
, resultfn_12
, data
=data
)
1139 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf15.vcd")
1140 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1141 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1142 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1143 vl
= rtlil
.convert(dut
, ports
=ports
)
1144 with
open("test_bufunbuf15.il", "w") as f
:
1148 dut
= ExampleBufModeUnBufPipe()
1149 data
= data_chain1()
1150 test
= Test5(dut
, resultfn_9
, data
=data
)
1151 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf16.vcd")
1152 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1153 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1154 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1155 vl
= rtlil
.convert(dut
, ports
=ports
)
1156 with
open("test_bufunbuf16.il", "w") as f
:
1160 dut
= ExampleUnBufAdd1Pipe2()
1161 data
= data_chain1()
1162 test
= Test5(dut
, resultfn_12
, data
=data
)
1163 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe17.vcd")
1164 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1165 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1166 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1167 vl
= rtlil
.convert(dut
, ports
=ports
)
1168 with
open("test_unbufpipe17.il", "w") as f
:
1172 dut
= PassThroughTest()
1173 data
= data_chain1()
1174 test
= Test5(dut
, resultfn_identical
, data
=data
)
1175 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_passthru18.vcd")
1176 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1177 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1178 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1179 vl
= rtlil
.convert(dut
, ports
=ports
)
1180 with
open("test_passthru18.il", "w") as f
:
1184 dut
= ExampleBufPassThruPipe()
1185 data
= data_chain1()
1186 test
= Test5(dut
, resultfn_9
, data
=data
)
1187 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass19.vcd")
1188 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1189 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1190 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1191 vl
= rtlil
.convert(dut
, ports
=ports
)
1192 with
open("test_bufpass19.il", "w") as f
:
1197 data
= data_chain1()
1198 test
= Test5(dut
, resultfn_identical
, data
=data
)
1199 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifo20.vcd")
1200 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1201 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1202 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1203 vl
= rtlil
.convert(dut
, ports
=ports
)
1204 with
open("test_fifo20.il", "w") as f
:
1208 dut
= ExampleFIFOPassThruPipe1()
1209 data
= data_chain1()
1210 test
= Test5(dut
, resultfn_12
, data
=data
)
1211 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifopass21.vcd")
1212 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1213 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1214 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1215 vl
= rtlil
.convert(dut
, ports
=ports
)
1216 with
open("test_fifopass21.il", "w") as f
:
1220 dut
= ExampleRecordHandshakeAddClass()
1222 test
= Test5(dut
, resultfn_8
, data
=data
)
1223 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord22.vcd")
1224 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1225 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1226 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1228 vl
= rtlil
.convert(dut
, ports
=ports
)
1229 with
open("test_addrecord22.il", "w") as f
:
1233 dut
= ExampleFIFORecordObjectPipe()
1235 test
= Test5(dut
, resultfn_8
, data
=data
)
1236 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord23.vcd")
1237 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1238 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1239 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1241 vl
= rtlil
.convert(dut
, ports
=ports
)
1242 with
open("test_addrecord23.il", "w") as f
:
1246 dut
= FIFOTestRecordAddStageControl()
1248 test
= Test5(dut
, resultfn_8
, data
=data
)
1249 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1250 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1251 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1253 vl
= rtlil
.convert(dut
, ports
=ports
)
1254 with
open("test_addrecord24.il", "w") as f
:
1256 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord24.vcd")
1259 dut
= ExampleFIFOAdd2Pipe()
1260 data
= data_chain1()
1261 test
= Test5(dut
, resultfn_9
, data
=data
)
1262 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_add2pipe25.vcd")
1263 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1264 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1265 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1266 vl
= rtlil
.convert(dut
, ports
=ports
)
1267 with
open("test_add2pipe25.il", "w") as f
:
1271 dut
= ExampleBufPassThruPipe2()
1272 data
= data_chain1()
1273 test
= Test5(dut
, resultfn_9
, data
=data
)
1274 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass997.vcd")
1275 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1276 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1277 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1278 vl
= rtlil
.convert(dut
, ports
=ports
)
1279 with
open("test_bufpass997.il", "w") as f
:
1282 print ("test 998 (fails, bug)")
1283 dut
= ExampleBufPipe3()
1284 data
= data_chain1()
1285 test
= Test5(dut
, resultfn_9
, data
=data
)
1286 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe14.vcd")
1287 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1288 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1289 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1290 vl
= rtlil
.convert(dut
, ports
=ports
)
1291 with
open("test_bufpipe14.il", "w") as f
:
1294 print ("test 999 (expected to fail, which is a bug)")
1295 dut
= ExampleBufUnBufPipe()
1296 data
= data_chain1()
1297 test
= Test5(dut
, resultfn_9
, data
=data
)
1298 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf999.vcd")
1299 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1300 dut
.n
.o_valid
, dut
.p
.ready_o
] + \
1301 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1302 vl
= rtlil
.convert(dut
, ports
=ports
)
1303 with
open("test_bufunbuf999.il", "w") as f
: