Merge pull request #2122 from PeterCrozier/struct_array2
[yosys.git] / passes / pmgen / ice40_dsp.pmg
1 pattern ice40_dsp
2
3 state <SigBit> clock
4 state <bool> clock_pol cd_signed o_lo
5 state <SigSpec> sigA sigB sigCD sigH sigO
6 state <Cell*> add mux
7 state <IdString> addAB muxAB
8
9 state <Cell*> ffA ffB ffCD
10 state <Cell*> ffFJKG ffH ffO
11
12 // subpattern
13 state <bool> argSdff
14 state <SigSpec> argQ argD
15 udata <SigSpec> dffD dffQ
16 udata <SigBit> dffclock
17 udata <Cell*> dff
18 udata <bool> dffclock_pol
19
20 match mul
21 select mul->type.in($mul, \SB_MAC16)
22 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
23 endmatch
24
25 code sigA sigB sigH
26 auto unextend = [](const SigSpec &sig) {
27 int i;
28 for (i = GetSize(sig)-1; i > 0; i--)
29 if (sig[i] != sig[i-1])
30 break;
31 // Do not remove non-const sign bit
32 if (sig[i].wire)
33 ++i;
34 return sig.extract(0, i);
35 };
36 sigA = unextend(port(mul, \A));
37 sigB = unextend(port(mul, \B));
38
39 SigSpec O;
40 if (mul->type == $mul)
41 O = mul->getPort(\Y);
42 else if (mul->type == \SB_MAC16)
43 O = mul->getPort(\O);
44 else log_abort();
45 if (GetSize(O) <= 10)
46 reject;
47
48 // Only care about those bits that are used
49 int i;
50 for (i = 0; i < GetSize(O); i++) {
51 if (nusers(O[i]) <= 1)
52 break;
53 sigH.append(O[i]);
54 }
55 // This sigM could have no users if downstream sinks (e.g. $add) is
56 // narrower than $mul result, for example
57 if (i == 0)
58 reject;
59
60 log_assert(nusers(O.extract_end(i)) <= 1);
61 endcode
62
63 code argQ ffA sigA clock clock_pol
64 if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
65 argQ = sigA;
66 subpattern(in_dffe);
67 if (dff) {
68 ffA = dff;
69 clock = dffclock;
70 clock_pol = dffclock_pol;
71 sigA = dffD;
72 }
73 }
74 endcode
75
76 code argQ ffB sigB clock clock_pol
77 if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
78 argQ = sigB;
79 subpattern(in_dffe);
80 if (dff) {
81 ffB = dff;
82 clock = dffclock;
83 clock_pol = dffclock_pol;
84 sigB = dffD;
85 }
86 }
87 endcode
88
89 code argD argSdff ffFJKG sigH clock clock_pol
90 if (nusers(sigH) == 2 &&
91 (mul->type != \SB_MAC16 ||
92 (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) {
93 argD = sigH;
94 argSdff = false;
95 subpattern(out_dffe);
96 if (dff) {
97 // F/J/K/G do not have a CE-like (hold) input
98 if (dff->hasPort(\EN))
99 goto reject_ffFJKG;
100
101 // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
102 // shared with A and B
103 if (ffA) {
104 if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
105 goto reject_ffFJKG;
106 if (ffA->hasPort(\ARST)) {
107 if (port(ffA, \ARST) != port(dff, \ARST))
108 goto reject_ffFJKG;
109 if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
110 goto reject_ffFJKG;
111 }
112 }
113 if (ffB) {
114 if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
115 goto reject_ffFJKG;
116 if (ffB->hasPort(\ARST)) {
117 if (port(ffB, \ARST) != port(dff, \ARST))
118 goto reject_ffFJKG;
119 if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
120 goto reject_ffFJKG;
121 }
122 }
123
124 ffFJKG = dff;
125 clock = dffclock;
126 clock_pol = dffclock_pol;
127 sigH = dffQ;
128
129 reject_ffFJKG: ;
130 }
131 }
132 endcode
133
134 code argD argSdff ffH sigH sigO clock clock_pol
135 if (ffFJKG && nusers(sigH) == 2 &&
136 (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
137 argD = sigH;
138 argSdff = false;
139 subpattern(out_dffe);
140 if (dff) {
141 // H does not have a CE-like (hold) input
142 if (dff->hasPort(\EN))
143 goto reject_ffH;
144
145 // Reset signal of H (IRSTBOT) shared with B
146 if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
147 goto reject_ffH;
148 if (ffB->hasPort(\ARST)) {
149 if (port(ffB, \ARST) != port(dff, \ARST))
150 goto reject_ffH;
151 if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
152 goto reject_ffH;
153 }
154
155 ffH = dff;
156 clock = dffclock;
157 clock_pol = dffclock_pol;
158 sigH = dffQ;
159
160 reject_ffH: ;
161 }
162 }
163
164 sigO = sigH;
165 endcode
166
167 match add
168 if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3)
169
170 select add->type.in($add)
171 choice <IdString> AB {\A, \B}
172 select nusers(port(add, AB)) == 2
173
174 index <SigBit> port(add, AB)[0] === sigH[0]
175 filter GetSize(port(add, AB)) <= GetSize(sigH)
176 filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB)))
177 filter nusers(sigH.extract_end(GetSize(port(add, AB)))) <= 1
178 set addAB AB
179 optional
180 endmatch
181
182 code sigCD sigO cd_signed
183 if (add) {
184 sigCD = port(add, addAB == \A ? \B : \A);
185 cd_signed = param(add, addAB == \A ? \B_SIGNED : \A_SIGNED).as_bool();
186
187 int natural_mul_width = GetSize(sigA) + GetSize(sigB);
188 int actual_mul_width = GetSize(sigH);
189 int actual_acc_width = GetSize(sigCD);
190
191 if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
192 reject;
193 // If accumulator, check adder width and signedness
194 if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool()))
195 reject;
196
197 sigO = port(add, \Y);
198 }
199 endcode
200
201 match mux
202 select mux->type == $mux
203 choice <IdString> AB {\A, \B}
204 select nusers(port(mux, AB)) == 2
205 index <SigSpec> port(mux, AB) === sigO
206 set muxAB AB
207 optional
208 endmatch
209
210 code sigO
211 if (mux)
212 sigO = port(mux, \Y);
213 endcode
214
215 code argD argSdff ffO sigO sigCD clock clock_pol cd_signed o_lo
216 if (mul->type != \SB_MAC16 ||
217 // Ensure that register is not already used
218 ((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) &&
219 // Ensure that OLOADTOP/OLOADBOT is unused or zero
220 (port(mul, \OLOADTOP, State::S0).is_fully_zero() && port(mul, \OLOADBOT, State::S0).is_fully_zero()))) {
221
222 dff = nullptr;
223
224 // First try entire sigO
225 if (nusers(sigO) == 2) {
226 argD = sigO;
227 argSdff = !mux;
228 subpattern(out_dffe);
229 }
230
231 // Otherwise try just its least significant 16 bits
232 if (!dff && GetSize(sigO) > 16) {
233 argD = sigO.extract(0, 16);
234 if (nusers(argD) == 2) {
235 argSdff = !mux;
236 subpattern(out_dffe);
237 o_lo = dff;
238 }
239 }
240
241 if (dff) {
242 ffO = dff;
243 clock = dffclock;
244 clock_pol = dffclock_pol;
245
246 sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
247 }
248
249 // Loading value into output register is not
250 // supported unless using accumulator
251 if (mux) {
252 if (sigCD != sigO)
253 reject;
254 sigCD = port(mux, muxAB == \B ? \A : \B);
255
256 cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
257 } else if (dff && dff->hasPort(\SRST)) {
258 if (sigCD != sigO)
259 reject;
260 sigCD = param(dff, \SRST_VALUE);
261
262 cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
263 }
264 }
265 endcode
266
267 code argQ ffCD sigCD clock clock_pol
268 if (!sigCD.empty() && sigCD != sigO &&
269 (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
270 argQ = sigCD;
271 subpattern(in_dffe);
272 if (dff) {
273 // Reset signal of C (IRSTTOP) and D (IRSTBOT)
274 // shared with A and B
275 if (ffA) {
276 if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
277 goto reject_ffCD;
278 if (ffA->hasPort(\ARST)) {
279 if (port(ffA, \ARST) != port(dff, \ARST))
280 goto reject_ffCD;
281 if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
282 goto reject_ffCD;
283 }
284 }
285 if (ffB) {
286 if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
287 goto reject_ffCD;
288 if (ffB->hasPort(\ARST)) {
289 if (port(ffB, \ARST) != port(dff, \ARST))
290 goto reject_ffCD;
291 if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
292 goto reject_ffCD;
293 }
294 }
295
296 ffCD = dff;
297 clock = dffclock;
298 clock_pol = dffclock_pol;
299 sigCD = dffD;
300
301 reject_ffCD: ;
302 }
303 }
304 endcode
305
306 code sigCD
307 sigCD.extend_u0(32, cd_signed);
308 endcode
309
310 code
311 accept;
312 endcode
313
314 // #######################
315
316 subpattern in_dffe
317 arg argD argQ clock clock_pol
318
319 code
320 dff = nullptr;
321 if (argQ.empty())
322 reject;
323 for (auto c : argQ.chunks()) {
324 if (!c.wire)
325 reject;
326 if (c.wire->get_bool_attribute(\keep))
327 reject;
328 Const init = c.wire->attributes.at(\init, State::Sx);
329 if (!init.is_fully_undef() && !init.is_fully_zero())
330 reject;
331 }
332 endcode
333
334 match ff
335 select ff->type.in($dff, $dffe)
336 // DSP48E1 does not support clock inversion
337 select param(ff, \CLK_POLARITY).as_bool()
338
339 slice offset GetSize(port(ff, \D))
340 index <SigBit> port(ff, \Q)[offset] === argQ[0]
341
342 // Check that the rest of argQ is present
343 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
344 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
345 endmatch
346
347 code argQ argD
348 {
349 if (clock != SigBit()) {
350 if (port(ff, \CLK) != clock)
351 reject;
352 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
353 reject;
354 }
355
356 SigSpec Q = port(ff, \Q);
357 dff = ff;
358 dffclock = port(ff, \CLK);
359 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
360 dffD = argQ;
361 argD = port(ff, \D);
362 argQ = Q;
363 dffD.replace(argQ, argD);
364 }
365 endcode
366
367 // #######################
368
369 subpattern out_dffe
370 arg argD argSdff argQ clock clock_pol
371
372 code
373 dff = nullptr;
374 for (auto c : argD.chunks())
375 if (c.wire->get_bool_attribute(\keep))
376 reject;
377 endcode
378
379 match ff
380 select ff->type.in($dff, $dffe, $sdff, $sdffce)
381 // SB_MAC16 does not support clock inversion
382 select param(ff, \CLK_POLARITY).as_bool()
383
384 slice offset GetSize(port(ff, \D))
385 index <SigBit> port(ff, \D)[offset] === argD[0]
386
387 // Only allow sync reset if requested.
388 filter argSdff || ff->type.in($dff, $dffe)
389 // Check that the rest of argD is present
390 filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
391 filter port(ff, \D).extract(offset, GetSize(argD)) == argD
392 endmatch
393
394 code argQ
395 if (ff) {
396 if (clock != SigBit()) {
397 if (port(ff, \CLK) != clock)
398 reject;
399 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
400 reject;
401 }
402 SigSpec D = port(ff, \D);
403 SigSpec Q = port(ff, \Q);
404 argQ = argD;
405 argQ.replace(D, Q);
406
407 for (auto c : argQ.chunks()) {
408 Const init = c.wire->attributes.at(\init, State::Sx);
409 if (!init.is_fully_undef() && !init.is_fully_zero())
410 reject;
411 }
412
413 dff = ff;
414 dffQ = argQ;
415 dffclock = port(ff, \CLK);
416 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
417 }
418 endcode