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