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
.valid_o
41 assert o_n_valid
== val
43 def check_o_n_valid2(dut
, val
):
44 o_n_valid
= yield dut
.n
.valid_o
45 assert o_n_valid
== val
49 #yield dut.i_p_rst.eq(1)
50 yield dut
.n
.ready_i
.eq(0)
51 #yield dut.p.ready_o.eq(0)
54 #yield dut.i_p_rst.eq(0)
55 yield dut
.n
.ready_i
.eq(1)
56 yield dut
.p
.data_i
.eq(5)
57 yield dut
.p
.valid_i
.eq(1)
60 yield dut
.p
.data_i
.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
.data_i
.eq(2)
67 yield dut
.n
.ready_i
.eq(0) # begin going into "stall" (next stage says ready)
68 yield dut
.p
.data_i
.eq(9)
70 yield dut
.p
.valid_i
.eq(0)
71 yield dut
.p
.data_i
.eq(12)
73 yield dut
.p
.data_i
.eq(32)
74 yield dut
.n
.ready_i
.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
.ready_i
.eq(0)
87 #yield dut.p.ready_o.eq(0)
90 #yield dut.p.i_rst.eq(0)
91 yield dut
.n
.ready_i
.eq(1)
92 yield dut
.p
.data_i
.eq(5)
93 yield dut
.p
.valid_i
.eq(1)
96 yield dut
.p
.data_i
.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
.data_i
.eq(2)
103 yield from check_o_n_valid2(dut
, 1) # ok *now* i_p_valid effect is felt
104 yield dut
.n
.ready_i
.eq(0) # begin going into "stall" (next stage says ready)
105 yield dut
.p
.data_i
.eq(9)
107 yield dut
.p
.valid_i
.eq(0)
108 yield dut
.p
.data_i
.eq(12)
110 yield dut
.p
.data_i
.eq(32)
111 yield dut
.n
.ready_i
.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
.valid_i
.eq(1)
150 yield self
.dut
.p
.data_i
.eq(self
.data
[self
.i
])
153 yield self
.dut
.p
.valid_i
.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
.ready_i
.eq(stall
)
163 o_n_valid
= yield self
.dut
.n
.valid_o
164 i_n_ready
= yield self
.dut
.n
.ready_i_test
165 if not o_n_valid
or not i_n_ready
:
167 data_o
= yield self
.dut
.n
.data_o
168 self
.resultfn(data_o
, self
.data
[self
.o
], self
.i
, self
.o
)
170 if self
.o
== len(self
.data
):
173 def resultfn_3(data_o
, expected
, i
, o
):
174 assert data_o
== expected
+ 1, \
175 "%d-%d data %x not match %x\n" \
176 % (i
, o
, data_o
, 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
.valid_i
.eq(1)
224 for v
in self
.dut
.set_input(self
.data
[self
.i
]):
228 yield self
.dut
.p
.valid_i
.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
.ready_i
.eq(ready
)
239 o_n_valid
= yield self
.dut
.n
.valid_o
240 i_n_ready
= yield self
.dut
.n
.ready_i_test
241 if not o_n_valid
or not i_n_ready
:
243 if isinstance(self
.dut
.n
.data_o
, Record
):
245 dod
= self
.dut
.n
.data_o
246 for k
, v
in dod
.fields
.items():
249 data_o
= yield self
.dut
.n
.data_o
250 self
.resultfn(data_o
, self
.data
[self
.o
], self
.i
, self
.o
)
252 if self
.o
== len(self
.data
):
255 def resultfn_5(data_o
, expected
, i
, o
):
256 res
= expected
[0] + expected
[1]
257 assert data_o
== res
, \
258 "%d-%d data %x not match %s\n" \
259 % (i
, o
, data_o
, 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
.ready_i
.eq(stall
)
272 o_p_ready
= yield dut
.p
.ready_o
274 if send
and i
!= len(data
):
275 yield dut
.p
.valid_i
.eq(1)
276 yield dut
.p
.data_i
.eq(data
[i
])
279 yield dut
.p
.valid_i
.eq(0)
281 o_n_valid
= yield dut
.n
.valid_o
282 i_n_ready
= yield dut
.n
.ready_i_test
283 if o_n_valid
and i_n_ready
:
284 data_o
= yield dut
.n
.data_o
285 assert data_o
== data
[o
] + 2, "%d-%d data %x not match %x\n" \
286 % (i
, o
, data_o
, 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(data_o
, expected
, i
, o
):
336 assert data_o
== res
, \
337 "%d-%d received data %x not match expected %x\n" \
338 % (i
, o
, data_o
, 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
):
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(data_o
, expected
, i
, o
):
426 res
= 1 if expected
[0] < expected
[1] else 0
427 assert data_o
== res
, \
428 "%d-%d data %x not match %s\n" \
429 % (i
, o
, data_o
, 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 # a dummy class that may have stuff assigned to instances once created
484 class PlaceHolder
: pass
487 class ExampleAddRecordPipe(UnbufferedPipeline
):
488 """ an example of how to use the combinatorial pipeline.
492 stage
= ExampleAddRecordStage()
493 UnbufferedPipeline
.__init
__(self
, stage
)
496 def resultfn_7(data_o
, expected
, i
, o
):
497 res
= (expected
['src1'] + 1, expected
['src2'] + 1)
498 assert data_o
['src1'] == res
[0] and data_o
['src2'] == res
[1], \
499 "%d-%d data %s not match %s\n" \
500 % (i
, o
, repr(data_o
), repr(expected
))
503 class ExampleAddRecordPlaceHolderPipe(UnbufferedPipeline
):
504 """ an example of how to use the combinatorial pipeline.
508 stage
= ExampleAddRecordPlaceHolderStage()
509 UnbufferedPipeline
.__init
__(self
, stage
)
512 def resultfn_test11(data_o
, expected
, i
, o
):
513 res1
= expected
.src1
+ 1
514 res2
= expected
.src2
+ 1
515 assert data_o
['src1'] == res1
and data_o
['src2'] == res2
, \
516 "%d-%d data %s not match %s\n" \
517 % (i
, o
, repr(data_o
), repr(expected
))
520 ######################################################################
522 ######################################################################
525 class Example2OpClass
:
526 """ an example of a class used to store 2 operands.
527 requires an eq function, to conform with the pipeline stage API
531 self
.op1
= Signal(16)
532 self
.op2
= Signal(16)
535 return [self
.op1
.eq(i
.op1
), self
.op2
.eq(i
.op2
)]
538 class ExampleAddClassStage(StageCls
):
539 """ an example of how to use the buffered pipeline, as a class instance
543 """ returns an instance of an Example2OpClass.
545 return Example2OpClass()
548 """ returns an output signal which will happen to contain the sum
551 return Signal(16, name
="add2_out")
553 def process(self
, i
):
554 """ process the input data (sums the values in the tuple) and returns it
559 class ExampleBufPipeAddClass(BufferedHandshake
):
560 """ an example of how to use the buffered pipeline, using a class instance
564 addstage
= ExampleAddClassStage()
565 BufferedHandshake
.__init
__(self
, addstage
)
569 """ the eq function, called by set_input, needs an incoming object
570 that conforms to the Example2OpClass.eq function requirements
571 easiest way to do that is to create a class that has the exact
572 same member layout (self.op1, self.op2) as Example2OpClass
574 def __init__(self
, op1
, op2
):
579 def resultfn_8(data_o
, expected
, i
, o
):
580 res
= expected
.op1
+ expected
.op2
# these are a TestInputAdd instance
581 assert data_o
== res
, \
582 "%d-%d data %s res %x not match %s\n" \
583 % (i
, o
, repr(data_o
), res
, repr(expected
))
587 for i
in range(num_tests
):
588 data
.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
592 ######################################################################
594 ######################################################################
596 class ExampleStageDelayCls(StageCls
, Elaboratable
):
597 """ an example of how to use the buffered pipeline, in a static class
601 def __init__(self
, valid_trigger
=2):
602 self
.count
= Signal(2)
603 self
.valid_trigger
= valid_trigger
606 return Signal(16, name
="example_input_signal")
609 return Signal(16, name
="example_output_signal")
613 """ data is ready to be accepted when this is true
615 return (self
.count
== 1)# | (self.count == 3)
618 def d_valid(self
, ready_i
):
619 """ data is valid at output when this is true
621 return self
.count
== self
.valid_trigger
624 def process(self
, i
):
625 """ process the input data and returns it (adds 1)
629 def elaborate(self
, platform
):
631 m
.d
.sync
+= self
.count
.eq(self
.count
+ 1)
635 class ExampleBufDelayedPipe(BufferedHandshake
):
638 stage
= ExampleStageDelayCls(valid_trigger
=2)
639 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
641 def elaborate(self
, platform
):
642 m
= BufferedHandshake
.elaborate(self
, platform
)
643 m
.submodules
.stage
= self
.stage
649 for i
in range(num_tests
):
650 data
.append(1<<((i
*3)%15))
651 #data.append(randint(0, 1<<16-2))
652 #print (hex(data[-1]))
656 def resultfn_12(data_o
, expected
, i
, o
):
658 assert data_o
== res
, \
659 "%d-%d data %x not match %x\n" \
660 % (i
, o
, data_o
, res
)
663 ######################################################################
665 ######################################################################
667 class ExampleUnBufDelayedPipe(BufferedHandshake
):
670 stage
= ExampleStageDelayCls(valid_trigger
=3)
671 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
673 def elaborate(self
, platform
):
674 m
= BufferedHandshake
.elaborate(self
, platform
)
675 m
.submodules
.stage
= self
.stage
678 ######################################################################
680 ######################################################################
682 class ExampleBufModeAdd1Pipe(SimpleHandshake
):
685 stage
= ExampleStageCls()
686 SimpleHandshake
.__init
__(self
, stage
)
689 ######################################################################
691 ######################################################################
693 class ExampleBufModeUnBufPipe(ControlBase
):
695 def elaborate(self
, platform
):
696 m
= ControlBase
.elaborate(self
, platform
)
698 pipe1
= ExampleBufModeAdd1Pipe()
699 pipe2
= ExampleBufAdd1Pipe()
701 m
.submodules
.pipe1
= pipe1
702 m
.submodules
.pipe2
= pipe2
704 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
708 ######################################################################
710 ######################################################################
712 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2
):
715 stage
= ExampleStageCls()
716 UnbufferedPipeline2
.__init__(self
, stage
)
719 ######################################################################
721 ######################################################################
723 class PassThroughTest(PassThroughHandshake
):
726 return Signal(16, "out")
729 stage
= PassThroughStage(self
.iospecfn
)
730 PassThroughHandshake
.__init
__(self
, stage
)
732 def resultfn_identical(data_o
, expected
, i
, o
):
734 assert data_o
== res
, \
735 "%d-%d data %x not match %x\n" \
736 % (i
, o
, data_o
, res
)
739 ######################################################################
741 ######################################################################
743 class ExamplePassAdd1Pipe(PassThroughHandshake
):
746 stage
= ExampleStageCls()
747 PassThroughHandshake
.__init
__(self
, stage
)
750 class ExampleBufPassThruPipe(ControlBase
):
752 def elaborate(self
, platform
):
753 m
= ControlBase
.elaborate(self
, platform
)
755 # XXX currently fails: any other permutation works fine.
756 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
757 # also fails using UnbufferedPipeline as well
758 pipe1
= ExampleBufModeAdd1Pipe()
759 pipe2
= ExamplePassAdd1Pipe()
761 m
.submodules
.pipe1
= pipe1
762 m
.submodules
.pipe2
= pipe2
764 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
769 ######################################################################
771 ######################################################################
774 return Signal(16, name
="d_in")
776 class FIFOTest16(FIFOControl
):
779 stage
= PassThroughStage(iospecfn
)
780 FIFOControl
.__init
__(self
, 2, stage
)
783 ######################################################################
785 ######################################################################
787 class ExampleFIFOPassThruPipe1(ControlBase
):
789 def elaborate(self
, platform
):
790 m
= ControlBase
.elaborate(self
, platform
)
793 pipe2
= ExamplePassAdd1Pipe()
795 m
.submodules
.pipe1
= pipe1
796 m
.submodules
.pipe2
= pipe2
798 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
803 ######################################################################
805 ######################################################################
807 class Example2OpRecord(RecordObject
):
809 RecordObject
.__init
__(self
)
810 self
.op1
= Signal(16)
811 self
.op2
= Signal(16)
814 class ExampleAddRecordObjectStage(StageCls
):
817 """ returns an instance of an Example2OpRecord.
819 return Example2OpRecord()
822 """ returns an output signal which will happen to contain the sum
827 def process(self
, i
):
828 """ process the input data (sums the values in the tuple) and returns it
833 class ExampleRecordHandshakeAddClass(SimpleHandshake
):
836 addstage
= ExampleAddRecordObjectStage()
837 SimpleHandshake
.__init
__(self
, stage
=addstage
)
840 ######################################################################
842 ######################################################################
844 def iospecfnrecord():
845 return Example2OpRecord()
847 class FIFOTestRecordControl(FIFOControl
):
850 stage
= PassThroughStage(iospecfnrecord
)
851 FIFOControl
.__init
__(self
, 2, stage
)
854 class ExampleFIFORecordObjectPipe(ControlBase
):
856 def elaborate(self
, platform
):
857 m
= ControlBase
.elaborate(self
, platform
)
859 pipe1
= FIFOTestRecordControl()
860 pipe2
= ExampleRecordHandshakeAddClass()
862 m
.submodules
.pipe1
= pipe1
863 m
.submodules
.pipe2
= pipe2
865 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
870 ######################################################################
872 ######################################################################
874 class FIFOTestRecordAddStageControl(FIFOControl
):
877 stage
= ExampleAddRecordObjectStage()
878 FIFOControl
.__init
__(self
, 2, stage
)
882 ######################################################################
884 ######################################################################
886 class FIFOTestAdd16(FIFOControl
):
889 stage
= ExampleStageCls()
890 FIFOControl
.__init
__(self
, 2, stage
)
893 class ExampleFIFOAdd2Pipe(ControlBase
):
895 def elaborate(self
, platform
):
896 m
= ControlBase
.elaborate(self
, platform
)
898 pipe1
= FIFOTestAdd16()
899 pipe2
= FIFOTestAdd16()
901 m
.submodules
.pipe1
= pipe1
902 m
.submodules
.pipe2
= pipe2
904 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
909 ######################################################################
911 ######################################################################
914 return (Signal(16, name
="src1"), Signal(16, name
="src2"))
916 class FIFOTest2x16(FIFOControl
):
919 stage
= PassThroughStage(iospecfn2
)
920 FIFOControl
.__init
__(self
, 2, stage
)
923 ######################################################################
925 ######################################################################
927 class ExampleBufPassThruPipe2(ControlBase
):
929 def elaborate(self
, platform
):
930 m
= ControlBase
.elaborate(self
, platform
)
932 # XXX currently fails: any other permutation works fine.
933 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
934 # also fails using UnbufferedPipeline as well
935 #pipe1 = ExampleUnBufAdd1Pipe()
936 #pipe2 = ExampleBufAdd1Pipe()
937 pipe1
= ExampleBufAdd1Pipe()
938 pipe2
= ExamplePassAdd1Pipe()
940 m
.submodules
.pipe1
= pipe1
941 m
.submodules
.pipe2
= pipe2
943 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
948 ######################################################################
950 ######################################################################
952 class ExampleBufPipe3(ControlBase
):
953 """ Example of how to do delayed pipeline, where the stage signals
957 def elaborate(self
, platform
):
958 m
= ControlBase
.elaborate(self
, platform
)
960 pipe1
= ExampleBufDelayedPipe()
961 pipe2
= ExampleBufPipe()
963 m
.submodules
.pipe1
= pipe1
964 m
.submodules
.pipe2
= pipe2
966 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
970 ######################################################################
971 # Test 999 - XXX FAILS
972 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
973 ######################################################################
975 class ExampleBufAdd1Pipe(BufferedHandshake
):
978 stage
= ExampleStageCls()
979 BufferedHandshake
.__init
__(self
, stage
)
982 class ExampleUnBufAdd1Pipe(UnbufferedPipeline
):
985 stage
= ExampleStageCls()
986 UnbufferedPipeline
.__init
__(self
, stage
)
989 class ExampleBufUnBufPipe(ControlBase
):
991 def elaborate(self
, platform
):
992 m
= ControlBase
.elaborate(self
, platform
)
994 # XXX currently fails: any other permutation works fine.
995 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
996 # also fails using UnbufferedPipeline as well
997 #pipe1 = ExampleUnBufAdd1Pipe()
998 #pipe2 = ExampleBufAdd1Pipe()
999 pipe1
= ExampleBufAdd1Pipe()
1000 pipe2
= ExampleUnBufAdd1Pipe()
1002 m
.submodules
.pipe1
= pipe1
1003 m
.submodules
.pipe2
= pipe2
1005 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1010 ######################################################################
1012 ######################################################################
1016 if __name__
== '__main__':
1019 dut
= ExampleBufPipe()
1020 run_simulation(dut
, tbench(dut
), vcd_name
="test_bufpipe.vcd")
1023 dut
= ExampleBufPipe2()
1024 run_simulation(dut
, tbench2(dut
), vcd_name
="test_bufpipe2.vcd")
1025 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1026 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1027 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1028 vl
= rtlil
.convert(dut
, ports
=ports
)
1029 with
open("test_bufpipe2.il", "w") as f
:
1034 dut
= ExampleBufPipe()
1035 test
= Test3(dut
, resultfn_3
)
1036 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
1039 dut
= ExamplePipeline()
1040 test
= Test3(dut
, resultfn_3
)
1041 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
1044 dut
= ExampleBufPipe2()
1045 run_simulation(dut
, tbench4(dut
), vcd_name
="test_bufpipe4.vcd")
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")
1053 dut
= ExampleLTPipeline()
1054 test
= Test5(dut
, resultfn_6
)
1055 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
1057 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1058 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1059 list(dut
.p
.data_i
) + [dut
.n
.data_o
]
1060 vl
= rtlil
.convert(dut
, ports
=ports
)
1061 with
open("test_ltcomb_pipe.il", "w") as f
:
1065 dut
= ExampleAddRecordPipe()
1067 test
= Test5(dut
, resultfn_7
, data
=data
)
1068 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1069 dut
.n
.valid_o
, dut
.p
.ready_o
,
1070 dut
.p
.data_i
.src1
, dut
.p
.data_i
.src2
,
1071 dut
.n
.data_o
.src1
, dut
.n
.data_o
.src2
]
1072 vl
= rtlil
.convert(dut
, ports
=ports
)
1073 with
open("test_recordcomb_pipe.il", "w") as f
:
1075 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1078 dut
= ExampleBufPipeAddClass()
1080 test
= Test5(dut
, resultfn_8
, data
=data
)
1081 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")
1084 dut
= ExampleBufPipeChain2()
1085 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1086 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1087 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1088 vl
= rtlil
.convert(dut
, ports
=ports
)
1089 with
open("test_bufpipechain2.il", "w") as f
:
1092 data
= data_chain2()
1093 test
= Test5(dut
, resultfn_9
, data
=data
)
1094 run_simulation(dut
, [test
.send
, test
.rcv
],
1095 vcd_name
="test_bufpipechain2.vcd")
1098 dut
= ExampleLTBufferedPipeDerived()
1099 test
= Test5(dut
, resultfn_6
)
1100 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltbufpipe10.vcd")
1101 vl
= rtlil
.convert(dut
, ports
=ports
)
1102 with
open("test_ltbufpipe10.il", "w") as f
:
1106 dut
= ExampleAddRecordPlaceHolderPipe()
1107 data
=data_placeholder()
1108 test
= Test5(dut
, resultfn_test11
, data
=data
)
1109 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1113 dut
= ExampleBufDelayedPipe()
1114 data
= data_chain1()
1115 test
= Test5(dut
, resultfn_12
, data
=data
)
1116 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe12.vcd")
1117 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1118 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1119 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1120 vl
= rtlil
.convert(dut
, ports
=ports
)
1121 with
open("test_bufpipe12.il", "w") as f
:
1125 dut
= ExampleUnBufDelayedPipe()
1126 data
= data_chain1()
1127 test
= Test5(dut
, resultfn_12
, data
=data
)
1128 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe13.vcd")
1129 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1130 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1131 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1132 vl
= rtlil
.convert(dut
, ports
=ports
)
1133 with
open("test_unbufpipe13.il", "w") as f
:
1137 dut
= ExampleBufModeAdd1Pipe()
1138 data
= data_chain1()
1139 test
= Test5(dut
, resultfn_12
, data
=data
)
1140 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf15.vcd")
1141 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1142 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1143 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1144 vl
= rtlil
.convert(dut
, ports
=ports
)
1145 with
open("test_bufunbuf15.il", "w") as f
:
1149 dut
= ExampleBufModeUnBufPipe()
1150 data
= data_chain1()
1151 test
= Test5(dut
, resultfn_9
, data
=data
)
1152 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf16.vcd")
1153 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1154 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1155 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1156 vl
= rtlil
.convert(dut
, ports
=ports
)
1157 with
open("test_bufunbuf16.il", "w") as f
:
1161 dut
= ExampleUnBufAdd1Pipe2()
1162 data
= data_chain1()
1163 test
= Test5(dut
, resultfn_12
, data
=data
)
1164 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe17.vcd")
1165 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1166 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1167 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1168 vl
= rtlil
.convert(dut
, ports
=ports
)
1169 with
open("test_unbufpipe17.il", "w") as f
:
1173 dut
= PassThroughTest()
1174 data
= data_chain1()
1175 test
= Test5(dut
, resultfn_identical
, data
=data
)
1176 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_passthru18.vcd")
1177 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1178 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1179 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1180 vl
= rtlil
.convert(dut
, ports
=ports
)
1181 with
open("test_passthru18.il", "w") as f
:
1185 dut
= ExampleBufPassThruPipe()
1186 data
= data_chain1()
1187 test
= Test5(dut
, resultfn_9
, data
=data
)
1188 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass19.vcd")
1189 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1190 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1191 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1192 vl
= rtlil
.convert(dut
, ports
=ports
)
1193 with
open("test_bufpass19.il", "w") as f
:
1198 data
= data_chain1()
1199 test
= Test5(dut
, resultfn_identical
, data
=data
)
1200 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifo20.vcd")
1201 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1202 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1203 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1204 vl
= rtlil
.convert(dut
, ports
=ports
)
1205 with
open("test_fifo20.il", "w") as f
:
1209 dut
= ExampleFIFOPassThruPipe1()
1210 data
= data_chain1()
1211 test
= Test5(dut
, resultfn_12
, data
=data
)
1212 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifopass21.vcd")
1213 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1214 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1215 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1216 vl
= rtlil
.convert(dut
, ports
=ports
)
1217 with
open("test_fifopass21.il", "w") as f
:
1221 dut
= ExampleRecordHandshakeAddClass()
1223 test
= Test5(dut
, resultfn_8
, data
=data
)
1224 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord22.vcd")
1225 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1226 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1227 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1229 vl
= rtlil
.convert(dut
, ports
=ports
)
1230 with
open("test_addrecord22.il", "w") as f
:
1234 dut
= ExampleFIFORecordObjectPipe()
1236 test
= Test5(dut
, resultfn_8
, data
=data
)
1237 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord23.vcd")
1238 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1239 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1240 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1242 vl
= rtlil
.convert(dut
, ports
=ports
)
1243 with
open("test_addrecord23.il", "w") as f
:
1247 dut
= FIFOTestRecordAddStageControl()
1249 test
= Test5(dut
, resultfn_8
, data
=data
)
1250 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1251 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1252 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1254 vl
= rtlil
.convert(dut
, ports
=ports
)
1255 with
open("test_addrecord24.il", "w") as f
:
1257 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord24.vcd")
1260 dut
= ExampleFIFOAdd2Pipe()
1261 data
= data_chain1()
1262 test
= Test5(dut
, resultfn_9
, data
=data
)
1263 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_add2pipe25.vcd")
1264 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1265 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1266 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1267 vl
= rtlil
.convert(dut
, ports
=ports
)
1268 with
open("test_add2pipe25.il", "w") as f
:
1272 dut
= ExampleBufPassThruPipe2()
1273 data
= data_chain1()
1274 test
= Test5(dut
, resultfn_9
, data
=data
)
1275 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass997.vcd")
1276 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1277 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1278 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1279 vl
= rtlil
.convert(dut
, ports
=ports
)
1280 with
open("test_bufpass997.il", "w") as f
:
1283 print ("test 998 (fails, bug)")
1284 dut
= ExampleBufPipe3()
1285 data
= data_chain1()
1286 test
= Test5(dut
, resultfn_9
, data
=data
)
1287 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe14.vcd")
1288 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1289 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1290 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1291 vl
= rtlil
.convert(dut
, ports
=ports
)
1292 with
open("test_bufpipe14.il", "w") as f
:
1295 print ("test 999 (expected to fail, which is a bug)")
1296 dut
= ExampleBufUnBufPipe()
1297 data
= data_chain1()
1298 test
= Test5(dut
, resultfn_9
, data
=data
)
1299 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf999.vcd")
1300 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1301 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1302 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1303 vl
= rtlil
.convert(dut
, ports
=ports
)
1304 with
open("test_bufunbuf999.il", "w") as f
: