async2sync: Support all FF types.
[yosys.git] / kernel / ff.h
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2020 Marcelina Koƛcielnicka <mwk@0x04.net>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #ifndef FF_H
21 #define FF_H
22
23 #include "kernel/yosys.h"
24 #include "kernel/ffinit.h"
25
26 YOSYS_NAMESPACE_BEGIN
27
28 struct FfData {
29 FfInitVals *initvals;
30 SigSpec sig_q;
31 SigSpec sig_d;
32 SigSpec sig_clk;
33 SigSpec sig_en;
34 SigSpec sig_arst;
35 SigSpec sig_srst;
36 SigSpec sig_clr;
37 SigSpec sig_set;
38 bool has_d;
39 bool has_clk;
40 bool has_en;
41 bool has_srst;
42 bool has_arst;
43 bool has_sr;
44 bool ce_over_srst;
45 bool is_fine;
46 bool pol_clk;
47 bool pol_en;
48 bool pol_arst;
49 bool pol_srst;
50 bool pol_clr;
51 bool pol_set;
52 Const val_arst;
53 Const val_srst;
54 Const val_init;
55 Const val_d;
56 bool d_is_const;
57 int width;
58 dict<IdString, Const> attributes;
59
60 FfData(FfInitVals *initvals, Cell *cell = nullptr) : initvals(initvals) {
61 width = 0;
62 has_d = true;
63 has_clk = false;
64 has_en = false;
65 has_srst = false;
66 has_arst = false;
67 has_sr = false;
68 ce_over_srst = false;
69 is_fine = false;
70 pol_clk = false;
71 pol_en = false;
72 pol_arst = false;
73 pol_srst = false;
74 pol_clr = false;
75 pol_set = false;
76 d_is_const = false;
77
78 if (!cell)
79 return;
80
81 sig_q = cell->getPort(ID::Q);
82 width = GetSize(sig_q);
83 attributes = cell->attributes;
84
85 if (initvals)
86 val_init = (*initvals)(sig_q);
87
88 std::string type_str = cell->type.str();
89
90 if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
91 if (cell->type == ID($sr)) {
92 has_d = false;
93 } else {
94 sig_d = cell->getPort(ID::D);
95 }
96 if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
97 has_clk = true;
98 sig_clk = cell->getPort(ID::CLK);
99 pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
100 }
101 if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
102 has_en = true;
103 sig_en = cell->getPort(ID::EN);
104 pol_en = cell->getParam(ID::EN_POLARITY).as_bool();
105 }
106 if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
107 has_sr = true;
108 sig_clr = cell->getPort(ID::CLR);
109 sig_set = cell->getPort(ID::SET);
110 pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
111 pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
112 }
113 if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
114 has_arst = true;
115 sig_arst = cell->getPort(ID::ARST);
116 pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
117 val_arst = cell->getParam(ID::ARST_VALUE);
118 }
119 if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
120 has_srst = true;
121 sig_srst = cell->getPort(ID::SRST);
122 pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
123 val_srst = cell->getParam(ID::SRST_VALUE);
124 ce_over_srst = cell->type == ID($sdffce);
125 }
126 } else if (cell->type == ID($_FF_)) {
127 is_fine = true;
128 sig_d = cell->getPort(ID::D);
129 } else if (type_str.substr(0, 5) == "$_SR_") {
130 is_fine = true;
131 has_d = false;
132 has_sr = true;
133 pol_set = type_str[5] == 'P';
134 pol_clr = type_str[6] == 'P';
135 sig_set = cell->getPort(ID::S);
136 sig_clr = cell->getPort(ID::R);
137 } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
138 is_fine = true;
139 sig_d = cell->getPort(ID::D);
140 has_clk = true;
141 pol_clk = type_str[6] == 'P';
142 sig_clk = cell->getPort(ID::C);
143 } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
144 is_fine = true;
145 sig_d = cell->getPort(ID::D);
146 has_clk = true;
147 pol_clk = type_str[7] == 'P';
148 sig_clk = cell->getPort(ID::C);
149 has_en = true;
150 pol_en = type_str[8] == 'P';
151 sig_en = cell->getPort(ID::E);
152 } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
153 is_fine = true;
154 sig_d = cell->getPort(ID::D);
155 has_clk = true;
156 pol_clk = type_str[6] == 'P';
157 sig_clk = cell->getPort(ID::C);
158 has_arst = true;
159 pol_arst = type_str[7] == 'P';
160 sig_arst = cell->getPort(ID::R);
161 val_arst = type_str[8] == '1' ? State::S1 : State::S0;
162 } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
163 is_fine = true;
164 sig_d = cell->getPort(ID::D);
165 has_clk = true;
166 pol_clk = type_str[7] == 'P';
167 sig_clk = cell->getPort(ID::C);
168 has_arst = true;
169 pol_arst = type_str[8] == 'P';
170 sig_arst = cell->getPort(ID::R);
171 val_arst = type_str[9] == '1' ? State::S1 : State::S0;
172 has_en = true;
173 pol_en = type_str[10] == 'P';
174 sig_en = cell->getPort(ID::E);
175 } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
176 is_fine = true;
177 sig_d = cell->getPort(ID::D);
178 has_clk = true;
179 pol_clk = type_str[8] == 'P';
180 sig_clk = cell->getPort(ID::C);
181 has_sr = true;
182 pol_set = type_str[9] == 'P';
183 pol_clr = type_str[10] == 'P';
184 sig_set = cell->getPort(ID::S);
185 sig_clr = cell->getPort(ID::R);
186 } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
187 is_fine = true;
188 sig_d = cell->getPort(ID::D);
189 has_clk = true;
190 pol_clk = type_str[9] == 'P';
191 sig_clk = cell->getPort(ID::C);
192 has_sr = true;
193 pol_set = type_str[10] == 'P';
194 pol_clr = type_str[11] == 'P';
195 sig_set = cell->getPort(ID::S);
196 sig_clr = cell->getPort(ID::R);
197 has_en = true;
198 pol_en = type_str[12] == 'P';
199 sig_en = cell->getPort(ID::E);
200 } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
201 is_fine = true;
202 sig_d = cell->getPort(ID::D);
203 has_clk = true;
204 pol_clk = type_str[7] == 'P';
205 sig_clk = cell->getPort(ID::C);
206 has_srst = true;
207 pol_srst = type_str[8] == 'P';
208 sig_srst = cell->getPort(ID::R);
209 val_srst = type_str[9] == '1' ? State::S1 : State::S0;
210 } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
211 is_fine = true;
212 sig_d = cell->getPort(ID::D);
213 has_clk = true;
214 pol_clk = type_str[8] == 'P';
215 sig_clk = cell->getPort(ID::C);
216 has_srst = true;
217 pol_srst = type_str[9] == 'P';
218 sig_srst = cell->getPort(ID::R);
219 val_srst = type_str[10] == '1' ? State::S1 : State::S0;
220 has_en = true;
221 pol_en = type_str[11] == 'P';
222 sig_en = cell->getPort(ID::E);
223 } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
224 is_fine = true;
225 sig_d = cell->getPort(ID::D);
226 has_clk = true;
227 pol_clk = type_str[9] == 'P';
228 sig_clk = cell->getPort(ID::C);
229 has_srst = true;
230 pol_srst = type_str[10] == 'P';
231 sig_srst = cell->getPort(ID::R);
232 val_srst = type_str[11] == '1' ? State::S1 : State::S0;
233 has_en = true;
234 pol_en = type_str[12] == 'P';
235 sig_en = cell->getPort(ID::E);
236 ce_over_srst = true;
237 } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
238 is_fine = true;
239 sig_d = cell->getPort(ID::D);
240 has_en = true;
241 pol_en = type_str[9] == 'P';
242 sig_en = cell->getPort(ID::E);
243 } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
244 is_fine = true;
245 sig_d = cell->getPort(ID::D);
246 has_en = true;
247 pol_en = type_str[9] == 'P';
248 sig_en = cell->getPort(ID::E);
249 has_arst = true;
250 pol_arst = type_str[10] == 'P';
251 sig_arst = cell->getPort(ID::R);
252 val_arst = type_str[11] == '1' ? State::S1 : State::S0;
253 } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
254 is_fine = true;
255 sig_d = cell->getPort(ID::D);
256 has_en = true;
257 pol_en = type_str[11] == 'P';
258 sig_en = cell->getPort(ID::E);
259 has_sr = true;
260 pol_set = type_str[12] == 'P';
261 pol_clr = type_str[13] == 'P';
262 sig_set = cell->getPort(ID::S);
263 sig_clr = cell->getPort(ID::R);
264 } else {
265 log_assert(0);
266 }
267 if (has_d && sig_d.is_fully_const()) {
268 d_is_const = true;
269 val_d = sig_d.as_const();
270 if (has_en && !has_clk && !has_sr && !has_arst) {
271 // Plain D latches with const D treated specially.
272 has_en = has_d = false;
273 has_arst = true;
274 sig_arst = sig_en;
275 pol_arst = pol_en;
276 val_arst = val_d;
277 }
278 }
279 }
280
281 // Returns a FF identical to this one, but only keeping bit indices from the argument.
282 FfData slice(const std::vector<int> &bits) {
283 FfData res(initvals);
284 res.sig_clk = sig_clk;
285 res.sig_en = sig_en;
286 res.sig_arst = sig_arst;
287 res.sig_srst = sig_srst;
288 res.has_d = has_d;
289 res.has_clk = has_clk;
290 res.has_en = has_en;
291 res.has_arst = has_arst;
292 res.has_srst = has_srst;
293 res.has_sr = has_sr;
294 res.ce_over_srst = ce_over_srst;
295 res.is_fine = is_fine;
296 res.pol_clk = pol_clk;
297 res.pol_en = pol_en;
298 res.pol_arst = pol_arst;
299 res.pol_srst = pol_srst;
300 res.pol_clr = pol_clr;
301 res.pol_set = pol_set;
302 res.attributes = attributes;
303 for (int i : bits) {
304 res.sig_q.append(sig_q[i]);
305 if (has_d)
306 res.sig_d.append(sig_d[i]);
307 if (has_sr) {
308 res.sig_clr.append(sig_clr[i]);
309 res.sig_set.append(sig_set[i]);
310 }
311 if (has_arst)
312 res.val_arst.bits.push_back(val_arst[i]);
313 if (has_srst)
314 res.val_srst.bits.push_back(val_srst[i]);
315 res.val_init.bits.push_back(val_init[i]);
316 }
317 res.width = GetSize(res.sig_q);
318 // Slicing bits out may cause D to become const.
319 if (has_d && res.sig_d.is_fully_const()) {
320 res.d_is_const = true;
321 res.val_d = res.sig_d.as_const();
322 }
323 return res;
324 }
325
326 void unmap_ce(Module *module) {
327 if (!has_en)
328 return;
329 log_assert(has_clk);
330 if (has_srst && ce_over_srst)
331 unmap_srst(module);
332
333 if (!is_fine) {
334 if (pol_en)
335 sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
336 else
337 sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
338 } else {
339 if (pol_en)
340 sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
341 else
342 sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
343 }
344 has_en = false;
345 }
346
347 void unmap_srst(Module *module) {
348 if (!has_srst)
349 return;
350 if (has_en && !ce_over_srst)
351 unmap_ce(module);
352
353 if (!is_fine) {
354 if (pol_srst)
355 sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
356 else
357 sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
358 } else {
359 if (pol_srst)
360 sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
361 else
362 sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
363 }
364 has_srst = false;
365 }
366
367 void unmap_ce_srst(Module *module) {
368 unmap_ce(module);
369 unmap_srst(module);
370 }
371
372 Cell *emit(Module *module, IdString name) {
373 if (!width)
374 return nullptr;
375 if (!has_d && !has_sr) {
376 if (has_arst) {
377 // Convert this case to a D latch.
378 has_d = has_en = true;
379 has_arst = false;
380 sig_d = val_arst;
381 sig_en = sig_arst;
382 pol_en = pol_arst;
383 } else {
384 // No control inputs left. Turn into a const driver.
385 initvals->remove_init(sig_q);
386 module->connect(sig_q, val_init);
387 return nullptr;
388 }
389 }
390 initvals->set_init(sig_q, val_init);
391 Cell *cell;
392 if (!is_fine) {
393 if (!has_d) {
394 log_assert(has_sr);
395 cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
396 } else if (!has_clk && !has_en) {
397 log_assert(!has_arst);
398 log_assert(!has_srst);
399 log_assert(!has_sr);
400 cell = module->addFf(name, sig_d, sig_q);
401 } else if (!has_clk) {
402 log_assert(!has_srst);
403 if (has_sr)
404 cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
405 else if (has_arst)
406 cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
407 else
408 cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
409 } else {
410 if (has_sr) {
411 if (has_en)
412 cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
413 else
414 cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
415 } else if (has_arst) {
416 if (has_en)
417 cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
418 else
419 cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
420 } else if (has_srst) {
421 if (has_en)
422 if (ce_over_srst)
423 cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
424 else
425 cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
426 else
427 cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
428 } else {
429 if (has_en)
430 cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
431 else
432 cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
433 }
434 }
435 } else {
436 if (!has_d) {
437 log_assert(has_sr);
438 cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
439 } else if (!has_clk && !has_en) {
440 log_assert(!has_arst);
441 log_assert(!has_srst);
442 log_assert(!has_sr);
443 cell = module->addFfGate(name, sig_d, sig_q);
444 } else if (!has_clk) {
445 log_assert(!has_srst);
446 if (has_sr)
447 cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
448 else if (has_arst)
449 cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
450 else
451 cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
452 } else {
453 if (has_sr) {
454 if (has_en)
455 cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
456 else
457 cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
458 } else if (has_arst) {
459 if (has_en)
460 cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, pol_arst);
461 else
462 cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
463 } else if (has_srst) {
464 if (has_en)
465 if (ce_over_srst)
466 cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
467 else
468 cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
469 else
470 cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
471 } else {
472 if (has_en)
473 cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
474 else
475 cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
476 }
477 }
478 }
479 cell->attributes = attributes;
480 return cell;
481 }
482 };
483
484 YOSYS_NAMESPACE_END
485
486 #endif