4 state <bool> clock_pol cd_signed
5 state <SigSpec> sigA sigB sigCD sigH sigO
6 state <Cell*> addAB muxAB
9 select mul->type.in($mul, \SB_MAC16)
10 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
15 if (mul->type == $mul)
17 else if (mul->type == \SB_MAC16)
25 for (i = GetSize(sigA)-1; i > 0; i--)
26 if (sigA[i] != sigA[i-1])
28 // Do not remove non-const sign bit
31 sigA.remove(i, GetSize(sigA)-i);
33 for (i = GetSize(sigB)-1; i > 0; i--)
34 if (sigB[i] != sigB[i-1])
36 // Do not remove non-const sign bit
39 sigB.remove(i, GetSize(sigB)-i);
41 // Only care about those bits that are used
42 for (i = 0; i < GetSize(O); i++) {
43 if (nusers(O[i]) <= 1)
47 log_assert(nusers(O.extract_end(i)) <= 1);
51 if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()
52 select ffA->type.in($dff)
53 filter GetSize(port(ffA, \Q)) >= GetSize(sigA)
54 slice offset GetSize(port(ffA, \Q))
55 filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA
59 code sigA clock clock_pol
61 for (auto b : port(ffA, \Q))
62 if (b.wire->get_bool_attribute(\keep))
65 clock = port(ffA, \CLK).as_bit();
66 clock_pol = param(ffA, \CLK_POLARITY).as_bool();
68 sigA.replace(port(ffA, \Q), port(ffA, \D));
73 if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()
74 select ffB->type.in($dff)
75 filter GetSize(port(ffB, \Q)) >= GetSize(sigB)
76 slice offset GetSize(port(ffB, \Q))
77 filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB
81 code sigB clock clock_pol
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);