Fix broken ice40_dsp
[yosys.git] / passes / pmgen / ice40_dsp.pmg
1 pattern ice40_dsp
2
3 state <SigBit> clock
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
8
9 match mul
10 select mul->type.in($mul, \SB_MAC16)
11 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
12 endmatch
13
14 code sigAset sigBset
15 SigSpec A = port(mul, \A);
16 A.remove_const();
17 sigAset = A.to_sigbit_set();
18 SigSpec B = port(mul, \B);
19 B.remove_const();
20 sigBset = B.to_sigbit_set();
21 endcode
22
23 code sigH
24 SigSpec O;
25 if (mul->type == $mul)
26 O = mul->getPort(\Y);
27 else if (mul->type == \SB_MAC16)
28 O = mul->getPort(\O);
29 else log_abort();
30 if (GetSize(O) <= 10)
31 reject;
32 // Only care about those bits that are used
33 int i;
34 for (i = 0; i < GetSize(O); i++) {
35 if (nusers(O[i]) <= 1)
36 break;
37 sigH.append(O[i]);
38 }
39 log_assert(nusers(O.extract_end(i)) <= 1);
40 endcode
41
42 match ffA
43 if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()
44 if !sigAset.empty()
45 select ffA->type.in($dff)
46 optional
47 endmatch
48
49 code sigA clock clock_pol
50 sigA = port(mul, \A);
51
52 if (ffA) {
53 auto ffAset = port(ffA, \Q).to_sigbit_set();
54 if (!std::includes(ffAset.begin(), ffAset.end(), sigAset.begin(), sigAset.end()))
55 reject;
56
57 for (auto b : port(ffA, \Q))
58 if (b.wire->get_bool_attribute(\keep))
59 reject;
60
61 clock = port(ffA, \CLK).as_bit();
62 clock_pol = param(ffA, \CLK_POLARITY).as_bool();
63
64 sigA.replace(port(ffA, \Q), port(ffA, \D));
65 }
66 endcode
67
68 match ffB
69 if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()
70 if !sigBset.empty()
71 select ffB->type.in($dff)
72 optional
73 endmatch
74
75 code sigB clock clock_pol
76 sigB = port(mul, \B);
77
78 if (ffB) {
79 auto ffBset = port(ffB, \Q).to_sigbit_set();
80 if (!std::includes(ffBset.begin(), ffBset.end(), sigBset.begin(), sigBset.end()))
81 reject;
82
83 for (auto b : port(ffB, \Q))
84 if (b.wire->get_bool_attribute(\keep))
85 reject;
86
87 SigBit c = port(ffB, \CLK).as_bit();
88 bool cp = param(ffB, \CLK_POLARITY).as_bool();
89
90 if (clock != SigBit() && (c != clock || cp != clock_pol))
91 reject;
92
93 clock = c;
94 clock_pol = cp;
95
96 sigB.replace(port(ffB, \Q), port(ffB, \D));
97 }
98 endcode
99
100 match ffFJKG
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
106 optional
107 endmatch
108
109 code sigH sigO clock clock_pol
110 if (ffFJKG) {
111 sigH = port(ffFJKG, \Q);
112 for (auto b : sigH)
113 if (b.wire->get_bool_attribute(\keep))
114 reject;
115
116 SigBit c = port(ffFJKG, \CLK).as_bit();
117 bool cp = param(ffFJKG, \CLK_POLARITY).as_bool();
118
119 if (clock != SigBit() && (c != clock || cp != clock_pol))
120 reject;
121
122 clock = c;
123 clock_pol = cp;
124 }
125
126 sigO = sigH;
127 endcode
128
129 match addA
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())
135 optional
136 endmatch
137
138 match addB
139 if !addA
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())
145 optional
146 endmatch
147
148 code addAB sigCD sigO cd_signed
149 if (addA) {
150 addAB = addA;
151 sigCD = port(addAB, \B);
152 cd_signed = param(addAB, \B_SIGNED).as_bool();
153 }
154 else if (addB) {
155 addAB = addB;
156 sigCD = port(addAB, \A);
157 cd_signed = param(addAB, \A_SIGNED).as_bool();
158 }
159 if (addAB) {
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)
164 reject;
165 }
166
167 int natural_mul_width = GetSize(sigA) + GetSize(sigB);
168 int actual_mul_width = GetSize(sigH);
169 int actual_acc_width = GetSize(sigCD);
170
171 if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
172 reject;
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()))
175 reject;
176
177 sigO = port(addAB, \Y);
178 }
179 endcode
180
181 match muxA
182 select muxA->type.in($mux)
183 index <int> nusers(port(muxA, \A)) === 2
184 index <SigSpec> port(muxA, \A) === sigO
185 optional
186 endmatch
187
188 match muxB
189 if !muxA
190 select muxB->type.in($mux)
191 index <int> nusers(port(muxB, \B)) === 2
192 index <SigSpec> port(muxB, \B) === sigO
193 optional
194 endmatch
195
196 code muxAB sigO
197 if (muxA)
198 muxAB = muxA;
199 else if (muxB)
200 muxAB = muxB;
201 if (muxAB)
202 sigO = port(muxAB, \Y);
203 endcode
204
205 match ffO
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())
210 if nusers(sigO) == 2
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
215 optional
216 endmatch
217
218 match ffO_lo
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)
229 optional
230 endmatch
231
232 code clock clock_pol sigO sigCD cd_signed
233 Cell* ff = nullptr;
234 if (ffO)
235 ff = ffO;
236 else if (ffO_lo)
237 ff = ffO_lo;
238 if (ff) {
239 for (auto b : port(ff, \Q))
240 if (b.wire->get_bool_attribute(\keep))
241 reject;
242
243 SigBit c = port(ff, \CLK).as_bit();
244 bool cp = param(ff, \CLK_POLARITY).as_bool();
245
246 if (clock != SigBit() && (c != clock || cp != clock_pol))
247 reject;
248
249 clock = c;
250 clock_pol = cp;
251
252 sigO.replace(port(ff, \D), port(ff, \Q));
253
254 // Loading value into output register is not
255 // supported unless using accumulator
256 if (muxAB) {
257 if (sigCD != sigO)
258 reject;
259 if (muxA)
260 sigCD = port(muxAB, \B);
261 else if (muxB)
262 sigCD = port(muxAB, \A);
263 else log_abort();
264
265 cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
266 }
267 }
268 sigCD.extend_u0(32, cd_signed);
269 endcode
270
271 code
272 accept;
273 endcode