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.o_ready.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.o_ready.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
.o_ready
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
.o_ready
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
.o_ready
274 if send
and i
!= len(data
):
275 yield dut
.p
.i_valid
.eq(1)
276 yield dut
.p
.i_data
.eq(data
[i
])
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)
364 return (Signal(16, name
="sig1"), Signal(16, "sig2"))
367 return Signal(16, "out")
369 def setup(self
, m
, i
):
371 m
.submodules
.slt
= self
.slt
372 m
.d
.comb
+= self
.slt
.src1
.eq(i
[0])
373 m
.d
.comb
+= self
.slt
.src2
.eq(i
[1])
374 m
.d
.comb
+= self
.o
.eq(self
.slt
.output
)
376 def process(self
, i
):
380 class LTStageDerived(SetLessThan
, StageCls
, Elaboratable
):
381 """ special version of a nmigen module where the module is also a stage
383 shows that you don't actually need to combinatorially connect
384 to the outputs, or add the module as a submodule: just return
385 the module output parameter(s) from the Stage.process() function
389 SetLessThan
.__init
__(self
, 16, True)
392 return (Signal(16), Signal(16))
397 def setup(self
, m
, i
):
398 m
.submodules
.slt
= self
399 m
.d
.comb
+= self
.src1
.eq(i
[0])
400 m
.d
.comb
+= self
.src2
.eq(i
[1])
402 def process(self
, i
):
406 class ExampleLTPipeline(UnbufferedPipeline
):
407 """ an example of how to use the unbuffered pipeline.
412 UnbufferedPipeline
.__init
__(self
, stage
)
415 class ExampleLTBufferedPipeDerived(BufferedHandshake
):
416 """ an example of how to use the buffered pipeline.
420 stage
= LTStageDerived()
421 BufferedHandshake
.__init
__(self
, stage
)
424 def resultfn_6(o_data
, expected
, i
, o
):
425 res
= 1 if expected
[0] < expected
[1] else 0
426 assert o_data
== res
, \
427 "%d-%d data %x not match %s\n" \
428 % (i
, o
, o_data
, repr(expected
))
431 ######################################################################
433 ######################################################################
435 class ExampleAddRecordStage(StageCls
):
436 """ example use of a Record
439 record_spec
= [('src1', 16), ('src2', 16)]
441 """ returns a Record using the specification
443 return Record(self
.record_spec
)
446 return Record(self
.record_spec
)
448 def process(self
, i
):
449 """ process the input data, returning a dictionary with key names
450 that exactly match the Record's attributes.
452 return {'src1': i
.src1
+ 1,
455 ######################################################################
457 ######################################################################
459 class ExampleAddRecordPlaceHolderStage(StageCls
):
460 """ example use of a Record, with a placeholder as the processing result
463 record_spec
= [('src1', 16), ('src2', 16)]
465 """ returns a Record using the specification
467 return Record(self
.record_spec
)
470 return Record(self
.record_spec
)
472 def process(self
, i
):
473 """ process the input data, returning a PlaceHolder class instance
474 with attributes that exactly match those of the Record.
482 class PlaceHolder
: pass
485 class ExampleAddRecordPipe(UnbufferedPipeline
):
486 """ an example of how to use the combinatorial pipeline.
490 stage
= ExampleAddRecordStage()
491 UnbufferedPipeline
.__init
__(self
, stage
)
494 def resultfn_7(o_data
, expected
, i
, o
):
495 res
= (expected
['src1'] + 1, expected
['src2'] + 1)
496 assert o_data
['src1'] == res
[0] and o_data
['src2'] == res
[1], \
497 "%d-%d data %s not match %s\n" \
498 % (i
, o
, repr(o_data
), repr(expected
))
501 class ExampleAddRecordPlaceHolderPipe(UnbufferedPipeline
):
502 """ an example of how to use the combinatorial pipeline.
506 stage
= ExampleAddRecordPlaceHolderStage()
507 UnbufferedPipeline
.__init
__(self
, stage
)
510 def resultfn_test11(o_data
, expected
, i
, o
):
511 res1
= expected
.src1
+ 1
512 res2
= expected
.src2
+ 1
513 assert o_data
['src1'] == res1
and o_data
['src2'] == res2
, \
514 "%d-%d data %s not match %s\n" \
515 % (i
, o
, repr(o_data
), repr(expected
))
518 ######################################################################
520 ######################################################################
523 class Example2OpClass
:
524 """ an example of a class used to store 2 operands.
525 requires an eq function, to conform with the pipeline stage API
529 self
.op1
= Signal(16)
530 self
.op2
= Signal(16)
533 return [self
.op1
.eq(i
.op1
), self
.op2
.eq(i
.op2
)]
536 class ExampleAddClassStage(StageCls
):
537 """ an example of how to use the buffered pipeline, as a class instance
541 """ returns an instance of an Example2OpClass.
543 return Example2OpClass()
546 """ returns an output signal which will happen to contain the sum
551 def process(self
, i
):
552 """ process the input data (sums the values in the tuple) and returns it
557 class ExampleBufPipeAddClass(BufferedHandshake
):
558 """ an example of how to use the buffered pipeline, using a class instance
562 addstage
= ExampleAddClassStage()
563 BufferedHandshake
.__init
__(self
, addstage
)
567 """ the eq function, called by set_input, needs an incoming object
568 that conforms to the Example2OpClass.eq function requirements
569 easiest way to do that is to create a class that has the exact
570 same member layout (self.op1, self.op2) as Example2OpClass
572 def __init__(self
, op1
, op2
):
577 def resultfn_8(o_data
, expected
, i
, o
):
578 res
= expected
.op1
+ expected
.op2
# these are a TestInputAdd instance
579 assert o_data
== res
, \
580 "%d-%d data %s res %x not match %s\n" \
581 % (i
, o
, repr(o_data
), res
, repr(expected
))
585 for i
in range(num_tests
):
586 data
.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
590 ######################################################################
592 ######################################################################
594 class ExampleStageDelayCls(StageCls
, Elaboratable
):
595 """ an example of how to use the buffered pipeline, in a static class
599 def __init__(self
, valid_trigger
=2):
600 self
.count
= Signal(2)
601 self
.valid_trigger
= valid_trigger
604 return Signal(16, name
="example_input_signal")
607 return Signal(16, name
="example_output_signal")
611 """ data is ready to be accepted when this is true
613 return (self
.count
== 1)# | (self.count == 3)
616 def d_valid(self
, i_ready
):
617 """ data is valid at output when this is true
619 return self
.count
== self
.valid_trigger
622 def process(self
, i
):
623 """ process the input data and returns it (adds 1)
627 def elaborate(self
, platform
):
629 m
.d
.sync
+= self
.count
.eq(self
.count
+ 1)
633 class ExampleBufDelayedPipe(BufferedHandshake
):
636 stage
= ExampleStageDelayCls(valid_trigger
=2)
637 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
639 def elaborate(self
, platform
):
640 m
= BufferedHandshake
.elaborate(self
, platform
)
641 m
.submodules
.stage
= self
.stage
647 for i
in range(num_tests
):
648 data
.append(1<<((i
*3)%15))
649 #data.append(randint(0, 1<<16-2))
650 #print (hex(data[-1]))
654 def resultfn_12(o_data
, expected
, i
, o
):
656 assert o_data
== res
, \
657 "%d-%d data %x not match %x\n" \
658 % (i
, o
, o_data
, res
)
661 ######################################################################
663 ######################################################################
665 class ExampleUnBufDelayedPipe(BufferedHandshake
):
668 stage
= ExampleStageDelayCls(valid_trigger
=3)
669 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
671 def elaborate(self
, platform
):
672 m
= BufferedHandshake
.elaborate(self
, platform
)
673 m
.submodules
.stage
= self
.stage
676 ######################################################################
678 ######################################################################
680 class ExampleBufModeAdd1Pipe(SimpleHandshake
):
683 stage
= ExampleStageCls()
684 SimpleHandshake
.__init
__(self
, stage
)
687 ######################################################################
689 ######################################################################
691 class ExampleBufModeUnBufPipe(ControlBase
):
693 def elaborate(self
, platform
):
694 m
= ControlBase
.elaborate(self
, platform
)
696 pipe1
= ExampleBufModeAdd1Pipe()
697 pipe2
= ExampleBufAdd1Pipe()
699 m
.submodules
.pipe1
= pipe1
700 m
.submodules
.pipe2
= pipe2
702 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
706 ######################################################################
708 ######################################################################
710 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2
):
713 stage
= ExampleStageCls()
714 UnbufferedPipeline2
.__init__(self
, stage
)
717 ######################################################################
719 ######################################################################
721 class PassThroughTest(PassThroughHandshake
):
724 return Signal(16, "out")
727 stage
= PassThroughStage(self
.iospecfn
)
728 PassThroughHandshake
.__init
__(self
, stage
)
730 def resultfn_identical(o_data
, expected
, i
, o
):
732 assert o_data
== res
, \
733 "%d-%d data %x not match %x\n" \
734 % (i
, o
, o_data
, res
)
737 ######################################################################
739 ######################################################################
741 class ExamplePassAdd1Pipe(PassThroughHandshake
):
744 stage
= ExampleStageCls()
745 PassThroughHandshake
.__init
__(self
, stage
)
748 class ExampleBufPassThruPipe(ControlBase
):
750 def elaborate(self
, platform
):
751 m
= ControlBase
.elaborate(self
, platform
)
753 # XXX currently fails: any other permutation works fine.
754 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
755 # also fails using UnbufferedPipeline as well
756 pipe1
= ExampleBufModeAdd1Pipe()
757 pipe2
= ExamplePassAdd1Pipe()
759 m
.submodules
.pipe1
= pipe1
760 m
.submodules
.pipe2
= pipe2
762 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
767 ######################################################################
769 ######################################################################
772 return Signal(16, name
="d_in")
774 class FIFOTest16(FIFOControl
):
777 stage
= PassThroughStage(iospecfn
)
778 FIFOControl
.__init
__(self
, 2, stage
)
781 ######################################################################
783 ######################################################################
785 class ExampleFIFOPassThruPipe1(ControlBase
):
787 def elaborate(self
, platform
):
788 m
= ControlBase
.elaborate(self
, platform
)
791 pipe2
= ExamplePassAdd1Pipe()
793 m
.submodules
.pipe1
= pipe1
794 m
.submodules
.pipe2
= pipe2
796 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
801 ######################################################################
803 ######################################################################
805 class Example2OpRecord(RecordObject
):
807 RecordObject
.__init
__(self
)
808 self
.op1
= Signal(16)
809 self
.op2
= Signal(16)
812 class ExampleAddRecordObjectStage(StageCls
):
815 """ returns an instance of an Example2OpRecord.
817 return Example2OpRecord()
820 """ returns an output signal which will happen to contain the sum
825 def process(self
, i
):
826 """ process the input data (sums the values in the tuple) and returns it
831 class ExampleRecordHandshakeAddClass(SimpleHandshake
):
834 addstage
= ExampleAddRecordObjectStage()
835 SimpleHandshake
.__init
__(self
, stage
=addstage
)
838 ######################################################################
840 ######################################################################
842 def iospecfnrecord():
843 return Example2OpRecord()
845 class FIFOTestRecordControl(FIFOControl
):
848 stage
= PassThroughStage(iospecfnrecord
)
849 FIFOControl
.__init
__(self
, 2, stage
)
852 class ExampleFIFORecordObjectPipe(ControlBase
):
854 def elaborate(self
, platform
):
855 m
= ControlBase
.elaborate(self
, platform
)
857 pipe1
= FIFOTestRecordControl()
858 pipe2
= ExampleRecordHandshakeAddClass()
860 m
.submodules
.pipe1
= pipe1
861 m
.submodules
.pipe2
= pipe2
863 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
868 ######################################################################
870 ######################################################################
872 class FIFOTestRecordAddStageControl(FIFOControl
):
875 stage
= ExampleAddRecordObjectStage()
876 FIFOControl
.__init
__(self
, 2, stage
)
880 ######################################################################
882 ######################################################################
884 class FIFOTestAdd16(FIFOControl
):
887 stage
= ExampleStageCls()
888 FIFOControl
.__init
__(self
, 2, stage
)
891 class ExampleFIFOAdd2Pipe(ControlBase
):
893 def elaborate(self
, platform
):
894 m
= ControlBase
.elaborate(self
, platform
)
896 pipe1
= FIFOTestAdd16()
897 pipe2
= FIFOTestAdd16()
899 m
.submodules
.pipe1
= pipe1
900 m
.submodules
.pipe2
= pipe2
902 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
907 ######################################################################
909 ######################################################################
912 return (Signal(16, name
="src1"), Signal(16, name
="src2"))
914 class FIFOTest2x16(FIFOControl
):
917 stage
= PassThroughStage(iospecfn2
)
918 FIFOControl
.__init
__(self
, 2, stage
)
921 ######################################################################
923 ######################################################################
925 class ExampleBufPassThruPipe2(ControlBase
):
927 def elaborate(self
, platform
):
928 m
= ControlBase
.elaborate(self
, platform
)
930 # XXX currently fails: any other permutation works fine.
931 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
932 # also fails using UnbufferedPipeline as well
933 #pipe1 = ExampleUnBufAdd1Pipe()
934 #pipe2 = ExampleBufAdd1Pipe()
935 pipe1
= ExampleBufAdd1Pipe()
936 pipe2
= ExamplePassAdd1Pipe()
938 m
.submodules
.pipe1
= pipe1
939 m
.submodules
.pipe2
= pipe2
941 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
946 ######################################################################
948 ######################################################################
950 class ExampleBufPipe3(ControlBase
):
951 """ Example of how to do delayed pipeline, where the stage signals
955 def elaborate(self
, platform
):
956 m
= ControlBase
.elaborate(self
, platform
)
958 pipe1
= ExampleBufDelayedPipe()
959 pipe2
= ExampleBufPipe()
961 m
.submodules
.pipe1
= pipe1
962 m
.submodules
.pipe2
= pipe2
964 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
968 ######################################################################
969 # Test 999 - XXX FAILS
970 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
971 ######################################################################
973 class ExampleBufAdd1Pipe(BufferedHandshake
):
976 stage
= ExampleStageCls()
977 BufferedHandshake
.__init
__(self
, stage
)
980 class ExampleUnBufAdd1Pipe(UnbufferedPipeline
):
983 stage
= ExampleStageCls()
984 UnbufferedPipeline
.__init
__(self
, stage
)
987 class ExampleBufUnBufPipe(ControlBase
):
989 def elaborate(self
, platform
):
990 m
= ControlBase
.elaborate(self
, platform
)
992 # XXX currently fails: any other permutation works fine.
993 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
994 # also fails using UnbufferedPipeline as well
995 #pipe1 = ExampleUnBufAdd1Pipe()
996 #pipe2 = ExampleBufAdd1Pipe()
997 pipe1
= ExampleBufAdd1Pipe()
998 pipe2
= ExampleUnBufAdd1Pipe()
1000 m
.submodules
.pipe1
= pipe1
1001 m
.submodules
.pipe2
= pipe2
1003 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1008 ######################################################################
1010 ######################################################################
1014 if __name__
== '__main__':
1017 dut
= ExampleBufPipe()
1018 run_simulation(dut
, tbench(dut
), vcd_name
="test_bufpipe.vcd")
1021 dut
= ExampleBufPipe2()
1022 run_simulation(dut
, tbench2(dut
), vcd_name
="test_bufpipe2.vcd")
1023 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1024 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1025 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1026 vl
= rtlil
.convert(dut
, ports
=ports
)
1027 with
open("test_bufpipe2.il", "w") as f
:
1032 dut
= ExampleBufPipe()
1033 test
= Test3(dut
, resultfn_3
)
1034 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
1037 dut
= ExamplePipeline()
1038 test
= Test3(dut
, resultfn_3
)
1039 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
1042 dut
= ExampleBufPipe2()
1043 run_simulation(dut
, tbench4(dut
), vcd_name
="test_bufpipe4.vcd")
1046 dut
= ExampleBufPipeAdd()
1047 test
= Test5(dut
, resultfn_5
, stage_ctl
=True)
1048 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe5.vcd")
1051 dut
= ExampleLTPipeline()
1052 test
= Test5(dut
, resultfn_6
)
1053 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
1055 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1056 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1057 list(dut
.p
.i_data
) + [dut
.n
.o_data
]
1058 vl
= rtlil
.convert(dut
, ports
=ports
)
1059 with
open("test_ltcomb_pipe.il", "w") as f
:
1063 dut
= ExampleAddRecordPipe()
1065 test
= Test5(dut
, resultfn_7
, data
=data
)
1066 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1067 dut
.n
.o_valid
, dut
.p
.o_ready
,
1068 dut
.p
.i_data
.src1
, dut
.p
.i_data
.src2
,
1069 dut
.n
.o_data
.src1
, dut
.n
.o_data
.src2
]
1070 vl
= rtlil
.convert(dut
, ports
=ports
)
1071 with
open("test_recordcomb_pipe.il", "w") as f
:
1073 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1076 dut
= ExampleBufPipeAddClass()
1078 test
= Test5(dut
, resultfn_8
, data
=data
)
1079 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")
1082 dut
= ExampleBufPipeChain2()
1083 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1084 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1085 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1086 vl
= rtlil
.convert(dut
, ports
=ports
)
1087 with
open("test_bufpipechain2.il", "w") as f
:
1090 data
= data_chain2()
1091 test
= Test5(dut
, resultfn_9
, data
=data
)
1092 run_simulation(dut
, [test
.send
, test
.rcv
],
1093 vcd_name
="test_bufpipechain2.vcd")
1096 dut
= ExampleLTBufferedPipeDerived()
1097 test
= Test5(dut
, resultfn_6
)
1098 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltbufpipe10.vcd")
1099 vl
= rtlil
.convert(dut
, ports
=ports
)
1100 with
open("test_ltbufpipe10.il", "w") as f
:
1104 dut
= ExampleAddRecordPlaceHolderPipe()
1105 data
=data_placeholder()
1106 test
= Test5(dut
, resultfn_test11
, data
=data
)
1107 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1111 dut
= ExampleBufDelayedPipe()
1112 data
= data_chain1()
1113 test
= Test5(dut
, resultfn_12
, data
=data
)
1114 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe12.vcd")
1115 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1116 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1117 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1118 vl
= rtlil
.convert(dut
, ports
=ports
)
1119 with
open("test_bufpipe12.il", "w") as f
:
1123 dut
= ExampleUnBufDelayedPipe()
1124 data
= data_chain1()
1125 test
= Test5(dut
, resultfn_12
, data
=data
)
1126 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe13.vcd")
1127 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1128 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1129 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1130 vl
= rtlil
.convert(dut
, ports
=ports
)
1131 with
open("test_unbufpipe13.il", "w") as f
:
1135 dut
= ExampleBufModeAdd1Pipe()
1136 data
= data_chain1()
1137 test
= Test5(dut
, resultfn_12
, data
=data
)
1138 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf15.vcd")
1139 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1140 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1141 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1142 vl
= rtlil
.convert(dut
, ports
=ports
)
1143 with
open("test_bufunbuf15.il", "w") as f
:
1147 dut
= ExampleBufModeUnBufPipe()
1148 data
= data_chain1()
1149 test
= Test5(dut
, resultfn_9
, data
=data
)
1150 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf16.vcd")
1151 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1152 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1153 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1154 vl
= rtlil
.convert(dut
, ports
=ports
)
1155 with
open("test_bufunbuf16.il", "w") as f
:
1159 dut
= ExampleUnBufAdd1Pipe2()
1160 data
= data_chain1()
1161 test
= Test5(dut
, resultfn_12
, data
=data
)
1162 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe17.vcd")
1163 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1164 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1165 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1166 vl
= rtlil
.convert(dut
, ports
=ports
)
1167 with
open("test_unbufpipe17.il", "w") as f
:
1171 dut
= PassThroughTest()
1172 data
= data_chain1()
1173 test
= Test5(dut
, resultfn_identical
, data
=data
)
1174 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_passthru18.vcd")
1175 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1176 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1177 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1178 vl
= rtlil
.convert(dut
, ports
=ports
)
1179 with
open("test_passthru18.il", "w") as f
:
1183 dut
= ExampleBufPassThruPipe()
1184 data
= data_chain1()
1185 test
= Test5(dut
, resultfn_9
, data
=data
)
1186 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass19.vcd")
1187 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1188 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1189 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1190 vl
= rtlil
.convert(dut
, ports
=ports
)
1191 with
open("test_bufpass19.il", "w") as f
:
1196 data
= data_chain1()
1197 test
= Test5(dut
, resultfn_identical
, data
=data
)
1198 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifo20.vcd")
1199 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1200 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1201 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1202 vl
= rtlil
.convert(dut
, ports
=ports
)
1203 with
open("test_fifo20.il", "w") as f
:
1207 dut
= ExampleFIFOPassThruPipe1()
1208 data
= data_chain1()
1209 test
= Test5(dut
, resultfn_12
, data
=data
)
1210 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifopass21.vcd")
1211 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1212 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1213 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1214 vl
= rtlil
.convert(dut
, ports
=ports
)
1215 with
open("test_fifopass21.il", "w") as f
:
1219 dut
= ExampleRecordHandshakeAddClass()
1221 test
= Test5(dut
, resultfn_8
, data
=data
)
1222 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord22.vcd")
1223 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1224 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1225 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1227 vl
= rtlil
.convert(dut
, ports
=ports
)
1228 with
open("test_addrecord22.il", "w") as f
:
1232 dut
= ExampleFIFORecordObjectPipe()
1234 test
= Test5(dut
, resultfn_8
, data
=data
)
1235 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord23.vcd")
1236 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1237 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1238 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1240 vl
= rtlil
.convert(dut
, ports
=ports
)
1241 with
open("test_addrecord23.il", "w") as f
:
1245 dut
= FIFOTestRecordAddStageControl()
1247 test
= Test5(dut
, resultfn_8
, data
=data
)
1248 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1249 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1250 [dut
.p
.i_data
.op1
, dut
.p
.i_data
.op2
] + \
1252 vl
= rtlil
.convert(dut
, ports
=ports
)
1253 with
open("test_addrecord24.il", "w") as f
:
1255 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord24.vcd")
1258 dut
= ExampleFIFOAdd2Pipe()
1259 data
= data_chain1()
1260 test
= Test5(dut
, resultfn_9
, data
=data
)
1261 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_add2pipe25.vcd")
1262 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1263 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1264 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1265 vl
= rtlil
.convert(dut
, ports
=ports
)
1266 with
open("test_add2pipe25.il", "w") as f
:
1270 dut
= ExampleBufPassThruPipe2()
1271 data
= data_chain1()
1272 test
= Test5(dut
, resultfn_9
, data
=data
)
1273 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass997.vcd")
1274 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1275 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1276 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1277 vl
= rtlil
.convert(dut
, ports
=ports
)
1278 with
open("test_bufpass997.il", "w") as f
:
1281 print ("test 998 (fails, bug)")
1282 dut
= ExampleBufPipe3()
1283 data
= data_chain1()
1284 test
= Test5(dut
, resultfn_9
, data
=data
)
1285 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe14.vcd")
1286 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1287 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1288 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1289 vl
= rtlil
.convert(dut
, ports
=ports
)
1290 with
open("test_bufpipe14.il", "w") as f
:
1293 print ("test 999 (expected to fail, which is a bug)")
1294 dut
= ExampleBufUnBufPipe()
1295 data
= data_chain1()
1296 test
= Test5(dut
, resultfn_9
, data
=data
)
1297 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf999.vcd")
1298 ports
= [dut
.p
.i_valid
, dut
.n
.i_ready
,
1299 dut
.n
.o_valid
, dut
.p
.o_ready
] + \
1300 [dut
.p
.i_data
] + [dut
.n
.o_data
]
1301 vl
= rtlil
.convert(dut
, ports
=ports
)
1302 with
open("test_bufunbuf999.il", "w") as f
: