Merge pull request #1031 from mdaiter/optimizeLookupTableBtor
[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;
264 RTLIL::Const val_cp, val_rp, val_rv;
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 == "$ff") {
289 sig_d = dff->getPort("\\D");
290 sig_q = dff->getPort("\\Q");
291 }
292 else if (dff->type == "$dff") {
293 sig_d = dff->getPort("\\D");
294 sig_q = dff->getPort("\\Q");
295 sig_c = dff->getPort("\\CLK");
296 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
297 }
298 else if (dff->type == "$adff") {
299 sig_d = dff->getPort("\\D");
300 sig_q = dff->getPort("\\Q");
301 sig_c = dff->getPort("\\CLK");
302 sig_r = dff->getPort("\\ARST");
303 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
304 val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
305 val_rv = dff->parameters["\\ARST_VALUE"];
306 }
307 else
308 log_abort();
309
310 assign_map.apply(sig_d);
311 assign_map.apply(sig_q);
312 assign_map.apply(sig_c);
313 assign_map.apply(sig_r);
314
315 bool has_init = false;
316 RTLIL::Const val_init;
317 for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
318 if (bit.wire == NULL || keepdc)
319 has_init = true;
320 val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
321 }
322
323 if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
324 std::set<RTLIL::Cell*> muxes;
325 mux_drivers.find(sig_d, muxes);
326 for (auto mux : muxes) {
327 RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
328 RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
329 if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
330 mod->connect(sig_q, sig_b);
331 goto delete_dff;
332 }
333 if (sig_b == sig_q && sig_a.is_fully_const() && (!has_init || val_init == sig_a.as_const())) {
334 mod->connect(sig_q, sig_a);
335 goto delete_dff;
336 }
337 }
338 }
339
340 if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
341 if (val_rv.bits.size() == 0)
342 val_rv = val_init;
343 mod->connect(sig_q, val_rv);
344 goto delete_dff;
345 }
346
347 if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
348 mod->connect(sig_q, val_rv);
349 goto delete_dff;
350 }
351
352 if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
353 mod->connect(sig_q, val_init);
354 goto delete_dff;
355 }
356
357 if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
358 mod->connect(sig_q, sig_d);
359 goto delete_dff;
360 }
361
362 if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
363 if (sig_r.size())
364 mod->connect(sig_q, val_rv);
365 if (has_init)
366 mod->connect(sig_q, val_init);
367 goto delete_dff;
368 }
369
370 if (!sig_r.empty() && sig_r.is_fully_const())
371 {
372 if (sig_r == val_rp || sig_r.is_fully_undef()) {
373 mod->connect(sig_q, val_rv);
374 goto delete_dff;
375 }
376
377 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
378
379 if (dff->type == "$adff") {
380 dff->type = "$dff";
381 dff->unsetPort("\\ARST");
382 dff->unsetParam("\\ARST_POLARITY");
383 dff->unsetParam("\\ARST_VALUE");
384 return true;
385 }
386
387 log_assert(dff->type.substr(0,6) == "$_DFF_");
388 dff->type = stringf("$_DFF_%c_", + dff->type[6]);
389 dff->unsetPort("\\R");
390 }
391
392 return false;
393
394 delete_dff:
395 log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
396 remove_init_attr(dff->getPort("\\Q"));
397 mod->remove(dff);
398 return true;
399 }
400
401 struct OptRmdffPass : public Pass {
402 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
403 void help() YS_OVERRIDE
404 {
405 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
406 log("\n");
407 log(" opt_rmdff [-keepdc] [selection]\n");
408 log("\n");
409 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
410 log("a constant driver.\n");
411 log("\n");
412 }
413 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
414 {
415 int total_count = 0, total_initdrv = 0;
416 log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
417
418 keepdc = false;
419
420 size_t argidx;
421 for (argidx = 1; argidx < args.size(); argidx++) {
422 if (args[argidx] == "-keepdc") {
423 keepdc = true;
424 continue;
425 }
426 break;
427 }
428 extra_args(args, argidx, design);
429
430 for (auto module : design->selected_modules())
431 {
432 pool<SigBit> driven_bits;
433 dict<SigBit, State> init_bits;
434
435 assign_map.set(module);
436 dff_init_map.set(module);
437 mux_drivers.clear();
438 init_attributes.clear();
439
440 for (auto wire : module->wires())
441 {
442 if (wire->attributes.count("\\init") != 0) {
443 Const initval = wire->attributes.at("\\init");
444 for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
445 if (initval[i] == State::S0 || initval[i] == State::S1)
446 dff_init_map.add(SigBit(wire, i), initval[i]);
447 for (int i = 0; i < GetSize(wire); i++) {
448 SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
449 if (mapped_bit.wire) {
450 init_attributes[mapped_bit].insert(wire_bit);
451 if (i < GetSize(initval))
452 init_bits[mapped_bit] = initval[i];
453 }
454 }
455 }
456
457 if (wire->port_input) {
458 for (auto bit : assign_map(wire))
459 driven_bits.insert(bit);
460 }
461 }
462 mux_drivers.clear();
463
464 std::vector<RTLIL::IdString> dff_list;
465 std::vector<RTLIL::IdString> dffsr_list;
466 std::vector<RTLIL::IdString> dlatch_list;
467 for (auto cell : module->cells())
468 {
469 for (auto &conn : cell->connections())
470 if (cell->output(conn.first) || !cell->known())
471 for (auto bit : assign_map(conn.second))
472 driven_bits.insert(bit);
473
474 if (cell->type == "$mux" || cell->type == "$pmux") {
475 if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
476 mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
477 continue;
478 }
479
480 if (!design->selected(module, cell))
481 continue;
482
483 if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
484 "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
485 "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
486 "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
487 dffsr_list.push_back(cell->name);
488
489 if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
490 "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
491 "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
492 "$ff", "$dff", "$adff"))
493 dff_list.push_back(cell->name);
494
495 if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
496 dlatch_list.push_back(cell->name);
497 }
498
499 for (auto &id : dffsr_list) {
500 if (module->cell(id) != nullptr &&
501 handle_dffsr(module, module->cells_[id]))
502 total_count++;
503 }
504
505 for (auto &id : dff_list) {
506 if (module->cell(id) != nullptr &&
507 handle_dff(module, module->cells_[id]))
508 total_count++;
509 }
510
511 for (auto &id : dlatch_list) {
512 if (module->cell(id) != nullptr &&
513 handle_dlatch(module, module->cells_[id]))
514 total_count++;
515 }
516
517 SigSpec const_init_sigs;
518
519 for (auto bit : init_bits)
520 if (!driven_bits.count(bit.first))
521 const_init_sigs.append(bit.first);
522
523 const_init_sigs.sort_and_unify();
524
525 for (SigSpec sig : const_init_sigs.chunks())
526 {
527 Const val;
528
529 for (auto bit : sig)
530 val.bits.push_back(init_bits.at(bit));
531
532 log("Promoting init spec %s = %s to constant driver in module %s.\n",
533 log_signal(sig), log_signal(val), log_id(module));
534
535 module->connect(sig, val);
536 remove_init_attr(sig);
537 total_initdrv++;
538 }
539 }
540
541 assign_map.clear();
542 mux_drivers.clear();
543 init_attributes.clear();
544
545 if (total_count || total_initdrv)
546 design->scratchpad_set_bool("opt.did_something", true);
547
548 if (total_initdrv)
549 log("Promoted %d init specs to constant drivers.\n", total_initdrv);
550
551 if (total_count)
552 log("Replaced %d DFF cells.\n", total_count);
553 }
554 } OptRmdffPass;
555
556 PRIVATE_NAMESPACE_END