1 """ key strategic example showing how to do multi-input fan-in into a
2 multi-stage pipeline, then multi-output fanout.
4 the multiplex ID from the fan-in is passed in to the pipeline, preserved,
5 and used as a routing ID on the fanout.
8 from random
import randint
9 from nmigen
.compat
.sim
import run_simulation
10 from nmigen
.cli
import verilog
, rtlil
14 def __init__(self
, dut
, width
, fpkls
, fpop
, vals
, single_op
):
18 self
.single_op
= single_op
21 self
.tlen
= len(vals
) // dut
.num_rows
23 for muxid
in range(dut
.num_rows
):
26 for i
in range(self
.tlen
):
30 if isinstance(op1
, tuple):
33 res
= self
.fpop(self
.fpkls(op1
))
34 self
.di
[muxid
][i
] = (op1
, )
36 (op1
, op2
, ) = vals
.pop(0)
37 #print ("test", hex(op1), hex(op2))
38 res
= self
.fpop(self
.fpkls(op1
), self
.fpkls(op2
))
39 self
.di
[muxid
][i
] = (op1
, op2
)
40 self
.do
[muxid
].append(res
.bits
)
42 def send(self
, muxid
):
43 for i
in range(self
.tlen
):
45 op1
, = self
.di
[muxid
][i
]
47 op1
, op2
= self
.di
[muxid
][i
]
48 rs
= self
.dut
.p
[muxid
]
49 yield rs
.valid_i
.eq(1)
50 yield rs
.data_i
.a
.eq(op1
)
51 if not self
.single_op
:
52 yield rs
.data_i
.b
.eq(op2
)
53 yield rs
.data_i
.muxid
.eq(muxid
)
55 o_p_ready
= yield rs
.ready_o
58 o_p_ready
= yield rs
.ready_o
61 fop1
= self
.fpkls(op1
)
63 print ("send", muxid
, i
, hex(op1
), hex(res
.bits
),
66 fop1
= self
.fpkls(op1
)
67 fop2
= self
.fpkls(op2
)
68 res
= self
.fpop(fop1
, fop2
)
69 print ("send", muxid
, i
, hex(op1
), hex(op2
), hex(res
.bits
),
72 yield rs
.valid_i
.eq(0)
73 # wait random period of time before queueing another value
74 for i
in range(randint(0, 3)):
77 yield rs
.valid_i
.eq(0)
80 print ("send ended", muxid
)
82 ## wait random period of time before queueing another value
83 #for i in range(randint(0, 3)):
86 #send_range = randint(0, 3)
90 # send = randint(0, send_range) != 0
94 #stall_range = randint(0, 3)
95 #for j in range(randint(1,10)):
96 # stall = randint(0, stall_range) != 0
97 # yield self.dut.n[0].ready_i.eq(stall)
100 yield n
.ready_i
.eq(1)
102 o_n_valid
= yield n
.valid_o
103 i_n_ready
= yield n
.ready_i
104 if not o_n_valid
or not i_n_ready
:
107 out_muxid
= yield n
.data_o
.muxid
108 out_z
= yield n
.data_o
.z
112 print ("recv", out_muxid
, hex(out_z
), "expected",
113 hex(self
.do
[muxid
][out_i
] ))
115 # see if this output has occurred already, delete it if it has
116 assert muxid
== out_muxid
, "out_muxid %d not correct %d" % \
118 assert self
.do
[muxid
][out_i
] == out_z
119 del self
.do
[muxid
][out_i
]
121 # check if there's any more outputs
122 if len(self
.do
[muxid
]) == 0:
124 print ("recv ended", muxid
)
127 def create_random(num_rows
, width
, single_op
=False, n_vals
=10):
129 for muxid
in range(num_rows
):
130 for i
in range(n_vals
):
132 op1
= randint(0, (1<<width
)-1)
148 #op1 = 0x9885020648d8c0e8
151 op1
= randint(0, (1<<width
)-1)
152 op2
= randint(0, (1<<width
)-1)
153 vals
.append((op1
, op2
,))
157 def repeat(num_rows
, vals
):
158 """ bit of a hack: repeats the last value to create a list
159 that will be accepted by the muxer, all mux lists to be
163 n_to_repeat
= len(vals
) % num_rows
164 #print ("repeat", vals)
165 return vals
+ [vals
[-1]] * n_to_repeat
168 def pipe_cornercases_repeat(dut
, name
, mod
, fmod
, width
, fn
, cc
, fpfn
, count
,
170 for i
, fixed_num
in enumerate(cc(mod
)):
171 vals
= fn(mod
, fixed_num
, count
, width
, single_op
)
172 vals
= repeat(dut
.num_rows
, vals
)
173 #print ("repeat", i, fn, single_op, list(vals))
174 fmt
= "test_pipe_fp%d_%s_cornercases_%d"
175 runfp(dut
, width
, fmt
% (width
, name
, i
),
176 fmod
, fpfn
, vals
=vals
, single_op
=single_op
)
179 def runfp(dut
, width
, name
, fpkls
, fpop
, single_op
=False, n_vals
=10, vals
=None):
180 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
181 with
open("%s.il" % name
, "w") as f
:
185 vals
= create_random(dut
.num_rows
, width
, single_op
, n_vals
)
187 test
= MuxInOut(dut
, width
, fpkls
, fpop
, vals
, single_op
)
189 for i
in range(dut
.num_rows
):
190 fns
.append(test
.rcv(i
))
191 fns
.append(test
.send(i
))
192 run_simulation(dut
, fns
, vcd_name
="%s.vcd" % name
)