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