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 nmutil
.singlepipe
import UnbufferedPipeline2
28 from nmutil
.singlepipe
import SimpleHandshake
29 from nmutil
.singlepipe
import PassThroughHandshake
30 from nmutil
.singlepipe
import PassThroughStage
31 from nmutil
.singlepipe
import FIFOControl
32 from nmutil
.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
)
794 pipe3
= ExamplePassAdd1Pipe()
796 m
.submodules
.pipe1
= pipe1
797 m
.submodules
.pipe2
= pipe2
798 m
.submodules
.pipe3
= pipe3
800 m
.d
.comb
+= self
.connect([pipe1
, pipe2
, pipe3
])
805 ######################################################################
807 ######################################################################
809 class Example2OpRecord(RecordObject
):
811 RecordObject
.__init
__(self
)
812 self
.op1
= Signal(16)
813 self
.op2
= Signal(16)
816 class ExampleAddRecordObjectStage(StageCls
):
819 """ returns an instance of an Example2OpRecord.
821 return Example2OpRecord()
824 """ returns an output signal which will happen to contain the sum
829 def process(self
, i
):
830 """ process the input data (sums the values in the tuple) and returns it
835 class ExampleRecordHandshakeAddClass(SimpleHandshake
):
838 addstage
= ExampleAddRecordObjectStage()
839 SimpleHandshake
.__init
__(self
, stage
=addstage
)
842 ######################################################################
844 ######################################################################
846 def iospecfnrecord():
847 return Example2OpRecord()
849 class FIFOTestRecordControl(FIFOControl
):
852 stage
= PassThroughStage(iospecfnrecord
)
853 FIFOControl
.__init
__(self
, 2, stage
)
856 class ExampleFIFORecordObjectPipe(ControlBase
):
858 def elaborate(self
, platform
):
859 m
= ControlBase
.elaborate(self
, platform
)
861 pipe1
= FIFOTestRecordControl()
862 pipe2
= ExampleRecordHandshakeAddClass()
864 m
.submodules
.pipe1
= pipe1
865 m
.submodules
.pipe2
= pipe2
867 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
872 ######################################################################
874 ######################################################################
876 class FIFOTestRecordAddStageControl(FIFOControl
):
879 stage
= ExampleAddRecordObjectStage()
880 FIFOControl
.__init
__(self
, 2, stage
)
884 ######################################################################
886 ######################################################################
888 class FIFOTestAdd16(FIFOControl
):
891 stage
= ExampleStageCls()
892 FIFOControl
.__init
__(self
, 2, stage
)
895 class ExampleFIFOAdd2Pipe(ControlBase
):
897 def elaborate(self
, platform
):
898 m
= ControlBase
.elaborate(self
, platform
)
900 pipe1
= FIFOTestAdd16()
901 pipe2
= FIFOTestAdd16()
903 m
.submodules
.pipe1
= pipe1
904 m
.submodules
.pipe2
= pipe2
906 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
911 ######################################################################
913 ######################################################################
916 return (Signal(16, name
="src1"), Signal(16, name
="src2"))
918 class FIFOTest2x16(FIFOControl
):
921 stage
= PassThroughStage(iospecfn2
)
922 FIFOControl
.__init
__(self
, 2, stage
)
925 ######################################################################
927 ######################################################################
929 class ExampleBufPassThruPipe2(ControlBase
):
931 def elaborate(self
, platform
):
932 m
= ControlBase
.elaborate(self
, platform
)
934 # XXX currently fails: any other permutation works fine.
935 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
936 # also fails using UnbufferedPipeline as well
937 #pipe1 = ExampleUnBufAdd1Pipe()
938 #pipe2 = ExampleBufAdd1Pipe()
939 pipe1
= ExampleBufAdd1Pipe()
940 pipe2
= ExamplePassAdd1Pipe()
942 m
.submodules
.pipe1
= pipe1
943 m
.submodules
.pipe2
= pipe2
945 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
950 ######################################################################
952 ######################################################################
954 class ExampleBufPipe3(ControlBase
):
955 """ Example of how to do delayed pipeline, where the stage signals
959 def elaborate(self
, platform
):
960 m
= ControlBase
.elaborate(self
, platform
)
962 pipe1
= ExampleBufDelayedPipe()
963 pipe2
= ExampleBufPipe()
965 m
.submodules
.pipe1
= pipe1
966 m
.submodules
.pipe2
= pipe2
968 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
972 ######################################################################
973 # Test 999 - XXX FAILS
974 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
975 ######################################################################
977 class ExampleBufAdd1Pipe(BufferedHandshake
):
980 stage
= ExampleStageCls()
981 BufferedHandshake
.__init
__(self
, stage
)
984 class ExampleUnBufAdd1Pipe(UnbufferedPipeline
):
987 stage
= ExampleStageCls()
988 UnbufferedPipeline
.__init
__(self
, stage
)
991 class ExampleBufUnBufPipe(ControlBase
):
993 def elaborate(self
, platform
):
994 m
= ControlBase
.elaborate(self
, platform
)
996 # XXX currently fails: any other permutation works fine.
997 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
998 # also fails using UnbufferedPipeline as well
999 #pipe1 = ExampleUnBufAdd1Pipe()
1000 #pipe2 = ExampleBufAdd1Pipe()
1001 pipe1
= ExampleBufAdd1Pipe()
1002 pipe2
= ExampleUnBufAdd1Pipe()
1004 m
.submodules
.pipe1
= pipe1
1005 m
.submodules
.pipe2
= pipe2
1007 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1012 ######################################################################
1014 ######################################################################
1018 if __name__
== '__main__':
1021 dut
= ExampleBufPipe()
1022 run_simulation(dut
, tbench(dut
), vcd_name
="test_bufpipe.vcd")
1025 dut
= ExampleBufPipe2()
1026 run_simulation(dut
, tbench2(dut
), vcd_name
="test_bufpipe2.vcd")
1027 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1028 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1029 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1030 vl
= rtlil
.convert(dut
, ports
=ports
)
1031 with
open("test_bufpipe2.il", "w") as f
:
1036 dut
= ExampleBufPipe()
1037 test
= Test3(dut
, resultfn_3
)
1038 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
1041 dut
= ExamplePipeline()
1042 test
= Test3(dut
, resultfn_3
)
1043 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
1046 dut
= ExampleBufPipe2()
1047 run_simulation(dut
, tbench4(dut
), vcd_name
="test_bufpipe4.vcd")
1050 dut
= ExampleBufPipeAdd()
1051 test
= Test5(dut
, resultfn_5
, stage_ctl
=True)
1052 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe5.vcd")
1055 dut
= ExampleLTPipeline()
1056 test
= Test5(dut
, resultfn_6
)
1057 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
1059 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1060 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1061 list(dut
.p
.data_i
) + [dut
.n
.data_o
]
1062 vl
= rtlil
.convert(dut
, ports
=ports
)
1063 with
open("test_ltcomb_pipe.il", "w") as f
:
1067 dut
= ExampleAddRecordPipe()
1069 test
= Test5(dut
, resultfn_7
, data
=data
)
1070 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1071 dut
.n
.valid_o
, dut
.p
.ready_o
,
1072 dut
.p
.data_i
.src1
, dut
.p
.data_i
.src2
,
1073 dut
.n
.data_o
.src1
, dut
.n
.data_o
.src2
]
1074 vl
= rtlil
.convert(dut
, ports
=ports
)
1075 with
open("test_recordcomb_pipe.il", "w") as f
:
1077 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1080 dut
= ExampleBufPipeAddClass()
1082 test
= Test5(dut
, resultfn_8
, data
=data
)
1083 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")
1086 dut
= ExampleBufPipeChain2()
1087 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1088 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1089 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1090 vl
= rtlil
.convert(dut
, ports
=ports
)
1091 with
open("test_bufpipechain2.il", "w") as f
:
1094 data
= data_chain2()
1095 test
= Test5(dut
, resultfn_9
, data
=data
)
1096 run_simulation(dut
, [test
.send
, test
.rcv
],
1097 vcd_name
="test_bufpipechain2.vcd")
1100 dut
= ExampleLTBufferedPipeDerived()
1101 test
= Test5(dut
, resultfn_6
)
1102 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltbufpipe10.vcd")
1103 vl
= rtlil
.convert(dut
, ports
=ports
)
1104 with
open("test_ltbufpipe10.il", "w") as f
:
1108 dut
= ExampleAddRecordPlaceHolderPipe()
1109 data
=data_placeholder()
1110 test
= Test5(dut
, resultfn_test11
, data
=data
)
1111 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1115 dut
= ExampleBufDelayedPipe()
1116 data
= data_chain1()
1117 test
= Test5(dut
, resultfn_12
, data
=data
)
1118 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe12.vcd")
1119 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1120 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1121 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1122 vl
= rtlil
.convert(dut
, ports
=ports
)
1123 with
open("test_bufpipe12.il", "w") as f
:
1127 dut
= ExampleUnBufDelayedPipe()
1128 data
= data_chain1()
1129 test
= Test5(dut
, resultfn_12
, data
=data
)
1130 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe13.vcd")
1131 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1132 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1133 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1134 vl
= rtlil
.convert(dut
, ports
=ports
)
1135 with
open("test_unbufpipe13.il", "w") as f
:
1139 dut
= ExampleBufModeAdd1Pipe()
1140 data
= data_chain1()
1141 test
= Test5(dut
, resultfn_12
, data
=data
)
1142 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf15.vcd")
1143 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1144 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1145 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1146 vl
= rtlil
.convert(dut
, ports
=ports
)
1147 with
open("test_bufunbuf15.il", "w") as f
:
1151 dut
= ExampleBufModeUnBufPipe()
1152 data
= data_chain1()
1153 test
= Test5(dut
, resultfn_9
, data
=data
)
1154 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf16.vcd")
1155 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1156 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1157 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1158 vl
= rtlil
.convert(dut
, ports
=ports
)
1159 with
open("test_bufunbuf16.il", "w") as f
:
1163 dut
= ExampleUnBufAdd1Pipe2()
1164 data
= data_chain1()
1165 test
= Test5(dut
, resultfn_12
, data
=data
)
1166 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe17.vcd")
1167 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1168 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1169 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1170 vl
= rtlil
.convert(dut
, ports
=ports
)
1171 with
open("test_unbufpipe17.il", "w") as f
:
1175 dut
= PassThroughTest()
1176 data
= data_chain1()
1177 test
= Test5(dut
, resultfn_identical
, data
=data
)
1178 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_passthru18.vcd")
1179 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1180 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1181 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1182 vl
= rtlil
.convert(dut
, ports
=ports
)
1183 with
open("test_passthru18.il", "w") as f
:
1187 dut
= ExampleBufPassThruPipe()
1188 data
= data_chain1()
1189 test
= Test5(dut
, resultfn_9
, data
=data
)
1190 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass19.vcd")
1191 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1192 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1193 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1194 vl
= rtlil
.convert(dut
, ports
=ports
)
1195 with
open("test_bufpass19.il", "w") as f
:
1200 data
= data_chain1()
1201 test
= Test5(dut
, resultfn_identical
, data
=data
)
1202 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifo20.vcd")
1203 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1204 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1205 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1206 vl
= rtlil
.convert(dut
, ports
=ports
)
1207 with
open("test_fifo20.il", "w") as f
:
1211 dut
= ExampleFIFOPassThruPipe1()
1212 data
= data_chain1()
1213 test
= Test5(dut
, resultfn_12
, data
=data
)
1214 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifopass21.vcd")
1215 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1216 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1217 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1218 vl
= rtlil
.convert(dut
, ports
=ports
)
1219 with
open("test_fifopass21.il", "w") as f
:
1223 dut
= ExampleRecordHandshakeAddClass()
1225 test
= Test5(dut
, resultfn_8
, data
=data
)
1226 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord22.vcd")
1227 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1228 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1229 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1231 vl
= rtlil
.convert(dut
, ports
=ports
)
1232 with
open("test_addrecord22.il", "w") as f
:
1236 dut
= ExampleFIFORecordObjectPipe()
1238 test
= Test5(dut
, resultfn_8
, data
=data
)
1239 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord23.vcd")
1240 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1241 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1242 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1244 vl
= rtlil
.convert(dut
, ports
=ports
)
1245 with
open("test_addrecord23.il", "w") as f
:
1249 dut
= FIFOTestRecordAddStageControl()
1251 test
= Test5(dut
, resultfn_8
, data
=data
)
1252 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1253 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1254 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1256 vl
= rtlil
.convert(dut
, ports
=ports
)
1257 with
open("test_addrecord24.il", "w") as f
:
1259 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord24.vcd")
1262 dut
= ExampleFIFOAdd2Pipe()
1263 data
= data_chain1()
1264 test
= Test5(dut
, resultfn_9
, data
=data
)
1265 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_add2pipe25.vcd")
1266 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1267 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1268 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1269 vl
= rtlil
.convert(dut
, ports
=ports
)
1270 with
open("test_add2pipe25.il", "w") as f
:
1274 dut
= ExampleBufPassThruPipe2()
1275 data
= data_chain1()
1276 test
= Test5(dut
, resultfn_9
, data
=data
)
1277 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass997.vcd")
1278 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1279 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1280 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1281 vl
= rtlil
.convert(dut
, ports
=ports
)
1282 with
open("test_bufpass997.il", "w") as f
:
1285 print ("test 998 (fails, bug)")
1286 dut
= ExampleBufPipe3()
1287 data
= data_chain1()
1288 test
= Test5(dut
, resultfn_9
, data
=data
)
1289 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe14.vcd")
1290 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1291 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1292 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1293 vl
= rtlil
.convert(dut
, ports
=ports
)
1294 with
open("test_bufpipe14.il", "w") as f
:
1297 print ("test 999 (expected to fail, which is a bug)")
1298 dut
= ExampleBufUnBufPipe()
1299 data
= data_chain1()
1300 test
= Test5(dut
, resultfn_9
, data
=data
)
1301 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf999.vcd")
1302 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1303 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1304 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1305 vl
= rtlil
.convert(dut
, ports
=ports
)
1306 with
open("test_bufunbuf999.il", "w") as f
: