3 state <std::function<SigSpec(const SigSpec&)>> unextend
5 state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP
6 state <IdString> postAddAB postAddMuxAB
7 state <bool> ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol
10 state <Cell*> ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux
14 state <bool> dffenpol_
16 udata <SigBit> dffclock
17 udata <Cell*> dff dffmux
21 select dsp->type.in(\DSP48E1)
24 code unextend sigA sigB sigC sigD sigM
25 unextend = [](const SigSpec &sig) {
27 for (i = GetSize(sig)-1; i > 0; i--)
28 if (sig[i] != sig[i-1])
30 // Do not remove non-const sign bit
33 return sig.extract(0, i);
35 sigA = unextend(port(dsp, \A));
36 sigB = unextend(port(dsp, \B));
38 sigC = dsp->connections_.at(\C, SigSpec());
39 sigD = dsp->connections_.at(\D, SigSpec());
41 SigSpec P = port(dsp, \P);
42 // Only care about those bits that are used
44 for (i = 0; i < GetSize(P); i++) {
45 if (nusers(P[i]) <= 1)
49 log_assert(nusers(P.extract_end(i)) <= 1);
50 //if (GetSize(sigM) <= 10)
54 code dffQ ffAD ffADmux ffADenpol sigA clock
55 if (param(dsp, \ADREG).as_int() == 0) {
71 if sigD.empty() || sigD.is_fully_zero()
72 // Ensure that preAdder not already used
73 if dsp->parameters.at(\USE_DPORT, Const("FALSE")).decode_string() == "FALSE"
74 if dsp->connections_.at(\INMODE, Const(0, 5)).is_fully_zero()
76 select preAdd->type.in($add)
77 // Output has to be 25 bits or less
78 select GetSize(port(preAdd, \Y)) <= 25
79 select nusers(port(preAdd, \Y)) == 2
80 choice <IdString> AB {\A, \B}
81 // A port has to be 30 bits or less
82 select GetSize(port(preAdd, AB)) <= 30
83 define <IdString> BA (AB == \A ? \B : \A)
84 // D port has to be 25 bits or less
85 select GetSize(port(preAdd, BA)) <= 25
86 index <SigSpec> port(preAdd, \Y) === sigA
93 sigA = port(preAdd, \A);
94 sigD = port(preAdd, \B);
95 if (GetSize(sigA) < GetSize(sigD))
96 std::swap(sigA, sigD);
100 code dffQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol
101 // Only search for ffA if there was a pre-adder
102 // (otherwise ffA would have been matched as ffAD)
104 if (param(dsp, \AREG).as_int() == 0) {
118 // And if there wasn't a pre-adder,
119 // move AD register to A
121 log_assert(!ffA && !ffAmux);
122 std::swap(ffA, ffAD);
123 std::swap(ffAmux, ffADmux);
124 ffAenpol = ffADenpol;
128 code dffQ ffB ffBmux ffBenpol sigB clock
129 if (param(dsp, \BREG).as_int() == 0) {
144 code dffQ ffD ffDmux ffDenpol sigD clock
145 if (param(dsp, \DREG).as_int() == 0) {
161 if param(dsp, \MREG).as_int() == 0
163 select ffMmux->type.in($mux)
164 choice <IdString> BA {\B, \A}
165 // new-value net must have exactly two users: dsp and ffMmux
166 select nusers(port(ffMmux, BA)) == 2
167 define <IdString> AB (BA == \B ? \A : \B)
168 // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s)
169 select nusers(port(ffMmux, AB)) >= 3
170 // ffMmux output must have two users: ffMmux and ffM.D
171 select nusers(port(ffMmux, \Y)) == 2
172 filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM)
173 filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA))))
174 // Remaining bits on sigM must not have any other users
175 filter nusers(sigM.extract_end(GetSize(unextend(port(ffMmux, BA))))) <= 1
176 define <bool> pol (AB == \A)
183 sigM = port(ffMmux, \Y);
189 select ffM_enable->type.in($dff)
190 // DSP48E1 does not support clock inversion
191 select param(ffM_enable, \CLK_POLARITY).as_bool()
192 index <SigSpec> port(ffM_enable, \D) === sigM
193 index <SigSpec> port(ffM_enable, \Q) === port(ffMmux, ffMenpol ? \A : \B)
198 if param(dsp, \MREG).as_int() == 0
200 select ffM->type.in($dff)
201 // DSP48E1 does not support clock inversion
202 select param(ffM, \CLK_POLARITY).as_bool()
203 index <SigSpec> port(ffM, \D) === sigM
207 code ffM clock sigM sigP
213 sigM = port(ffM, \Q);
216 if (b.wire->get_bool_attribute(\keep))
219 SigBit c = port(ffM, \CLK).as_bit();
220 if (clock != SigBit() && c != clock)
224 // No enable mux possible without flop
232 // Ensure that Z mux is not already used
233 if port(dsp, \OPMODE).extract(4,3).is_fully_zero()
235 select postAdd->type.in($add)
236 select GetSize(port(postAdd, \Y)) <= 48
237 select nusers(port(postAdd, \Y)) == 2
238 choice <IdString> AB {\A, \B}
239 select nusers(port(postAdd, AB)) <= 3
240 filter ffMmux || nusers(port(postAdd, AB)) == 2
241 filter !ffMmux || nusers(port(postAdd, AB)) == 3
242 filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP)
243 filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB))))
244 filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1
251 sigC = port(postAdd, postAddAB == \A ? \B : \A);
253 // TODO for DSP48E1, which will have sign extended inputs/outputs
254 //int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B));
255 //int actual_mul_width = GetSize(sigP);
256 //int actual_acc_width = GetSize(sigC);
258 //if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
260 //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(postAdd, \A_SIGNED).as_bool()))
263 sigP = port(postAdd, \Y);
268 if param(dsp, \PREG).as_int() == 0
269 // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux
270 if !ffMmux || postAdd || nusers(sigP) == 3
271 // Otherwise new-value net must have exactly two users: dsp and ffPmux
272 if (ffMmux && !postAdd) || nusers(sigP) == 2
274 select ffPmux->type.in($mux)
275 // ffPmux output must have two users: ffPmux and ffP.D
276 select nusers(port(ffPmux, \Y)) == 2
277 filter GetSize(port(ffPmux, \Y)) >= GetSize(sigP)
279 slice offset GetSize(port(ffPmux, \Y))
280 filter offset+GetSize(sigP) <= GetSize(port(ffPmux, \Y))
281 choice <IdString> BA {\B, \A}
282 filter port(ffPmux, BA).extract(offset, GetSize(sigP)) == sigP
284 define <IdString> AB (BA == \B ? \A : \B)
285 // keep-last-value net must have at least three users: ffPmux, ffP, downstream sink(s)
286 filter nusers(port(ffPmux, AB)) >= 3
287 define <bool> pol (AB == \A)
295 sigP.replace(port(ffPmux, ffPenpol ? \B : \A), port(ffPmux, \Y));
301 select ffP_enable->type.in($dff)
302 // DSP48E1 does not support clock inversion
303 select param(ffP_enable, \CLK_POLARITY).as_bool()
304 index <SigSpec> port(ffP_enable, \D) === port(ffPmux, \Y)
305 index <SigSpec> port(ffP_enable, \Q) === port(ffPmux, ffPenpol ? \A : \B)
306 filter GetSize(port(ffP_enable, \D)) >= GetSize(sigP)
307 filter ffPoffset+GetSize(sigP) <= GetSize(port(ffP_enable, \D))
308 filter port(ffP_enable, \D).extract(ffPoffset, GetSize(sigP)) == sigP
313 if param(dsp, \PREG).as_int() == 0
314 // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux
315 if !ffMmux || postAdd || nusers(sigP) == 3
316 // Otherwise new-value net must have exactly two users: dsp and ffPmux
317 if (ffMmux && !postAdd) || nusers(sigP) == 2
319 select ffP->type.in($dff)
320 // DSP48E1 does not support clock inversion
321 select param(ffP, \CLK_POLARITY).as_bool()
322 filter GetSize(port(ffP, \D)) >= GetSize(sigP)
323 slice offset GetSize(port(ffP, \D))
324 filter offset+GetSize(sigP) <= GetSize(port(ffP, \D))
325 filter port(ffP, \D).extract(offset, GetSize(sigP)) == sigP
335 for (auto b : port(ffP, \Q))
336 if (b.wire->get_bool_attribute(\keep))
339 SigBit c = port(ffP, \CLK).as_bit();
341 if (clock != SigBit() && c != clock)
346 sigP.replace(port(ffP, \D), port(ffP, \Q));
348 // No enable mux possible without flop
356 select postAddMux->type.in($mux)
357 select nusers(port(postAddMux, \Y)) == 2
358 choice <IdString> AB {\A, \B}
359 index <SigSpec> port(postAddMux, AB) === sigP
360 index <SigSpec> port(postAddMux, \Y) === sigC
367 sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
370 code dffQ ffC ffCmux ffCenpol sigC clock
371 if (param(dsp, \CREG).as_int() == 0) {
391 arg dffQ clock dffenpol_
399 select ff->type.in($dff)
400 // DSP48E1 does not support clock inversion
401 select param(ff, \CLK_POLARITY).as_bool()
402 filter GetSize(port(ff, \Q)) >= GetSize(dffQ)
403 slice offset GetSize(port(ff, \Q))
404 filter offset+GetSize(dffQ) <= GetSize(port(ff, \Q))
405 filter port(ff, \Q).extract(offset, GetSize(dffQ)) == dffQ
412 if (b.wire->get_bool_attribute(\keep))
415 if (clock != SigBit()) {
416 if (port(ff, \CLK) != clock)
420 dffclock = port(ff, \CLK);
424 dffD.replace(port(ff, \Q), port(ff, \D));
425 // Only search for ffmux if ff.Q has at
426 // least 3 users (ff, dsp, ffmux) and
427 // its ff.D only has two (ff, ffmux)
428 if (!(nusers(dffQ) >= 3 && nusers(dffD) == 2))
437 select ffmux->type.in($mux)
438 index <SigSpec> port(ffmux, \Y) === port(ff, \D)
439 filter GetSize(port(ffmux, \Y)) >= GetSize(dffD)
440 slice offset GetSize(port(ffmux, \Y))
441 filter offset+GetSize(dffD) <= GetSize(port(ffmux, \Y))
442 filter port(ffmux, \Y).extract(offset, GetSize(dffD)) == dffD
443 choice <IdString> AB {\A, \B}
444 filter offset+GetSize(dffQ) <= GetSize(port(ffmux, \Y))
445 filter port(ffmux, AB).extract(offset, GetSize(dffQ)) == dffQ
446 define <bool> pol (AB == \A)
454 dffenpol = dffenpol_;
455 dffD = port(ffmux, dffenpol ? \B : \A);