Add comments
[yosys.git] / passes / opt / opt_rmdff.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 SigMap assign_map, dff_init_map;
30 SigSet<RTLIL::Cell*> mux_drivers;
31 dict<SigBit, pool<SigBit>> init_attributes;
32 bool keepdc;
33
34 void remove_init_attr(SigSpec sig)
35 {
36 for (auto bit : assign_map(sig))
37 if (init_attributes.count(bit))
38 for (auto wbit : init_attributes.at(bit))
39 wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx;
40 }
41
42 bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
43 {
44 SigSpec sig_set, sig_clr;
45 State pol_set, pol_clr;
46
47 if (cell->hasPort("\\S"))
48 sig_set = cell->getPort("\\S");
49
50 if (cell->hasPort("\\R"))
51 sig_clr = cell->getPort("\\R");
52
53 if (cell->hasPort("\\SET"))
54 sig_set = cell->getPort("\\SET");
55
56 if (cell->hasPort("\\CLR"))
57 sig_clr = cell->getPort("\\CLR");
58
59 log_assert(GetSize(sig_set) == GetSize(sig_clr));
60
61 if (cell->type.substr(0,8) == "$_DFFSR_") {
62 pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
63 pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
64 } else
65 if (cell->type.substr(0,11) == "$_DLATCHSR_") {
66 pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
67 pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
68 } else
69 if (cell->type == "$dffsr" || cell->type == "$dlatchsr") {
70 pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0;
71 pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0;
72 } else
73 log_abort();
74
75 State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
76 State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
77
78 SigSpec sig_d = cell->getPort("\\D");
79 SigSpec sig_q = cell->getPort("\\Q");
80
81 bool did_something = false;
82 bool proper_sr = false;
83 bool used_pol_set = false;
84 bool used_pol_clr = false;
85 bool hasreset = false;
86 Const reset_val;
87 SigSpec sig_reset;
88
89 for (int i = 0; i < GetSize(sig_set); i++)
90 {
91 SigBit s = sig_set[i], c = sig_clr[i];
92
93 if (s != npol_set || c != npol_clr)
94 hasreset = true;
95
96 if (s == pol_set || c == pol_clr)
97 {
98 log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
99 s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
100 log_id(cell), log_id(cell->type), log_id(mod));
101
102 remove_init_attr(sig_q[i]);
103 mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
104 sig_set.remove(i);
105 sig_clr.remove(i);
106 sig_d.remove(i);
107 sig_q.remove(i--);
108 did_something = true;
109 continue;
110 }
111 if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
112 if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
113
114 if (s.wire != nullptr && s != sig_reset) proper_sr = true;
115 if (c.wire != nullptr && c != sig_reset) proper_sr = true;
116
117 if ((s.wire == nullptr) != (c.wire == nullptr)) {
118 if (s.wire != nullptr) used_pol_set = true;
119 if (c.wire != nullptr) used_pol_clr = true;
120 reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
121 } else
122 proper_sr = true;
123 }
124
125 if (!hasreset)
126 proper_sr = false;
127
128 if (GetSize(sig_set) == 0)
129 {
130 log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
131 mod->remove(cell);
132 return true;
133 }
134
135 if (cell->type == "$dffsr" || cell->type == "$dlatchsr")
136 {
137 cell->setParam("\\WIDTH", GetSize(sig_d));
138 cell->setPort("\\SET", sig_set);
139 cell->setPort("\\CLR", sig_clr);
140 cell->setPort("\\D", sig_d);
141 cell->setPort("\\Q", sig_q);
142 }
143 else
144 {
145 cell->setPort("\\S", sig_set);
146 cell->setPort("\\R", sig_clr);
147 cell->setPort("\\D", sig_d);
148 cell->setPort("\\Q", sig_q);
149 }
150
151 if (proper_sr)
152 return did_something;
153
154 if (used_pol_set && used_pol_clr && pol_set != pol_clr)
155 return did_something;
156
157 if (cell->type == "$dlatchsr")
158 return did_something;
159
160 State unified_pol = used_pol_set ? pol_set : pol_clr;
161
162 if (cell->type == "$dffsr")
163 {
164 if (hasreset)
165 {
166 log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
167
168 cell->type = "$adff";
169 cell->setParam("\\ARST_POLARITY", unified_pol);
170 cell->setParam("\\ARST_VALUE", reset_val);
171 cell->setPort("\\ARST", sig_reset);
172
173 cell->unsetParam("\\SET_POLARITY");
174 cell->unsetParam("\\CLR_POLARITY");
175 cell->unsetPort("\\SET");
176 cell->unsetPort("\\CLR");
177 }
178 else
179 {
180 log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
181
182 cell->type = "$dff";
183 cell->unsetParam("\\SET_POLARITY");
184 cell->unsetParam("\\CLR_POLARITY");
185 cell->unsetPort("\\SET");
186 cell->unsetPort("\\CLR");
187 }
188
189 return true;
190 }
191
192 if (!hasreset)
193 {
194 IdString new_type;
195
196 if (cell->type.substr(0,8) == "$_DFFSR_")
197 new_type = stringf("$_DFF_%c_", cell->type[8]);
198 else if (cell->type.substr(0,11) == "$_DLATCHSR_")
199 new_type = stringf("$_DLATCH_%c_", cell->type[11]);
200 else
201 log_abort();
202
203 log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
204
205 cell->type = new_type;
206 cell->unsetPort("\\S");
207 cell->unsetPort("\\R");
208
209 return true;
210 }
211
212 return did_something;
213 }
214
215 bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
216 {
217 SigSpec sig_e;
218 State on_state, off_state;
219
220 if (dlatch->type == "$dlatch") {
221 sig_e = assign_map(dlatch->getPort("\\EN"));
222 on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
223 off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
224 } else
225 if (dlatch->type == "$_DLATCH_P_") {
226 sig_e = assign_map(dlatch->getPort("\\E"));
227 on_state = State::S1;
228 off_state = State::S0;
229 } else
230 if (dlatch->type == "$_DLATCH_N_") {
231 sig_e = assign_map(dlatch->getPort("\\E"));
232 on_state = State::S0;
233 off_state = State::S1;
234 } else
235 log_abort();
236
237 if (sig_e == off_state)
238 {
239 RTLIL::Const val_init;
240 for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
241 val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx);
242 mod->connect(dlatch->getPort("\\Q"), val_init);
243 goto delete_dlatch;
244 }
245
246 if (sig_e == on_state)
247 {
248 mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
249 goto delete_dlatch;
250 }
251
252 return false;
253
254 delete_dlatch:
255 log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
256 remove_init_attr(dlatch->getPort("\\Q"));
257 mod->remove(dlatch);
258 return true;
259 }
260
261 bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
262 {
263 RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
264 RTLIL::Const val_cp, val_rp, val_rv, val_ep;
265
266 if (dff->type == "$_FF_") {
267 sig_d = dff->getPort("\\D");
268 sig_q = dff->getPort("\\Q");
269 }
270 else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
271 sig_d = dff->getPort("\\D");
272 sig_q = dff->getPort("\\Q");
273 sig_c = dff->getPort("\\C");
274 val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
275 }
276 else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
277 (dff->type[6] == 'N' || dff->type[6] == 'P') &&
278 (dff->type[7] == 'N' || dff->type[7] == 'P') &&
279 (dff->type[8] == '0' || dff->type[8] == '1')) {
280 sig_d = dff->getPort("\\D");
281 sig_q = dff->getPort("\\Q");
282 sig_c = dff->getPort("\\C");
283 sig_r = dff->getPort("\\R");
284 val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
285 val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
286 val_rv = RTLIL::Const(dff->type[8] == '1', 1);
287 }
288 else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
289 (dff->type[7] == 'N' || dff->type[7] == 'P') &&
290 (dff->type[8] == 'N' || dff->type[8] == 'P')) {
291 sig_d = dff->getPort("\\D");
292 sig_q = dff->getPort("\\Q");
293 sig_c = dff->getPort("\\C");
294 sig_e = dff->getPort("\\E");
295 val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
296 val_ep = RTLIL::Const(dff->type[7] == 'P', 1);
297 }
298 else if (dff->type == "$ff") {
299 sig_d = dff->getPort("\\D");
300 sig_q = dff->getPort("\\Q");
301 }
302 else if (dff->type == "$dff") {
303 sig_d = dff->getPort("\\D");
304 sig_q = dff->getPort("\\Q");
305 sig_c = dff->getPort("\\CLK");
306 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
307 }
308 else if (dff->type == "$dffe") {
309 sig_e = dff->getPort("\\EN");
310 sig_d = dff->getPort("\\D");
311 sig_q = dff->getPort("\\Q");
312 sig_c = dff->getPort("\\CLK");
313 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
314 val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
315 }
316 else if (dff->type == "$adff") {
317 sig_d = dff->getPort("\\D");
318 sig_q = dff->getPort("\\Q");
319 sig_c = dff->getPort("\\CLK");
320 sig_r = dff->getPort("\\ARST");
321 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
322 val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
323 val_rv = dff->parameters["\\ARST_VALUE"];
324 }
325 else
326 log_abort();
327
328 assign_map.apply(sig_d);
329 assign_map.apply(sig_q);
330 assign_map.apply(sig_c);
331 assign_map.apply(sig_r);
332
333 bool has_init = false;
334 RTLIL::Const val_init;
335 for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
336 if (bit.wire == NULL || keepdc)
337 has_init = true;
338 val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
339 }
340
341 if (sig_e.size()) {
342 if (!sig_e.is_fully_const())
343 return false;
344 if (sig_e != val_ep) {
345 mod->connect(sig_q, val_init);
346 goto delete_dff;
347 }
348 }
349
350 if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
351 std::set<RTLIL::Cell*> muxes;
352 mux_drivers.find(sig_d, muxes);
353 for (auto mux : muxes) {
354 RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
355 RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
356 if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
357 mod->connect(sig_q, sig_b);
358 goto delete_dff;
359 }
360 if (sig_b == sig_q && sig_a.is_fully_const() && (!has_init || val_init == sig_a.as_const())) {
361 mod->connect(sig_q, sig_a);
362 goto delete_dff;
363 }
364 }
365 }
366
367 // If clock is driven by a constant and (i) no reset signal
368 // (ii) Q has no initial value
369 // (iii) initial value is same as reset value
370 if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
371 if (val_rv.bits.size() == 0)
372 val_rv = val_init;
373 // Q is permanently reset value or initial value
374 mod->connect(sig_q, val_rv);
375 goto delete_dff;
376 }
377
378 // If D is fully undefined and reset signal present and (i) Q has no initial value
379 // (ii) initial value is same as reset value
380 if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
381 // Q is permanently reset value
382 mod->connect(sig_q, val_rv);
383 goto delete_dff;
384 }
385
386 // If D is fully undefined and no reset signal and Q has an initial value
387 if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
388 // Q is permanently initial value
389 mod->connect(sig_q, val_init);
390 goto delete_dff;
391 }
392
393 // If D is fully constant and (i) no reset signal
394 // (ii) reset value is same as constant D
395 // and (a) has initial value
396 // (b) initial value same as constant D
397 if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
398 // Q is permanently D
399 mod->connect(sig_q, sig_d);
400 goto delete_dff;
401 }
402
403 // If D input is same as Q output and (i) no reset signal
404 // (ii) no initial signal
405 // (iii) initial value is same as reset value
406 if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
407 // Q is permanently reset value or initial value
408 if (sig_r.size())
409 mod->connect(sig_q, val_rv);
410 else if (has_init)
411 mod->connect(sig_q, val_init);
412 goto delete_dff;
413 }
414
415 // If reset signal is present, and is fully constant
416 if (!sig_r.empty() && sig_r.is_fully_const())
417 {
418 // If reset value is permanently enable or if reset is undefined
419 if (sig_r == val_rp || sig_r.is_fully_undef()) {
420 // Q is permanently reset value
421 mod->connect(sig_q, val_rv);
422 goto delete_dff;
423 }
424
425 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
426
427 if (dff->type == "$adff") {
428 dff->type = "$dff";
429 dff->unsetPort("\\ARST");
430 dff->unsetParam("\\ARST_POLARITY");
431 dff->unsetParam("\\ARST_VALUE");
432 return true;
433 }
434
435 log_assert(dff->type.substr(0,6) == "$_DFF_");
436 dff->type = stringf("$_DFF_%c_", + dff->type[6]);
437 dff->unsetPort("\\R");
438 }
439
440 return false;
441
442 delete_dff:
443 log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
444 remove_init_attr(dff->getPort("\\Q"));
445 mod->remove(dff);
446 return true;
447 }
448
449 struct OptRmdffPass : public Pass {
450 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
451 void help() YS_OVERRIDE
452 {
453 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
454 log("\n");
455 log(" opt_rmdff [-keepdc] [selection]\n");
456 log("\n");
457 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
458 log("a constant driver.\n");
459 log("\n");
460 }
461 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
462 {
463 int total_count = 0, total_initdrv = 0;
464 log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
465
466 keepdc = false;
467
468 size_t argidx;
469 for (argidx = 1; argidx < args.size(); argidx++) {
470 if (args[argidx] == "-keepdc") {
471 keepdc = true;
472 continue;
473 }
474 break;
475 }
476 extra_args(args, argidx, design);
477
478 for (auto module : design->selected_modules())
479 {
480 pool<SigBit> driven_bits;
481 dict<SigBit, State> init_bits;
482
483 assign_map.set(module);
484 dff_init_map.set(module);
485 mux_drivers.clear();
486 init_attributes.clear();
487
488 for (auto wire : module->wires())
489 {
490 if (wire->attributes.count("\\init") != 0) {
491 Const initval = wire->attributes.at("\\init");
492 for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
493 if (initval[i] == State::S0 || initval[i] == State::S1)
494 dff_init_map.add(SigBit(wire, i), initval[i]);
495 for (int i = 0; i < GetSize(wire); i++) {
496 SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
497 if (mapped_bit.wire) {
498 init_attributes[mapped_bit].insert(wire_bit);
499 if (i < GetSize(initval))
500 init_bits[mapped_bit] = initval[i];
501 }
502 }
503 }
504
505 if (wire->port_input) {
506 for (auto bit : assign_map(wire))
507 driven_bits.insert(bit);
508 }
509 }
510 mux_drivers.clear();
511
512 std::vector<RTLIL::IdString> dff_list;
513 std::vector<RTLIL::IdString> dffsr_list;
514 std::vector<RTLIL::IdString> dlatch_list;
515 for (auto cell : module->cells())
516 {
517 for (auto &conn : cell->connections())
518 if (cell->output(conn.first) || !cell->known())
519 for (auto bit : assign_map(conn.second))
520 driven_bits.insert(bit);
521
522 if (cell->type == "$mux" || cell->type == "$pmux") {
523 if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
524 mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
525 continue;
526 }
527
528 if (!design->selected(module, cell))
529 continue;
530
531 if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
532 "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
533 "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
534 "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
535 dffsr_list.push_back(cell->name);
536
537 if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
538 "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
539 "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
540 "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
541 "$ff", "$dff", "$dffe", "$adff"))
542 dff_list.push_back(cell->name);
543
544 if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
545 dlatch_list.push_back(cell->name);
546 }
547
548 for (auto &id : dffsr_list) {
549 if (module->cell(id) != nullptr &&
550 handle_dffsr(module, module->cells_[id]))
551 total_count++;
552 }
553
554 for (auto &id : dff_list) {
555 if (module->cell(id) != nullptr &&
556 handle_dff(module, module->cells_[id]))
557 total_count++;
558 }
559
560 for (auto &id : dlatch_list) {
561 if (module->cell(id) != nullptr &&
562 handle_dlatch(module, module->cells_[id]))
563 total_count++;
564 }
565
566 SigSpec const_init_sigs;
567
568 for (auto bit : init_bits)
569 if (!driven_bits.count(bit.first))
570 const_init_sigs.append(bit.first);
571
572 const_init_sigs.sort_and_unify();
573
574 for (SigSpec sig : const_init_sigs.chunks())
575 {
576 Const val;
577
578 for (auto bit : sig)
579 val.bits.push_back(init_bits.at(bit));
580
581 log("Promoting init spec %s = %s to constant driver in module %s.\n",
582 log_signal(sig), log_signal(val), log_id(module));
583
584 module->connect(sig, val);
585 remove_init_attr(sig);
586 total_initdrv++;
587 }
588 }
589
590 assign_map.clear();
591 mux_drivers.clear();
592 init_attributes.clear();
593
594 if (total_count || total_initdrv)
595 design->scratchpad_set_bool("opt.did_something", true);
596
597 if (total_initdrv)
598 log("Promoted %d init specs to constant drivers.\n", total_initdrv);
599
600 if (total_count)
601 log("Replaced %d DFF cells.\n", total_count);
602 }
603 } OptRmdffPass;
604
605 PRIVATE_NAMESPACE_END