Merge remote-tracking branch 'origin/eddie/peepopt_dffmuxext' into xc7dsp
[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 <SigSpec> sigA sigB sigCD sigH sigO
6 state <Cell*> addAB muxAB
7
8 match mul
9 select mul->type.in($mul, \SB_MAC16)
10 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
11 endmatch
12
13 code sigA sigB sigH
14 SigSpec O;
15 if (mul->type == $mul)
16 O = mul->getPort(\Y);
17 else if (mul->type == \SB_MAC16)
18 O = mul->getPort(\O);
19 else log_abort();
20 if (GetSize(O) <= 10)
21 reject;
22
23 sigA = port(mul, \A);
24 int i;
25 for (i = GetSize(sigA)-1; i > 0; i--)
26 if (sigA[i] != sigA[i-1])
27 break;
28 // Do not remove non-const sign bit
29 if (sigA[i].wire)
30 ++i;
31 sigA.remove(i, GetSize(sigA)-i);
32 sigB = port(mul, \B);
33 for (i = GetSize(sigB)-1; i > 0; i--)
34 if (sigB[i] != sigB[i-1])
35 break;
36 // Do not remove non-const sign bit
37 if (sigB[i].wire)
38 ++i;
39 sigB.remove(i, GetSize(sigB)-i);
40
41 // Only care about those bits that are used
42 for (i = 0; i < GetSize(O); i++) {
43 if (nusers(O[i]) <= 1)
44 break;
45 sigH.append(O[i]);
46 }
47 log_assert(nusers(O.extract_end(i)) <= 1);
48 endcode
49
50 match ffA
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
56 optional
57 endmatch
58
59 code sigA clock clock_pol
60 if (ffA) {
61 for (auto b : port(ffA, \Q))
62 if (b.wire->get_bool_attribute(\keep))
63 reject;
64
65 clock = port(ffA, \CLK).as_bit();
66 clock_pol = param(ffA, \CLK_POLARITY).as_bool();
67
68 sigA.replace(port(ffA, \Q), port(ffA, \D));
69 }
70 endcode
71
72 match ffB
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
78 optional
79 endmatch
80
81 code sigB clock clock_pol
82 if (ffB) {
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 ffO clock clock_pol sigO sigCD cd_signed
233 if (ffO_lo) {
234 log_assert(!ffO);
235 ffO = ffO_lo;
236 }
237 if (ffO) {
238 for (auto b : port(ffO, \Q))
239 if (b.wire->get_bool_attribute(\keep))
240 reject;
241
242 SigBit c = port(ffO, \CLK).as_bit();
243 bool cp = param(ffO, \CLK_POLARITY).as_bool();
244
245 if (clock != SigBit() && (c != clock || cp != clock_pol))
246 reject;
247
248 clock = c;
249 clock_pol = cp;
250
251 sigO.replace(port(ffO, \D), port(ffO, \Q));
252
253 // Loading value into output register is not
254 // supported unless using accumulator
255 if (muxAB) {
256 if (sigCD != sigO)
257 reject;
258 if (muxA)
259 sigCD = port(muxAB, \B);
260 else if (muxB)
261 sigCD = port(muxAB, \A);
262 else log_abort();
263
264 cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
265 }
266 }
267 sigCD.extend_u0(32, cd_signed);
268 endcode
269
270 code
271 accept;
272 endcode