2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
29 SigMap assign_map
, dff_init_map
;
30 SigSet
<RTLIL::Cell
*> mux_drivers
;
31 dict
<SigBit
, pool
<SigBit
>> init_attributes
;
34 void remove_init_attr(SigSpec sig
)
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
;
42 bool handle_dffsr(RTLIL::Module
*mod
, RTLIL::Cell
*cell
)
44 SigSpec sig_set
, sig_clr
;
45 State pol_set
, pol_clr
;
47 if (cell
->hasPort("\\S"))
48 sig_set
= cell
->getPort("\\S");
50 if (cell
->hasPort("\\R"))
51 sig_clr
= cell
->getPort("\\R");
53 if (cell
->hasPort("\\SET"))
54 sig_set
= cell
->getPort("\\SET");
56 if (cell
->hasPort("\\CLR"))
57 sig_clr
= cell
->getPort("\\CLR");
59 log_assert(GetSize(sig_set
) == GetSize(sig_clr
));
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
;
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
;
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
;
75 State npol_set
= pol_set
== State::S0
? State::S1
: State::S0
;
76 State npol_clr
= pol_clr
== State::S0
? State::S1
: State::S0
;
78 SigSpec sig_d
= cell
->getPort("\\D");
79 SigSpec sig_q
= cell
->getPort("\\Q");
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;
89 for (int i
= 0; i
< GetSize(sig_set
); i
++)
91 SigBit s
= sig_set
[i
], c
= sig_clr
[i
];
93 if (s
!= npol_set
|| c
!= npol_clr
)
96 if (s
== pol_set
|| c
== pol_clr
)
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
));
102 remove_init_attr(sig_q
[i
]);
103 mod
->connect(sig_q
[i
], s
== pol_set
? State::S1
: State::S0
);
108 did_something
= true;
111 if (sig_reset
.empty() && s
.wire
!= nullptr) sig_reset
= s
;
112 if (sig_reset
.empty() && c
.wire
!= nullptr) sig_reset
= c
;
114 if (s
.wire
!= nullptr && s
!= sig_reset
) proper_sr
= true;
115 if (c
.wire
!= nullptr && c
!= sig_reset
) proper_sr
= true;
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
);
128 if (GetSize(sig_set
) == 0)
130 log("Removing %s (%s) from module %s.\n", log_id(cell
), log_id(cell
->type
), log_id(mod
));
135 if (cell
->type
== "$dffsr" || cell
->type
== "$dlatchsr")
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
);
145 cell
->setPort("\\S", sig_set
);
146 cell
->setPort("\\R", sig_clr
);
147 cell
->setPort("\\D", sig_d
);
148 cell
->setPort("\\Q", sig_q
);
152 return did_something
;
154 if (used_pol_set
&& used_pol_clr
&& pol_set
!= pol_clr
)
155 return did_something
;
157 if (cell
->type
== "$dlatchsr")
158 return did_something
;
160 State unified_pol
= used_pol_set
? pol_set
: pol_clr
;
162 if (cell
->type
== "$dffsr")
166 log("Converting %s (%s) to %s in module %s.\n", log_id(cell
), log_id(cell
->type
), "$adff", log_id(mod
));
168 cell
->type
= "$adff";
169 cell
->setParam("\\ARST_POLARITY", unified_pol
);
170 cell
->setParam("\\ARST_VALUE", reset_val
);
171 cell
->setPort("\\ARST", sig_reset
);
173 cell
->unsetParam("\\SET_POLARITY");
174 cell
->unsetParam("\\CLR_POLARITY");
175 cell
->unsetPort("\\SET");
176 cell
->unsetPort("\\CLR");
180 log("Converting %s (%s) to %s in module %s.\n", log_id(cell
), log_id(cell
->type
), "$dff", log_id(mod
));
183 cell
->unsetParam("\\SET_POLARITY");
184 cell
->unsetParam("\\CLR_POLARITY");
185 cell
->unsetPort("\\SET");
186 cell
->unsetPort("\\CLR");
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]);
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
));
205 cell
->type
= new_type
;
206 cell
->unsetPort("\\S");
207 cell
->unsetPort("\\R");
212 return did_something
;
215 bool handle_dlatch(RTLIL::Module
*mod
, RTLIL::Cell
*dlatch
)
218 State on_state
, off_state
;
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
;
225 if (dlatch
->type
== "$_DLATCH_P_") {
226 sig_e
= assign_map(dlatch
->getPort("\\E"));
227 on_state
= State::S1
;
228 off_state
= State::S0
;
230 if (dlatch
->type
== "$_DLATCH_N_") {
231 sig_e
= assign_map(dlatch
->getPort("\\E"));
232 on_state
= State::S0
;
233 off_state
= State::S1
;
237 if (sig_e
== off_state
)
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
);
246 if (sig_e
== on_state
)
248 mod
->connect(dlatch
->getPort("\\Q"), dlatch
->getPort("\\D"));
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"));
261 bool handle_dff(RTLIL::Module
*mod
, RTLIL::Cell
*dff
)
263 RTLIL::SigSpec sig_d
, sig_q
, sig_c
, sig_r
, sig_e
;
264 RTLIL::Const val_cp
, val_rp
, val_rv
, val_ep
;
266 if (dff
->type
== "$_FF_") {
267 sig_d
= dff
->getPort("\\D");
268 sig_q
= dff
->getPort("\\Q");
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);
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);
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);
298 else if (dff
->type
== "$ff") {
299 sig_d
= dff
->getPort("\\D");
300 sig_q
= dff
->getPort("\\Q");
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);
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);
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"];
328 assign_map
.apply(sig_d
);
329 assign_map
.apply(sig_q
);
330 assign_map
.apply(sig_c
);
331 assign_map
.apply(sig_r
);
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
)
338 val_init
.bits
.push_back(bit
.wire
== NULL
? bit
.data
: RTLIL::State::Sx
);
342 if (!sig_e
.is_fully_const())
344 if (sig_e
!= val_ep
) {
345 mod
->connect(sig_q
, val_init
);
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
);
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
);
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)
373 // Q is permanently reset value or initial value
374 mod
->connect(sig_q
, val_rv
);
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
);
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
);
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
);
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
409 mod
->connect(sig_q
, val_rv
);
411 mod
->connect(sig_q
, val_init
);
415 // If reset signal is present, and is fully constant
416 if (!sig_r
.empty() && sig_r
.is_fully_const())
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
);
425 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
427 if (dff
->type
== "$adff") {
429 dff
->unsetPort("\\ARST");
430 dff
->unsetParam("\\ARST_POLARITY");
431 dff
->unsetParam("\\ARST_VALUE");
435 log_assert(dff
->type
.substr(0,6) == "$_DFF_");
436 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[6]);
437 dff
->unsetPort("\\R");
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"));
449 struct OptRmdffPass
: public Pass
{
450 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
451 void help() YS_OVERRIDE
453 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
455 log(" opt_rmdff [-keepdc] [selection]\n");
457 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
458 log("a constant driver.\n");
461 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
463 int total_count
= 0, total_initdrv
= 0;
464 log_header(design
, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
469 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
470 if (args
[argidx
] == "-keepdc") {
476 extra_args(args
, argidx
, design
);
478 for (auto module
: design
->selected_modules())
480 pool
<SigBit
> driven_bits
;
481 dict
<SigBit
, State
> init_bits
;
483 assign_map
.set(module
);
484 dff_init_map
.set(module
);
486 init_attributes
.clear();
488 for (auto wire
: module
->wires())
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
];
505 if (wire
->port_input
) {
506 for (auto bit
: assign_map(wire
))
507 driven_bits
.insert(bit
);
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())
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
);
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
);
528 if (!design
->selected(module
, cell
))
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
);
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
);
544 if (cell
->type
.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
545 dlatch_list
.push_back(cell
->name
);
548 for (auto &id
: dffsr_list
) {
549 if (module
->cell(id
) != nullptr &&
550 handle_dffsr(module
, module
->cells_
[id
]))
554 for (auto &id
: dff_list
) {
555 if (module
->cell(id
) != nullptr &&
556 handle_dff(module
, module
->cells_
[id
]))
560 for (auto &id
: dlatch_list
) {
561 if (module
->cell(id
) != nullptr &&
562 handle_dlatch(module
, module
->cells_
[id
]))
566 SigSpec const_init_sigs
;
568 for (auto bit
: init_bits
)
569 if (!driven_bits
.count(bit
.first
))
570 const_init_sigs
.append(bit
.first
);
572 const_init_sigs
.sort_and_unify();
574 for (SigSpec sig
: const_init_sigs
.chunks())
579 val
.bits
.push_back(init_bits
.at(bit
));
581 log("Promoting init spec %s = %s to constant driver in module %s.\n",
582 log_signal(sig
), log_signal(val
), log_id(module
));
584 module
->connect(sig
, val
);
585 remove_init_attr(sig
);
592 init_attributes
.clear();
594 if (total_count
|| total_initdrv
)
595 design
->scratchpad_set_bool("opt.did_something", true);
598 log("Promoted %d init specs to constant drivers.\n", total_initdrv
);
601 log("Replaced %d DFF cells.\n", total_count
);
605 PRIVATE_NAMESPACE_END