450852beb17ba1a8d863d71eb51a663bf4ffb5d4
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 nmutil
.test
.example_buf_pipe
import ExampleBufPipe
, ExampleBufPipeAdd
23 from nmutil
.test
.example_buf_pipe
import ExamplePipeline
, UnbufferedPipeline
24 from nmutil
.test
.example_buf_pipe
import ExampleStageCls
25 from nmutil
.iocontrol
import PrevControl
, NextControl
26 from nmutil
.stageapi
import StageChain
, StageCls
27 from nmutil
.singlepipe
import ControlBase
28 from nmutil
.singlepipe
import UnbufferedPipeline2
29 from nmutil
.singlepipe
import SimpleHandshake
30 from nmutil
.singlepipe
import BufferedHandshake
31 from nmutil
.singlepipe
import PassThroughHandshake
32 from nmutil
.singlepipe
import PassThroughStage
33 from nmutil
.singlepipe
import FIFOControl
34 from nmutil
.singlepipe
import RecordObject
35 from nmutil
.singlepipe
import MaskCancellable
37 from random
import randint
, seed
42 def check_o_n_valid(dut
, val
):
43 o_n_valid
= yield dut
.n
.valid_o
44 assert o_n_valid
== val
46 def check_o_n_valid2(dut
, val
):
47 o_n_valid
= yield dut
.n
.valid_o
48 assert o_n_valid
== val
52 #yield dut.i_p_rst.eq(1)
53 yield dut
.n
.ready_i
.eq(0)
54 #yield dut.p.ready_o.eq(0)
57 #yield dut.i_p_rst.eq(0)
58 yield dut
.n
.ready_i
.eq(1)
59 yield dut
.p
.data_i
.eq(5)
60 yield dut
.p
.valid_i
.eq(1)
63 yield dut
.p
.data_i
.eq(7)
64 yield from check_o_n_valid(dut
, 0) # effects of i_p_valid delayed
66 yield from check_o_n_valid(dut
, 1) # ok *now* i_p_valid effect is felt
68 yield dut
.p
.data_i
.eq(2)
70 yield dut
.n
.ready_i
.eq(0) # begin going into "stall" (next stage says ready)
71 yield dut
.p
.data_i
.eq(9)
73 yield dut
.p
.valid_i
.eq(0)
74 yield dut
.p
.data_i
.eq(12)
76 yield dut
.p
.data_i
.eq(32)
77 yield dut
.n
.ready_i
.eq(1)
79 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
81 yield from check_o_n_valid(dut
, 1) # buffer still needs to output
83 yield from check_o_n_valid(dut
, 0) # buffer outputted, *now* we're done.
88 #yield dut.p.i_rst.eq(1)
89 yield dut
.n
.ready_i
.eq(0)
90 #yield dut.p.ready_o.eq(0)
93 #yield dut.p.i_rst.eq(0)
94 yield dut
.n
.ready_i
.eq(1)
95 yield dut
.p
.data_i
.eq(5)
96 yield dut
.p
.valid_i
.eq(1)
99 yield dut
.p
.data_i
.eq(7)
100 yield from check_o_n_valid2(dut
, 0) # effects of i_p_valid delayed 2 clocks
102 yield from check_o_n_valid2(dut
, 0) # effects of i_p_valid delayed 2 clocks
104 yield dut
.p
.data_i
.eq(2)
106 yield from check_o_n_valid2(dut
, 1) # ok *now* i_p_valid effect is felt
107 yield dut
.n
.ready_i
.eq(0) # begin going into "stall" (next stage says ready)
108 yield dut
.p
.data_i
.eq(9)
110 yield dut
.p
.valid_i
.eq(0)
111 yield dut
.p
.data_i
.eq(12)
113 yield dut
.p
.data_i
.eq(32)
114 yield dut
.n
.ready_i
.eq(1)
116 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
118 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
120 yield from check_o_n_valid2(dut
, 1) # buffer still needs to output
122 yield from check_o_n_valid2(dut
, 0) # buffer outputted, *now* we're done.
129 def __init__(self
, dut
, resultfn
):
131 self
.resultfn
= resultfn
133 for i
in range(num_tests
):
134 #data.append(randint(0, 1<<16-1))
135 self
.data
.append(i
+1)
140 while self
.o
!= len(self
.data
):
141 send_range
= randint(0, 3)
142 for j
in range(randint(1,10)):
146 send
= randint(0, send_range
) != 0
147 o_p_ready
= yield self
.dut
.p
.ready_o
151 if send
and self
.i
!= len(self
.data
):
152 yield self
.dut
.p
.valid_i
.eq(1)
153 yield self
.dut
.p
.data_i
.eq(self
.data
[self
.i
])
156 yield self
.dut
.p
.valid_i
.eq(0)
160 while self
.o
!= len(self
.data
):
161 stall_range
= randint(0, 3)
162 for j
in range(randint(1,10)):
163 stall
= randint(0, stall_range
) != 0
164 yield self
.dut
.n
.ready_i
.eq(stall
)
166 o_n_valid
= yield self
.dut
.n
.valid_o
167 i_n_ready
= yield self
.dut
.n
.ready_i_test
168 if not o_n_valid
or not i_n_ready
:
170 data_o
= yield self
.dut
.n
.data_o
171 self
.resultfn(data_o
, self
.data
[self
.o
], self
.i
, self
.o
)
173 if self
.o
== len(self
.data
):
176 def resultfn_3(data_o
, expected
, i
, o
):
177 assert data_o
== expected
+ 1, \
178 "%d-%d data %x not match %x\n" \
179 % (i
, o
, data_o
, expected
)
181 def data_placeholder():
183 for i
in range(num_tests
):
185 d
.src1
= randint(0, 1<<16-1)
186 d
.src2
= randint(0, 1<<16-1)
192 for i
in range(num_tests
):
193 data
.append({'src1': randint(0, 1<<16-1),
194 'src2': randint(0, 1<<16-1)})
199 def __init__(self
, dut
, resultfn
, data
=None, stage_ctl
=False):
201 self
.resultfn
= resultfn
202 self
.stage_ctl
= stage_ctl
207 for i
in range(num_tests
):
208 self
.data
.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
213 while self
.o
!= len(self
.data
):
214 send_range
= randint(0, 3)
215 for j
in range(randint(1,10)):
219 send
= randint(0, send_range
) != 0
221 o_p_ready
= yield self
.dut
.p
.ready_o
225 if send
and self
.i
!= len(self
.data
):
226 yield self
.dut
.p
.valid_i
.eq(1)
227 for v
in self
.dut
.set_input(self
.data
[self
.i
]):
231 yield self
.dut
.p
.valid_i
.eq(0)
235 while self
.o
!= len(self
.data
):
236 stall_range
= randint(0, 3)
237 for j
in range(randint(1,10)):
238 ready
= randint(0, stall_range
) != 0
240 yield self
.dut
.n
.ready_i
.eq(ready
)
242 o_n_valid
= yield self
.dut
.n
.valid_o
243 i_n_ready
= yield self
.dut
.n
.ready_i_test
244 if not o_n_valid
or not i_n_ready
:
246 if isinstance(self
.dut
.n
.data_o
, Record
):
248 dod
= self
.dut
.n
.data_o
249 for k
, v
in dod
.fields
.items():
252 data_o
= yield self
.dut
.n
.data_o
253 self
.resultfn(data_o
, self
.data
[self
.o
], self
.i
, self
.o
)
255 if self
.o
== len(self
.data
):
259 def __init__(self
, dut
, resultfn
, maskwid
, data
=None, stage_ctl
=False):
261 self
.resultfn
= resultfn
262 self
.stage_ctl
= stage_ctl
263 self
.maskwid
= maskwid
268 for i
in range(num_tests
):
269 self
.data
.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
274 while self
.o
!= len(self
.data
):
275 send_range
= randint(0, 3)
276 for j
in range(randint(1,10)):
280 send
= randint(0, send_range
) != 0
282 o_p_ready
= yield self
.dut
.p
.ready_o
286 if send
and self
.i
!= len(self
.data
):
287 print ("send", self
.i
, self
.data
[self
.i
])
288 yield self
.dut
.p
.valid_i
.eq(1)
289 yield self
.dut
.p
.mask_i
.eq(1<<self
.i
) # XXX TODO
290 for v
in self
.dut
.set_input(self
.data
[self
.i
]):
294 yield self
.dut
.p
.valid_i
.eq(0)
295 yield self
.dut
.p
.mask_i
.eq(0) # XXX TODO
299 while self
.o
!= len(self
.data
):
300 stall_range
= randint(0, 3)
301 for j
in range(randint(1,10)):
302 ready
= randint(0, stall_range
) != 0
304 yield self
.dut
.n
.ready_i
.eq(ready
)
306 o_n_valid
= yield self
.dut
.n
.valid_o
307 i_n_ready
= yield self
.dut
.n
.ready_i_test
308 if not o_n_valid
or not i_n_ready
:
310 if isinstance(self
.dut
.n
.data_o
, Record
):
312 dod
= self
.dut
.n
.data_o
313 for k
, v
in dod
.fields
.items():
316 data_o
= yield self
.dut
.n
.data_o
317 print ("recv", self
.o
, data_o
)
318 self
.resultfn(data_o
, self
.data
[self
.o
], self
.i
, self
.o
)
320 if self
.o
== len(self
.data
):
323 def resultfn_5(data_o
, expected
, i
, o
):
324 res
= expected
[0] + expected
[1]
325 assert data_o
== res
, \
326 "%d-%d data %x not match %s\n" \
327 % (i
, o
, data_o
, repr(expected
))
331 for i
in range(num_tests
):
332 #data.append(randint(0, 1<<16-1))
337 stall
= randint(0, 3) != 0
338 send
= randint(0, 5) != 0
339 yield dut
.n
.ready_i
.eq(stall
)
340 o_p_ready
= yield dut
.p
.ready_o
342 if send
and i
!= len(data
):
343 yield dut
.p
.valid_i
.eq(1)
344 yield dut
.p
.data_i
.eq(data
[i
])
347 yield dut
.p
.valid_i
.eq(0)
349 o_n_valid
= yield dut
.n
.valid_o
350 i_n_ready
= yield dut
.n
.ready_i_test
351 if o_n_valid
and i_n_ready
:
352 data_o
= yield dut
.n
.data_o
353 assert data_o
== data
[o
] + 2, "%d-%d data %x not match %x\n" \
354 % (i
, o
, data_o
, data
[o
])
359 ######################################################################
361 ######################################################################
363 class ExampleBufPipe2(ControlBase
):
364 """ Example of how to do chained pipeline stages.
367 def elaborate(self
, platform
):
368 m
= ControlBase
.elaborate(self
, platform
)
370 pipe1
= ExampleBufPipe()
371 pipe2
= ExampleBufPipe()
373 m
.submodules
.pipe1
= pipe1
374 m
.submodules
.pipe2
= pipe2
376 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
381 ######################################################################
383 ######################################################################
385 class ExampleBufPipeChain2(BufferedHandshake
):
386 """ connects two stages together as a *single* combinatorial stage.
389 stage1
= ExampleStageCls()
390 stage2
= ExampleStageCls()
391 combined
= StageChain([stage1
, stage2
])
392 BufferedHandshake
.__init
__(self
, combined
)
397 for i
in range(num_tests
):
398 data
.append(randint(0, 1<<16-2))
402 def resultfn_9(data_o
, expected
, i
, o
):
404 assert data_o
== res
, \
405 "%d-%d received data %x not match expected %x\n" \
406 % (i
, o
, data_o
, res
)
409 ######################################################################
411 ######################################################################
413 class SetLessThan(Elaboratable
):
414 def __init__(self
, width
, signed
):
416 self
.src1
= Signal((width
, signed
), name
="src1")
417 self
.src2
= Signal((width
, signed
), name
="src2")
418 self
.output
= Signal(width
, name
="out")
420 def elaborate(self
, platform
):
421 self
.m
.d
.comb
+= self
.output
.eq(Mux(self
.src1
< self
.src2
, 1, 0))
425 class LTStage(StageCls
):
426 """ module-based stage example
429 self
.slt
= SetLessThan(16, True)
431 def ispec(self
, name
):
432 return (Signal(16, name
="%s_sig1" % name
),
433 Signal(16, name
="%s_sig2" % name
))
435 def ospec(self
, name
):
436 return Signal(16, "%s_out" % name
)
438 def setup(self
, m
, i
):
440 m
.submodules
.slt
= self
.slt
441 m
.d
.comb
+= self
.slt
.src1
.eq(i
[0])
442 m
.d
.comb
+= self
.slt
.src2
.eq(i
[1])
443 m
.d
.comb
+= self
.o
.eq(self
.slt
.output
)
445 def process(self
, i
):
449 class LTStageDerived(SetLessThan
, StageCls
):
450 """ special version of a nmigen module where the module is also a stage
452 shows that you don't actually need to combinatorially connect
453 to the outputs, or add the module as a submodule: just return
454 the module output parameter(s) from the Stage.process() function
458 SetLessThan
.__init
__(self
, 16, True)
461 return (Signal(16), Signal(16))
466 def setup(self
, m
, i
):
467 m
.submodules
.slt
= self
468 m
.d
.comb
+= self
.src1
.eq(i
[0])
469 m
.d
.comb
+= self
.src2
.eq(i
[1])
471 def process(self
, i
):
475 class ExampleLTPipeline(UnbufferedPipeline
):
476 """ an example of how to use the unbuffered pipeline.
481 UnbufferedPipeline
.__init
__(self
, stage
)
484 class ExampleLTBufferedPipeDerived(BufferedHandshake
):
485 """ an example of how to use the buffered pipeline.
489 stage
= LTStageDerived()
490 BufferedHandshake
.__init
__(self
, stage
)
493 def resultfn_6(data_o
, expected
, i
, o
):
494 res
= 1 if expected
[0] < expected
[1] else 0
495 assert data_o
== res
, \
496 "%d-%d data %x not match %s\n" \
497 % (i
, o
, data_o
, repr(expected
))
500 ######################################################################
502 ######################################################################
504 class ExampleAddRecordStage(StageCls
):
505 """ example use of a Record
508 record_spec
= [('src1', 16), ('src2', 16)]
510 """ returns a Record using the specification
512 return Record(self
.record_spec
)
515 return Record(self
.record_spec
)
517 def process(self
, i
):
518 """ process the input data, returning a dictionary with key names
519 that exactly match the Record's attributes.
521 return {'src1': i
.src1
+ 1,
524 ######################################################################
526 ######################################################################
528 class ExampleAddRecordPlaceHolderStage(StageCls
):
529 """ example use of a Record, with a placeholder as the processing result
532 record_spec
= [('src1', 16), ('src2', 16)]
534 """ returns a Record using the specification
536 return Record(self
.record_spec
)
539 return Record(self
.record_spec
)
541 def process(self
, i
):
542 """ process the input data, returning a PlaceHolder class instance
543 with attributes that exactly match those of the Record.
551 # a dummy class that may have stuff assigned to instances once created
552 class PlaceHolder
: pass
555 class ExampleAddRecordPipe(UnbufferedPipeline
):
556 """ an example of how to use the combinatorial pipeline.
560 stage
= ExampleAddRecordStage()
561 UnbufferedPipeline
.__init
__(self
, stage
)
564 def resultfn_7(data_o
, expected
, i
, o
):
565 res
= (expected
['src1'] + 1, expected
['src2'] + 1)
566 assert data_o
['src1'] == res
[0] and data_o
['src2'] == res
[1], \
567 "%d-%d data %s not match %s\n" \
568 % (i
, o
, repr(data_o
), repr(expected
))
571 class ExampleAddRecordPlaceHolderPipe(UnbufferedPipeline
):
572 """ an example of how to use the combinatorial pipeline.
576 stage
= ExampleAddRecordPlaceHolderStage()
577 UnbufferedPipeline
.__init
__(self
, stage
)
580 def resultfn_11(data_o
, expected
, i
, o
):
581 res1
= expected
.src1
+ 1
582 res2
= expected
.src2
+ 1
583 assert data_o
['src1'] == res1
and data_o
['src2'] == res2
, \
584 "%d-%d data %s not match %s\n" \
585 % (i
, o
, repr(data_o
), repr(expected
))
588 ######################################################################
590 ######################################################################
593 class Example2OpClass
:
594 """ an example of a class used to store 2 operands.
595 requires an eq function, to conform with the pipeline stage API
599 self
.op1
= Signal(16)
600 self
.op2
= Signal(16)
603 return [self
.op1
.eq(i
.op1
), self
.op2
.eq(i
.op2
)]
606 class ExampleAddClassStage(StageCls
):
607 """ an example of how to use the buffered pipeline, as a class instance
611 """ returns an instance of an Example2OpClass.
613 return Example2OpClass()
616 """ returns an output signal which will happen to contain the sum
619 return Signal(16, name
="add2_out")
621 def process(self
, i
):
622 """ process the input data (sums the values in the tuple) and returns it
627 class ExampleBufPipeAddClass(BufferedHandshake
):
628 """ an example of how to use the buffered pipeline, using a class instance
632 addstage
= ExampleAddClassStage()
633 BufferedHandshake
.__init
__(self
, addstage
)
637 """ the eq function, called by set_input, needs an incoming object
638 that conforms to the Example2OpClass.eq function requirements
639 easiest way to do that is to create a class that has the exact
640 same member layout (self.op1, self.op2) as Example2OpClass
642 def __init__(self
, op1
, op2
):
647 def resultfn_8(data_o
, expected
, i
, o
):
648 res
= expected
.op1
+ expected
.op2
# these are a TestInputAdd instance
649 assert data_o
== res
, \
650 "%d-%d data %s res %x not match %s\n" \
651 % (i
, o
, repr(data_o
), res
, repr(expected
))
655 for i
in range(num_tests
):
656 data
.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
660 ######################################################################
662 ######################################################################
664 class ExampleStageDelayCls(StageCls
, Elaboratable
):
665 """ an example of how to use the buffered pipeline, in a static class
669 def __init__(self
, valid_trigger
=2):
670 self
.count
= Signal(2)
671 self
.valid_trigger
= valid_trigger
674 return Signal(16, name
="example_input_signal")
677 return Signal(16, name
="example_output_signal")
681 """ data is ready to be accepted when this is true
683 return (self
.count
== 1)# | (self.count == 3)
686 def d_valid(self
, ready_i
):
687 """ data is valid at output when this is true
689 return self
.count
== self
.valid_trigger
692 def process(self
, i
):
693 """ process the input data and returns it (adds 1)
697 def elaborate(self
, platform
):
699 m
.d
.sync
+= self
.count
.eq(self
.count
+ 1)
703 class ExampleBufDelayedPipe(BufferedHandshake
):
706 stage
= ExampleStageDelayCls(valid_trigger
=2)
707 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
709 def elaborate(self
, platform
):
710 m
= BufferedHandshake
.elaborate(self
, platform
)
711 m
.submodules
.stage
= self
.stage
717 for i
in range(num_tests
):
718 data
.append(1<<((i
*3)%15))
719 #data.append(randint(0, 1<<16-2))
720 #print (hex(data[-1]))
724 def resultfn_12(data_o
, expected
, i
, o
):
726 assert data_o
== res
, \
727 "%d-%d data %x not match %x\n" \
728 % (i
, o
, data_o
, res
)
731 ######################################################################
733 ######################################################################
735 class ExampleUnBufDelayedPipe(BufferedHandshake
):
738 stage
= ExampleStageDelayCls(valid_trigger
=3)
739 BufferedHandshake
.__init
__(self
, stage
, stage_ctl
=True)
741 def elaborate(self
, platform
):
742 m
= BufferedHandshake
.elaborate(self
, platform
)
743 m
.submodules
.stage
= self
.stage
746 ######################################################################
748 ######################################################################
750 class ExampleBufModeAdd1Pipe(SimpleHandshake
):
753 stage
= ExampleStageCls()
754 SimpleHandshake
.__init
__(self
, stage
)
757 ######################################################################
759 ######################################################################
761 class ExampleBufModeUnBufPipe(ControlBase
):
763 def elaborate(self
, platform
):
764 m
= ControlBase
.elaborate(self
, platform
)
766 pipe1
= ExampleBufModeAdd1Pipe()
767 pipe2
= ExampleBufAdd1Pipe()
769 m
.submodules
.pipe1
= pipe1
770 m
.submodules
.pipe2
= pipe2
772 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
776 ######################################################################
778 ######################################################################
780 class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2
):
783 stage
= ExampleStageCls()
784 UnbufferedPipeline2
.__init__(self
, stage
)
787 ######################################################################
789 ######################################################################
791 class PassThroughTest(PassThroughHandshake
):
794 return Signal(16, "out")
797 stage
= PassThroughStage(self
.iospecfn
)
798 PassThroughHandshake
.__init
__(self
, stage
)
800 def resultfn_identical(data_o
, expected
, i
, o
):
802 assert data_o
== res
, \
803 "%d-%d data %x not match %x\n" \
804 % (i
, o
, data_o
, res
)
807 ######################################################################
809 ######################################################################
811 class ExamplePassAdd1Pipe(PassThroughHandshake
):
814 stage
= ExampleStageCls()
815 PassThroughHandshake
.__init
__(self
, stage
)
818 class ExampleBufPassThruPipe(ControlBase
):
820 def elaborate(self
, platform
):
821 m
= ControlBase
.elaborate(self
, platform
)
823 # XXX currently fails: any other permutation works fine.
824 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
825 # also fails using UnbufferedPipeline as well
826 pipe1
= ExampleBufModeAdd1Pipe()
827 pipe2
= ExamplePassAdd1Pipe()
829 m
.submodules
.pipe1
= pipe1
830 m
.submodules
.pipe2
= pipe2
832 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
837 ######################################################################
839 ######################################################################
842 return Signal(16, name
="d_in")
844 class FIFOTest16(FIFOControl
):
847 stage
= PassThroughStage(iospecfn
)
848 FIFOControl
.__init
__(self
, 2, stage
)
851 ######################################################################
853 ######################################################################
855 class ExampleFIFOPassThruPipe1(ControlBase
):
857 def elaborate(self
, platform
):
858 m
= ControlBase
.elaborate(self
, platform
)
862 pipe3
= ExamplePassAdd1Pipe()
864 m
.submodules
.pipe1
= pipe1
865 m
.submodules
.pipe2
= pipe2
866 m
.submodules
.pipe3
= pipe3
868 m
.d
.comb
+= self
.connect([pipe1
, pipe2
, pipe3
])
873 ######################################################################
875 ######################################################################
877 class Example2OpRecord(RecordObject
):
879 RecordObject
.__init
__(self
)
880 self
.op1
= Signal(16)
881 self
.op2
= Signal(16)
884 class ExampleAddRecordObjectStage(StageCls
):
887 """ returns an instance of an Example2OpRecord.
889 return Example2OpRecord()
892 """ returns an output signal which will happen to contain the sum
897 def process(self
, i
):
898 """ process the input data (sums the values in the tuple) and returns it
903 class ExampleRecordHandshakeAddClass(SimpleHandshake
):
906 addstage
= ExampleAddRecordObjectStage()
907 SimpleHandshake
.__init
__(self
, stage
=addstage
)
910 ######################################################################
912 ######################################################################
914 def iospecfnrecord():
915 return Example2OpRecord()
917 class FIFOTestRecordControl(FIFOControl
):
920 stage
= PassThroughStage(iospecfnrecord
)
921 FIFOControl
.__init
__(self
, 2, stage
)
924 class ExampleFIFORecordObjectPipe(ControlBase
):
926 def elaborate(self
, platform
):
927 m
= ControlBase
.elaborate(self
, platform
)
929 pipe1
= FIFOTestRecordControl()
930 pipe2
= ExampleRecordHandshakeAddClass()
932 m
.submodules
.pipe1
= pipe1
933 m
.submodules
.pipe2
= pipe2
935 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
940 ######################################################################
942 ######################################################################
944 class FIFOTestRecordAddStageControl(FIFOControl
):
947 stage
= ExampleAddRecordObjectStage()
948 FIFOControl
.__init
__(self
, 2, stage
)
952 ######################################################################
954 ######################################################################
956 class FIFOTestAdd16(FIFOControl
):
959 stage
= ExampleStageCls()
960 FIFOControl
.__init
__(self
, 2, stage
)
963 class ExampleFIFOAdd2Pipe(ControlBase
):
965 def elaborate(self
, platform
):
966 m
= ControlBase
.elaborate(self
, platform
)
968 pipe1
= FIFOTestAdd16()
969 pipe2
= FIFOTestAdd16()
971 m
.submodules
.pipe1
= pipe1
972 m
.submodules
.pipe2
= pipe2
974 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
979 ######################################################################
981 ######################################################################
984 return (Signal(16, name
="src1"), Signal(16, name
="src2"))
986 class FIFOTest2x16(FIFOControl
):
989 stage
= PassThroughStage(iospecfn2
)
990 FIFOControl
.__init
__(self
, 2, stage
)
993 ######################################################################
995 ######################################################################
997 class ExampleBufPassThruPipe2(ControlBase
):
999 def elaborate(self
, platform
):
1000 m
= ControlBase
.elaborate(self
, platform
)
1002 # XXX currently fails: any other permutation works fine.
1003 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
1004 # also fails using UnbufferedPipeline as well
1005 #pipe1 = ExampleUnBufAdd1Pipe()
1006 #pipe2 = ExampleBufAdd1Pipe()
1007 pipe1
= ExampleBufAdd1Pipe()
1008 pipe2
= ExamplePassAdd1Pipe()
1010 m
.submodules
.pipe1
= pipe1
1011 m
.submodules
.pipe2
= pipe2
1013 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1018 ######################################################################
1020 ######################################################################
1022 class ExampleBufPipe3(ControlBase
):
1023 """ Example of how to do delayed pipeline, where the stage signals
1024 whether it is ready.
1027 def elaborate(self
, platform
):
1028 m
= ControlBase
.elaborate(self
, platform
)
1030 pipe1
= ExampleBufDelayedPipe()
1031 pipe2
= ExampleBufPipe()
1033 m
.submodules
.pipe1
= pipe1
1034 m
.submodules
.pipe2
= pipe2
1036 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1040 ######################################################################
1041 # Test 999 - XXX FAILS
1042 # http://bugs.libre-riscv.org/show_bug.cgi?id=57
1043 ######################################################################
1045 class ExampleBufAdd1Pipe(BufferedHandshake
):
1048 stage
= ExampleStageCls()
1049 BufferedHandshake
.__init
__(self
, stage
)
1052 class ExampleUnBufAdd1Pipe(UnbufferedPipeline
):
1055 stage
= ExampleStageCls()
1056 UnbufferedPipeline
.__init
__(self
, stage
)
1059 class ExampleBufUnBufPipe(ControlBase
):
1061 def elaborate(self
, platform
):
1062 m
= ControlBase
.elaborate(self
, platform
)
1064 # XXX currently fails: any other permutation works fine.
1065 # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
1066 # also fails using UnbufferedPipeline as well
1067 #pipe1 = ExampleUnBufAdd1Pipe()
1068 #pipe2 = ExampleBufAdd1Pipe()
1069 pipe1
= ExampleBufAdd1Pipe()
1070 pipe2
= ExampleUnBufAdd1Pipe()
1072 m
.submodules
.pipe1
= pipe1
1073 m
.submodules
.pipe2
= pipe2
1075 m
.d
.comb
+= self
.connect([pipe1
, pipe2
])
1080 ######################################################################
1082 ######################################################################
1084 class ExampleMaskRecord(RecordObject
):
1085 """ an example of a class used to store 2 operands.
1086 requires an eq function, to conform with the pipeline stage API
1090 RecordObject
.__init
__(self
)
1091 self
.src1
= Signal(16)
1092 self
.src2
= Signal(16)
1095 return [self
.src1
.eq(i
.src1
), self
.src2
.eq(i
.src2
)]
1098 class TestInputMask
:
1099 """ the eq function, called by set_input, needs an incoming object
1100 that conforms to the Example2OpClass.eq function requirements
1101 easiest way to do that is to create a class that has the exact
1102 same member layout (self.op1, self.op2) as Example2OpClass
1104 def __init__(self
, src1
, src2
):
1109 return "<TestInputMask %x %x" % (self
.src1
, self
.src2
)
1111 class ExampleMaskCancellable(StageCls
):
1114 """ returns an instance of an ExampleMaskRecord.
1116 return ExampleMaskRecord()
1119 """ returns the same
1121 return ExampleMaskRecord()
1123 def process(self
, i
):
1124 """ process the input data: increase op1 and op2
1126 return TestInputMask(i
.src1
+ 1, i
.src2
+ 1)
1129 class MaskCancellablePipe(MaskCancellable
):
1131 """ connects two stages together as a *single* combinatorial stage.
1134 self
.cancelmask
= Signal(16)
1135 stage1
= ExampleMaskCancellable()
1136 stage2
= ExampleMaskCancellable()
1137 combined
= StageChain([stage1
, stage2
])
1138 MaskCancellable
.__init
__(self
, combined
, 16)
1143 for i
in range(num_tests
):
1144 data
.append(TestInputMask(randint(0, 1<<16-1),
1145 randint(0, 1<<16-1)))
1149 def resultfn_0(data_o
, expected
, i
, o
):
1150 assert data_o
['src1'] == expected
.src1
+ 2, \
1151 "src1 %x-%x received data no match\n" \
1152 % (data_o
['src1'], expected
.src1
+ 2)
1153 assert data_o
['src2'] == expected
.src2
+ 2, \
1154 "src2 %x-%x received data no match\n" \
1155 % (data_o
['src2'] , expected
.src2
+ 2)
1158 ######################################################################
1160 ######################################################################
1166 dut
= MaskCancellablePipe()
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_bufpipe14.il", "w") as f:
1173 data
= data_chain0()
1174 test
= TestMask(dut
, resultfn_0
, 16, data
=data
)
1175 run_simulation(dut
, [test
.send
, test
.rcv
],
1176 vcd_name
="test_maskchain0.vcd")
1180 dut
= ExampleBufPipe()
1181 run_simulation(dut
, tbench(dut
), vcd_name
="test_bufpipe.vcd")
1185 dut
= ExampleBufPipe2()
1186 run_simulation(dut
, tbench2(dut
), vcd_name
="test_bufpipe2.vcd")
1187 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1188 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1189 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1190 vl
= rtlil
.convert(dut
, ports
=ports
)
1191 with
open("test_bufpipe2.il", "w") as f
:
1196 dut
= ExampleBufPipe()
1197 test
= Test3(dut
, resultfn_3
)
1198 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe3.vcd")
1202 dut
= ExamplePipeline()
1203 test
= Test3(dut
, resultfn_3
)
1204 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_combpipe3.vcd")
1208 dut
= ExampleBufPipe2()
1209 run_simulation(dut
, tbench4(dut
), vcd_name
="test_bufpipe4.vcd")
1213 dut
= ExampleBufPipeAdd()
1214 test
= Test5(dut
, resultfn_5
, stage_ctl
=True)
1215 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe5.vcd")
1219 dut
= ExampleLTPipeline()
1220 test
= Test5(dut
, resultfn_6
)
1221 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltcomb6.vcd")
1223 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1224 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1225 list(dut
.p
.data_i
) + [dut
.n
.data_o
]
1226 vl
= rtlil
.convert(dut
, ports
=ports
)
1227 with
open("test_ltcomb_pipe.il", "w") as f
:
1232 dut
= ExampleAddRecordPipe()
1234 test
= Test5(dut
, resultfn_7
, data
=data
)
1235 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1236 dut
.n
.valid_o
, dut
.p
.ready_o
,
1237 dut
.p
.data_i
.src1
, dut
.p
.data_i
.src2
,
1238 dut
.n
.data_o
.src1
, dut
.n
.data_o
.src2
]
1239 vl
= rtlil
.convert(dut
, ports
=ports
)
1240 with
open("test_recordcomb_pipe.il", "w") as f
:
1242 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1246 dut
= ExampleBufPipeAddClass()
1248 test
= Test5(dut
, resultfn_8
, data
=data
)
1249 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe8.vcd")
1253 dut
= ExampleBufPipeChain2()
1254 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1255 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1256 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1257 vl
= rtlil
.convert(dut
, ports
=ports
)
1258 with
open("test_bufpipechain2.il", "w") as f
:
1261 data
= data_chain2()
1262 test
= Test5(dut
, resultfn_9
, data
=data
)
1263 run_simulation(dut
, [test
.send
, test
.rcv
],
1264 vcd_name
="test_bufpipechain2.vcd")
1268 dut
= ExampleLTBufferedPipeDerived()
1269 test
= Test5(dut
, resultfn_6
)
1270 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_ltbufpipe10.vcd")
1272 vl
= rtlil
.convert(dut
, ports
=ports
)
1273 with
open("test_ltbufpipe10.il", "w") as f
:
1278 dut
= ExampleAddRecordPlaceHolderPipe()
1279 data
=data_placeholder()
1280 test
= Test5(dut
, resultfn_11
, data
=data
)
1281 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord.vcd")
1286 dut
= ExampleBufDelayedPipe()
1287 data
= data_chain1()
1288 test
= Test5(dut
, resultfn_12
, data
=data
)
1289 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe12.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_bufpipe12.il", "w") as f
:
1299 dut
= ExampleUnBufDelayedPipe()
1300 data
= data_chain1()
1301 test
= Test5(dut
, resultfn_12
, data
=data
)
1302 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe13.vcd")
1303 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1304 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1305 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1306 vl
= rtlil
.convert(dut
, ports
=ports
)
1307 with
open("test_unbufpipe13.il", "w") as f
:
1312 dut
= ExampleBufModeAdd1Pipe()
1313 data
= data_chain1()
1314 test
= Test5(dut
, resultfn_12
, data
=data
)
1315 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf15.vcd")
1316 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1317 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1318 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1319 vl
= rtlil
.convert(dut
, ports
=ports
)
1320 with
open("test_bufunbuf15.il", "w") as f
:
1325 dut
= ExampleBufModeUnBufPipe()
1326 data
= data_chain1()
1327 test
= Test5(dut
, resultfn_9
, data
=data
)
1328 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf16.vcd")
1329 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1330 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1331 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1332 vl
= rtlil
.convert(dut
, ports
=ports
)
1333 with
open("test_bufunbuf16.il", "w") as f
:
1338 dut
= ExampleUnBufAdd1Pipe2()
1339 data
= data_chain1()
1340 test
= Test5(dut
, resultfn_12
, data
=data
)
1341 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_unbufpipe17.vcd")
1342 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1343 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1344 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1345 vl
= rtlil
.convert(dut
, ports
=ports
)
1346 with
open("test_unbufpipe17.il", "w") as f
:
1351 dut
= PassThroughTest()
1352 data
= data_chain1()
1353 test
= Test5(dut
, resultfn_identical
, data
=data
)
1354 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_passthru18.vcd")
1355 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1356 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1357 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1358 vl
= rtlil
.convert(dut
, ports
=ports
)
1359 with
open("test_passthru18.il", "w") as f
:
1364 dut
= ExampleBufPassThruPipe()
1365 data
= data_chain1()
1366 test
= Test5(dut
, resultfn_9
, data
=data
)
1367 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass19.vcd")
1368 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1369 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1370 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1371 vl
= rtlil
.convert(dut
, ports
=ports
)
1372 with
open("test_bufpass19.il", "w") as f
:
1378 data
= data_chain1()
1379 test
= Test5(dut
, resultfn_identical
, data
=data
)
1380 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifo20.vcd")
1381 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1382 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1383 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1384 vl
= rtlil
.convert(dut
, ports
=ports
)
1385 with
open("test_fifo20.il", "w") as f
:
1390 dut
= ExampleFIFOPassThruPipe1()
1391 data
= data_chain1()
1392 test
= Test5(dut
, resultfn_12
, data
=data
)
1393 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_fifopass21.vcd")
1394 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1395 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1396 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1397 vl
= rtlil
.convert(dut
, ports
=ports
)
1398 with
open("test_fifopass21.il", "w") as f
:
1403 dut
= ExampleRecordHandshakeAddClass()
1405 test
= Test5(dut
, resultfn_8
, data
=data
)
1406 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord22.vcd")
1407 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1408 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1409 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1411 vl
= rtlil
.convert(dut
, ports
=ports
)
1412 with
open("test_addrecord22.il", "w") as f
:
1417 dut
= ExampleFIFORecordObjectPipe()
1419 test
= Test5(dut
, resultfn_8
, data
=data
)
1420 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord23.vcd")
1421 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1422 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1423 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1425 vl
= rtlil
.convert(dut
, ports
=ports
)
1426 with
open("test_addrecord23.il", "w") as f
:
1431 dut
= FIFOTestRecordAddStageControl()
1433 test
= Test5(dut
, resultfn_8
, data
=data
)
1434 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1435 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1436 [dut
.p
.data_i
.op1
, dut
.p
.data_i
.op2
] + \
1438 vl
= rtlil
.convert(dut
, ports
=ports
)
1439 with
open("test_addrecord24.il", "w") as f
:
1441 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_addrecord24.vcd")
1445 dut
= ExampleFIFOAdd2Pipe()
1446 data
= data_chain1()
1447 test
= Test5(dut
, resultfn_9
, data
=data
)
1448 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_add2pipe25.vcd")
1449 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1450 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1451 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1452 vl
= rtlil
.convert(dut
, ports
=ports
)
1453 with
open("test_add2pipe25.il", "w") as f
:
1458 dut
= ExampleBufPassThruPipe2()
1459 data
= data_chain1()
1460 test
= Test5(dut
, resultfn_9
, data
=data
)
1461 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpass997.vcd")
1462 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1463 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1464 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1465 vl
= rtlil
.convert(dut
, ports
=ports
)
1466 with
open("test_bufpass997.il", "w") as f
:
1470 print ("test 998 (fails, bug)")
1471 dut
= ExampleBufPipe3()
1472 data
= data_chain1()
1473 test
= Test5(dut
, resultfn_9
, data
=data
)
1474 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufpipe14.vcd")
1475 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1476 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1477 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1478 vl
= rtlil
.convert(dut
, ports
=ports
)
1479 with
open("test_bufpipe14.il", "w") as f
:
1483 print ("test 999 (expected to fail, which is a bug)")
1484 dut
= ExampleBufUnBufPipe()
1485 data
= data_chain1()
1486 test
= Test5(dut
, resultfn_9
, data
=data
)
1487 run_simulation(dut
, [test
.send
, test
.rcv
], vcd_name
="test_bufunbuf999.vcd")
1488 ports
= [dut
.p
.valid_i
, dut
.n
.ready_i
,
1489 dut
.n
.valid_o
, dut
.p
.ready_o
] + \
1490 [dut
.p
.data_i
] + [dut
.n
.data_o
]
1491 vl
= rtlil
.convert(dut
, ports
=ports
)
1492 with
open("test_bufunbuf999.il", "w") as f
:
1495 if __name__
== '__main__':