flowmap: new techmap pass.
[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 return true;
179 }
180 else
181 {
182 log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
183
184 cell->type = "$dff";
185 cell->unsetParam("\\SET_POLARITY");
186 cell->unsetParam("\\CLR_POLARITY");
187 cell->unsetPort("\\SET");
188 cell->unsetPort("\\CLR");
189
190 return true;
191 }
192 }
193 else
194 {
195 IdString new_type;
196
197 if (cell->type.substr(0,8) == "$_DFFSR_")
198 new_type = stringf("$_DFF_%c_", cell->type[8]);
199 else if (cell->type.substr(0,11) == "$_DLATCHSR_")
200 new_type = stringf("$_DLATCH_%c_", cell->type[11]);
201 else
202 log_abort();
203
204 log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
205
206 cell->type = new_type;
207 cell->unsetPort("\\S");
208 cell->unsetPort("\\R");
209
210 return did_something;
211 }
212 }
213
214 bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
215 {
216 SigSpec sig_e;
217 State on_state, off_state;
218
219 if (dlatch->type == "$dlatch") {
220 sig_e = assign_map(dlatch->getPort("\\EN"));
221 on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
222 off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
223 } else
224 if (dlatch->type == "$_DLATCH_P_") {
225 sig_e = assign_map(dlatch->getPort("\\E"));
226 on_state = State::S1;
227 off_state = State::S0;
228 } else
229 if (dlatch->type == "$_DLATCH_N_") {
230 sig_e = assign_map(dlatch->getPort("\\E"));
231 on_state = State::S0;
232 off_state = State::S1;
233 } else
234 log_abort();
235
236 if (sig_e == off_state)
237 {
238 RTLIL::Const val_init;
239 for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
240 val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx);
241 mod->connect(dlatch->getPort("\\Q"), val_init);
242 goto delete_dlatch;
243 }
244
245 if (sig_e == on_state)
246 {
247 mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
248 goto delete_dlatch;
249 }
250
251 return false;
252
253 delete_dlatch:
254 log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
255 remove_init_attr(dlatch->getPort("\\Q"));
256 mod->remove(dlatch);
257 return true;
258 }
259
260 bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
261 {
262 RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
263 RTLIL::Const val_cp, val_rp, val_rv;
264
265 if (dff->type == "$_FF_") {
266 sig_d = dff->getPort("\\D");
267 sig_q = dff->getPort("\\Q");
268 }
269 else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
270 sig_d = dff->getPort("\\D");
271 sig_q = dff->getPort("\\Q");
272 sig_c = dff->getPort("\\C");
273 val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
274 }
275 else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
276 (dff->type[6] == 'N' || dff->type[6] == 'P') &&
277 (dff->type[7] == 'N' || dff->type[7] == 'P') &&
278 (dff->type[8] == '0' || dff->type[8] == '1')) {
279 sig_d = dff->getPort("\\D");
280 sig_q = dff->getPort("\\Q");
281 sig_c = dff->getPort("\\C");
282 sig_r = dff->getPort("\\R");
283 val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
284 val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
285 val_rv = RTLIL::Const(dff->type[8] == '1', 1);
286 }
287 else if (dff->type == "$ff") {
288 sig_d = dff->getPort("\\D");
289 sig_q = dff->getPort("\\Q");
290 }
291 else if (dff->type == "$dff") {
292 sig_d = dff->getPort("\\D");
293 sig_q = dff->getPort("\\Q");
294 sig_c = dff->getPort("\\CLK");
295 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
296 }
297 else if (dff->type == "$adff") {
298 sig_d = dff->getPort("\\D");
299 sig_q = dff->getPort("\\Q");
300 sig_c = dff->getPort("\\CLK");
301 sig_r = dff->getPort("\\ARST");
302 val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
303 val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
304 val_rv = dff->parameters["\\ARST_VALUE"];
305 }
306 else
307 log_abort();
308
309 assign_map.apply(sig_d);
310 assign_map.apply(sig_q);
311 assign_map.apply(sig_c);
312 assign_map.apply(sig_r);
313
314 bool has_init = false;
315 RTLIL::Const val_init;
316 for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
317 if (bit.wire == NULL || keepdc)
318 has_init = true;
319 val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
320 }
321
322 if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
323 std::set<RTLIL::Cell*> muxes;
324 mux_drivers.find(sig_d, muxes);
325 for (auto mux : muxes) {
326 RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
327 RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
328 if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
329 mod->connect(sig_q, sig_b);
330 goto delete_dff;
331 }
332 if (sig_b == sig_q && sig_a.is_fully_const() && (!has_init || val_init == sig_a.as_const())) {
333 mod->connect(sig_q, sig_a);
334 goto delete_dff;
335 }
336 }
337 }
338
339 if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
340 if (val_rv.bits.size() == 0)
341 val_rv = val_init;
342 mod->connect(sig_q, val_rv);
343 goto delete_dff;
344 }
345
346 if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
347 mod->connect(sig_q, val_rv);
348 goto delete_dff;
349 }
350
351 if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
352 mod->connect(sig_q, val_init);
353 goto delete_dff;
354 }
355
356 if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
357 mod->connect(sig_q, sig_d);
358 goto delete_dff;
359 }
360
361 if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
362 if (sig_r.size())
363 mod->connect(sig_q, val_rv);
364 if (has_init)
365 mod->connect(sig_q, val_init);
366 goto delete_dff;
367 }
368
369 if (!sig_r.empty() && sig_r.is_fully_const())
370 {
371 if (sig_r == val_rp || sig_r.is_fully_undef()) {
372 mod->connect(sig_q, val_rv);
373 goto delete_dff;
374 }
375
376 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
377
378 if (dff->type == "$adff") {
379 dff->type = "$dff";
380 dff->unsetPort("\\ARST");
381 dff->unsetParam("\\ARST_POLARITY");
382 dff->unsetParam("\\ARST_VALUE");
383 return true;
384 }
385
386 log_assert(dff->type.substr(0,6) == "$_DFF_");
387 dff->type = stringf("$_DFF_%c_", + dff->type[6]);
388 dff->unsetPort("\\R");
389 }
390
391 return false;
392
393 delete_dff:
394 log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
395 remove_init_attr(dff->getPort("\\Q"));
396 mod->remove(dff);
397 return true;
398 }
399
400 struct OptRmdffPass : public Pass {
401 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
402 void help() YS_OVERRIDE
403 {
404 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
405 log("\n");
406 log(" opt_rmdff [-keepdc] [selection]\n");
407 log("\n");
408 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
409 log("a constant driver.\n");
410 log("\n");
411 }
412 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
413 {
414 int total_count = 0, total_initdrv = 0;
415 log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
416
417 keepdc = false;
418
419 size_t argidx;
420 for (argidx = 1; argidx < args.size(); argidx++) {
421 if (args[argidx] == "-keepdc") {
422 keepdc = true;
423 continue;
424 }
425 break;
426 }
427 extra_args(args, argidx, design);
428
429 for (auto module : design->selected_modules())
430 {
431 pool<SigBit> driven_bits;
432 dict<SigBit, State> init_bits;
433
434 assign_map.set(module);
435 dff_init_map.set(module);
436 mux_drivers.clear();
437 init_attributes.clear();
438
439 for (auto wire : module->wires())
440 {
441 if (wire->attributes.count("\\init") != 0) {
442 Const initval = wire->attributes.at("\\init");
443 for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
444 if (initval[i] == State::S0 || initval[i] == State::S1)
445 dff_init_map.add(SigBit(wire, i), initval[i]);
446 for (int i = 0; i < GetSize(wire); i++) {
447 SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
448 if (mapped_bit.wire) {
449 init_attributes[mapped_bit].insert(wire_bit);
450 if (i < GetSize(initval))
451 init_bits[mapped_bit] = initval[i];
452 }
453 }
454 }
455
456 if (wire->port_input) {
457 for (auto bit : assign_map(wire))
458 driven_bits.insert(bit);
459 }
460 }
461 mux_drivers.clear();
462
463 std::vector<RTLIL::IdString> dff_list;
464 std::vector<RTLIL::IdString> dffsr_list;
465 std::vector<RTLIL::IdString> dlatch_list;
466 for (auto cell : module->cells())
467 {
468 for (auto &conn : cell->connections())
469 if (cell->output(conn.first) || !cell->known())
470 for (auto bit : assign_map(conn.second))
471 driven_bits.insert(bit);
472
473 if (cell->type == "$mux" || cell->type == "$pmux") {
474 if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
475 mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
476 continue;
477 }
478
479 if (!design->selected(module, cell))
480 continue;
481
482 if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
483 "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
484 "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
485 "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
486 dffsr_list.push_back(cell->name);
487
488 if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
489 "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
490 "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
491 "$ff", "$dff", "$adff"))
492 dff_list.push_back(cell->name);
493
494 if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
495 dlatch_list.push_back(cell->name);
496 }
497
498 for (auto &id : dffsr_list) {
499 if (module->cell(id) != nullptr &&
500 handle_dffsr(module, module->cells_[id]))
501 total_count++;
502 }
503
504 for (auto &id : dff_list) {
505 if (module->cell(id) != nullptr &&
506 handle_dff(module, module->cells_[id]))
507 total_count++;
508 }
509
510 for (auto &id : dlatch_list) {
511 if (module->cell(id) != nullptr &&
512 handle_dlatch(module, module->cells_[id]))
513 total_count++;
514 }
515
516 SigSpec const_init_sigs;
517
518 for (auto bit : init_bits)
519 if (!driven_bits.count(bit.first))
520 const_init_sigs.append(bit.first);
521
522 const_init_sigs.sort_and_unify();
523
524 for (SigSpec sig : const_init_sigs.chunks())
525 {
526 Const val;
527
528 for (auto bit : sig)
529 val.bits.push_back(init_bits.at(bit));
530
531 log("Promoting init spec %s = %s to constant driver in module %s.\n",
532 log_signal(sig), log_signal(val), log_id(module));
533
534 module->connect(sig, val);
535 remove_init_attr(sig);
536 total_initdrv++;
537 }
538 }
539
540 assign_map.clear();
541 mux_drivers.clear();
542 init_attributes.clear();
543
544 if (total_count || total_initdrv)
545 design->scratchpad_set_bool("opt.did_something", true);
546
547 if (total_initdrv)
548 log("Promoted %d init specs to constant drivers.\n", total_initdrv);
549
550 if (total_count)
551 log("Replaced %d DFF cells.\n", total_count);
552 }
553 } OptRmdffPass;
554
555 PRIVATE_NAMESPACE_END