72e22c26062a611adc5650949328fa2fca8397df
[ieee754fpu.git] / src / ieee754 / fpcommon / test / fpmux.py
1 """ key strategic example showing how to do multi-input fan-in into a
2 multi-stage pipeline, then multi-output fanout.
3
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.
6 """
7
8 from random import randint
9 from nmigen.compat.sim import run_simulation
10 from nmigen.cli import verilog, rtlil
11
12
13 class MuxInOut:
14 def __init__(self, dut, width, fpkls, fpop, vals, single_op, opcode):
15 self.dut = dut
16 self.fpkls = fpkls
17 self.fpop = fpop
18 self.single_op = single_op
19 self.opcode = opcode
20 self.di = {}
21 self.do = {}
22 self.tlen = len(vals) // dut.num_rows
23 self.width = width
24 for muxid in range(dut.num_rows):
25 self.di[muxid] = {}
26 self.do[muxid] = []
27 for i in range(self.tlen):
28 if self.single_op:
29 #print ("vals", vals)
30 op1 = vals.pop(0)
31 if isinstance(op1, tuple):
32 assert len(op1) == 1
33 op1 = op1[0]
34 res = self.fpop(self.fpkls(op1))
35 self.di[muxid][i] = (op1, )
36 else:
37 (op1, op2, ) = vals.pop(0)
38 #print ("test", hex(op1), hex(op2))
39 res = self.fpop(self.fpkls(op1), self.fpkls(op2))
40 self.di[muxid][i] = (op1, op2)
41 if hasattr(res, "bits"):
42 self.do[muxid].append(res.bits)
43 else:
44 self.do[muxid].append(res) # for FP to INT
45
46 def send(self, muxid):
47 for i in range(self.tlen):
48 if self.single_op:
49 op1, = self.di[muxid][i]
50 else:
51 op1, op2 = self.di[muxid][i]
52 rs = self.dut.p[muxid]
53 yield rs.valid_i.eq(1)
54 yield rs.data_i.a.eq(op1)
55 if self.opcode is not None:
56 yield rs.data_i.ctx.op.eq(self.opcode)
57 if not self.single_op:
58 yield rs.data_i.b.eq(op2)
59 yield rs.data_i.muxid.eq(muxid)
60 yield
61 o_p_ready = yield rs.ready_o
62 while not o_p_ready:
63 yield
64 o_p_ready = yield rs.ready_o
65
66 if self.single_op:
67 fop1 = self.fpkls(op1)
68 res = self.fpop(fop1)
69 if hasattr(res, "bits"):
70 r = res.bits
71 else:
72 r = res
73 print("send", muxid, i, hex(op1), hex(r),
74 fop1, res)
75 else:
76 fop1 = self.fpkls(op1)
77 fop2 = self.fpkls(op2)
78 res = self.fpop(fop1, fop2)
79 print("send", muxid, i, hex(op1), hex(op2), hex(res.bits),
80 fop1, fop2, res)
81
82 yield rs.valid_i.eq(0)
83 # wait random period of time before queueing another value
84 for i in range(randint(0, 3)):
85 yield
86
87 yield rs.valid_i.eq(0)
88 yield
89
90 print("send ended", muxid)
91
92 ## wait random period of time before queueing another value
93 #for i in range(randint(0, 3)):
94 # yield
95
96 #send_range = randint(0, 3)
97 #if send_range == 0:
98 # send = True
99 #else:
100 # send = randint(0, send_range) != 0
101
102 def rcv(self, muxid):
103 while True:
104 #stall_range = randint(0, 3)
105 #for j in range(randint(1,10)):
106 # stall = randint(0, stall_range) != 0
107 # yield self.dut.n[0].ready_i.eq(stall)
108 # yield
109 n = self.dut.n[muxid]
110 yield n.ready_i.eq(1)
111 yield
112 o_n_valid = yield n.valid_o
113 i_n_ready = yield n.ready_i
114 if not o_n_valid or not i_n_ready:
115 continue
116
117 out_muxid = yield n.data_o.muxid
118 out_z = yield n.data_o.z
119
120 out_i = 0
121
122 print("recv", out_muxid, hex(out_z), "expected",
123 hex(self.do[muxid][out_i]))
124
125 # see if this output has occurred already, delete it if it has
126 assert muxid == out_muxid, "out_muxid %d not correct %d" % \
127 (out_muxid, muxid)
128 assert self.do[muxid][out_i] == out_z
129 del self.do[muxid][out_i]
130
131 # check if there's any more outputs
132 if len(self.do[muxid]) == 0:
133 break
134 print("recv ended", muxid)
135
136
137 def create_random(num_rows, width, single_op=False, n_vals=10):
138 vals = []
139 for muxid in range(num_rows):
140 for i in range(n_vals):
141 if single_op:
142 op1 = randint(0, (1 << width)-1)
143 #op1 = 0x40900000
144 #op1 = 0x94607b66
145 #op1 = 0x889cd8c
146 #op1 = 0xe98646d7
147 #op1 = 0x3340f2a7
148 #op1 = 0xfff13f05
149 #op1 = 0x453eb000
150 #op1 = 0x3a05de50
151 #op1 = 0xc27ff989
152 #op1 = 0x41689000
153 #op1 = 0xbbc0edec
154 #op1 = 0x2EDBE6FF
155 #op1 = 0x358637BD
156 #op1 = 0x3340f2a7
157 #op1 = 0x33D6BF95
158 #op1 = 0x9885020648d8c0e8
159 #op1 = 0xc26b
160 #op1 = 3
161
162 #op1 = 0x3a66
163 #op1 = 0x5299
164 #op1 = 0xe0eb
165 #op1 = 0x3954
166 #op1 = 0x4dea
167 #op1 = 0x65eb
168
169 #op1 = 0x1841
170
171 # FSQRT
172 #op1 = 0x3449f9a9
173 #op1 = 0x1ba94baa
174
175 #if i % 2:
176 # op1 = 0x0001
177 #else:
178 # op1 = 0x3C00
179
180 # FRSQRT
181 #op1 = 0x3686
182 #op1 = 0x4400
183 #op1 = 0x4800
184 #op1 = 0x48f0
185 #op1 = 0x429
186 #op1 = 0x2631
187 #op1 = 0x3001
188 #op1 = 0x3f2ad8eb
189
190 # f2int
191 #op1 = 0x4dc0
192 #op1 = 0x3b81
193 #op1 = 0xfcb6
194 #op1 = 0x4f8d77b3
195
196 # f2int signed
197 #op1 = 0xc913
198 #op1 = 0x7b97
199 #op1 = 0xaae2
200 #op1 = 0x7fca
201
202 # FCLASS
203 #op1 = 0x87d1
204 #op1 = 0x75e
205 #op1 = 0x7f8c
206 #op1 = 0x7c57
207 #op1 = 0xfea8
208 #op1 = 0xfd57
209
210 # f2int unsigned (fp64 to ui16)
211 #op1 = 0x40e6f5bc4d88b0cc
212
213 # f2int signed (fp64 to i16)
214 #op1 = 0xff292cf09f159ddb
215 #op1 = 0x5880e09f7cb716a1
216
217 # f2int signed (fp64 to i32)
218 #op1 = 0x5beb66ffc69a9a64
219 #op1 = 0xd4cdd178a1f2cdec
220
221 vals.append((op1,))
222 else:
223 op1 = randint(0, (1 << width)-1)
224 op2 = randint(0, (1 << width)-1)
225 # op1 = 0x3F800000 # 1.0f32
226 # op2 = 0x40000000 # 2.0f32
227
228 #op2 = 0x4000
229 #op1 = 0x3c50
230 #op2 = 0x3e00
231 #op2 = 0xb371
232 #op1 = 0x4400
233 #op1 = 0x656c
234 #op1 = 0x738c
235
236 vals.append((op1, op2,))
237 return vals
238
239
240 def repeat(num_rows, vals):
241 """ bit of a hack: repeats the last value to create a list
242 that will be accepted by the muxer, all mux lists to be
243 of equal length
244 """
245 vals = list(vals)
246 n_to_repeat = len(vals) % num_rows
247 #print ("repeat", vals)
248 return vals + [vals[-1]] * n_to_repeat
249
250
251 def pipe_cornercases_repeat(dut, name, mod, fmod, width, fn, cc, fpfn, count,
252 single_op=False, opcode=None):
253 for i, fixed_num in enumerate(cc(mod)):
254 vals = fn(mod, fixed_num, count, width, single_op)
255 vals = repeat(dut.num_rows, vals)
256 #print ("repeat", i, fn, single_op, list(vals))
257 fmt = "test_pipe_fp%d_%s_cornercases_%d"
258 runfp(dut, width, fmt % (width, name, i),
259 fmod, fpfn, vals=vals, single_op=single_op, opcode=opcode)
260
261
262 def runfp(dut, width, name, fpkls, fpop, single_op=False, n_vals=10,
263 vals=None, opcode=None):
264 vl = rtlil.convert(dut, ports=dut.ports())
265 with open("%s.il" % name, "w") as f:
266 f.write(vl)
267
268 if vals is None:
269 vals = create_random(dut.num_rows, width, single_op, n_vals)
270
271 test = MuxInOut(dut, width, fpkls, fpop, vals, single_op, opcode=opcode)
272 fns = []
273 for i in range(dut.num_rows):
274 fns.append(test.rcv(i))
275 fns.append(test.send(i))
276 run_simulation(dut, fns, vcd_name="%s.vcd" % name)