4 state <bool> clock_pol cd_signed
5 state <std::set<SigBit>> sigAset sigBset
6 state <SigSpec> sigA sigB sigCD sigH sigO sigOused
7 state <Cell*> addAB muxAB
10 select mul->type.in($mul, \SB_MAC16)
11 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
15 SigSpec A = port(mul, \A);
17 sigAset = A.to_sigbit_set();
18 SigSpec B = port(mul, \B);
20 sigBset = B.to_sigbit_set();
25 if (mul->type == $mul)
27 else if (mul->type == \SB_MAC16)
32 // Only care about those bits that are used
34 for (i = 0; i < GetSize(O); i++) {
35 if (nusers(O[i]) <= 1)
39 log_assert(nusers(O.extract_end(i)) <= 1);
43 if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()
45 select ffA->type.in($dff)
49 code sigA clock clock_pol
53 auto ffAset = port(ffA, \Q).to_sigbit_set();
54 if (!std::includes(ffAset.begin(), ffAset.end(), sigAset.begin(), sigAset.end()))
57 for (auto b : port(ffA, \Q))
58 if (b.wire->get_bool_attribute(\keep))
61 clock = port(ffA, \CLK).as_bit();
62 clock_pol = param(ffA, \CLK_POLARITY).as_bool();
64 sigA.replace(port(ffA, \Q), port(ffA, \D));
69 if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()
71 select ffB->type.in($dff)
75 code sigB clock clock_pol
79 auto ffBset = port(ffB, \Q).to_sigbit_set();
80 if (!std::includes(ffBset.begin(), ffBset.end(), sigBset.begin(), sigBset.end()))
83 for (auto b : port(ffB, \Q))
84 if (b.wire->get_bool_attribute(\keep))
87 SigBit c = port(ffB, \CLK).as_bit();
88 bool cp = param(ffB, \CLK_POLARITY).as_bool();
90 if (clock != SigBit() && (c != clock || cp != clock_pol))
96 sigB.replace(port(ffB, \Q), port(ffB, \D));
101 // Ensure pipeline register is not already used
102 if mul->type != \SB_MAC16 || (!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_REG2).as_bool())
103 select ffFJKG->type.in($dff)
104 select nusers(port(ffFJKG, \D)) == 2
105 index <SigSpec> port(ffFJKG, \D) === sigH
109 code sigH sigO clock clock_pol
111 sigH = port(ffFJKG, \Q);
113 if (b.wire->get_bool_attribute(\keep))
116 SigBit c = port(ffFJKG, \CLK).as_bit();
117 bool cp = param(ffFJKG, \CLK_POLARITY).as_bool();
119 if (clock != SigBit() && (c != clock || cp != clock_pol))
130 select addA->type.in($add)
131 select nusers(port(addA, \A)) == 2
132 filter param(addA, \A_WIDTH).as_int() <= GetSize(sigH)
133 //index <SigSpec> port(addA, \A) === sigH.extract(0, param(addA, \A_WIDTH).as_int())
134 filter port(addA, \A) == sigH.extract(0, param(addA, \A_WIDTH).as_int())
140 select addB->type.in($add, $sub)
141 select nusers(port(addB, \B)) == 2
142 filter param(addB, \B_WIDTH).as_int() <= GetSize(sigH)
143 //index <SigSpec> port(addB, \B) === sigH.extract(0, param(addB, \B_WIDTH).as_int())
144 filter port(addB, \B) == sigH.extract(0, param(addB, \B_WIDTH).as_int())
148 code addAB sigCD sigO cd_signed
151 sigCD = port(addAB, \B);
152 cd_signed = param(addAB, \B_SIGNED).as_bool();
156 sigCD = port(addAB, \A);
157 cd_signed = param(addAB, \A_SIGNED).as_bool();
160 if (mul->type == \SB_MAC16) {
161 // Ensure that adder is not used
162 if (param(mul, \TOPOUTPUT_SELECT).as_int() != 3 ||
163 param(mul, \BOTOUTPUT_SELECT).as_int() != 3)
167 int natural_mul_width = GetSize(sigA) + GetSize(sigB);
168 int actual_mul_width = GetSize(sigH);
169 int actual_acc_width = GetSize(sigCD);
171 if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
173 // If accumulator, check adder width and signedness
174 if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool()))
177 sigO = port(addAB, \Y);
182 select muxA->type.in($mux)
183 index <int> nusers(port(muxA, \A)) === 2
184 index <SigSpec> port(muxA, \A) === sigO
190 select muxB->type.in($mux)
191 index <int> nusers(port(muxB, \B)) === 2
192 index <SigSpec> port(muxB, \B) === sigO
202 sigO = port(muxAB, \Y);
206 // Ensure that register is not already used
207 if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1)
208 // Ensure that OLOADTOP/OLOADBOT is unused or zero
209 if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero())
211 select ffO->type.in($dff)
212 filter GetSize(port(ffO, \D)) >= GetSize(sigO)
213 slice offset GetSize(port(ffO, \D))
214 filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO
219 if !ffO && GetSize(sigO) > 16
220 // Ensure that register is not already used
221 if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1)
222 // Ensure that OLOADTOP/OLOADBOT is unused or zero
223 if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero())
224 if nusers(sigO.extract(0, 16)) == 2
225 select ffO_lo->type.in($dff)
226 filter GetSize(port(ffO_lo, \D)) >= 16
227 slice offset GetSize(port(ffO_lo, \D))
228 filter offset+GetSize(sigO) <= GetSize(port(ffO_lo, \D)) && port(ffO_lo, \D).extract(offset, 16) == sigO.extract(0, 16)
232 code clock clock_pol sigO sigCD cd_signed
239 for (auto b : port(ff, \Q))
240 if (b.wire->get_bool_attribute(\keep))
243 SigBit c = port(ff, \CLK).as_bit();
244 bool cp = param(ff, \CLK_POLARITY).as_bool();
246 if (clock != SigBit() && (c != clock || cp != clock_pol))
252 sigO.replace(port(ff, \D), port(ff, \Q));
254 // Loading value into output register is not
255 // supported unless using accumulator
260 sigCD = port(muxAB, \B);
262 sigCD = port(muxAB, \A);
265 cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
268 sigCD.extend_u0(32, cd_signed);