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
[7] == 'P', 1);
296 val_ep
= RTLIL::Const(dff
->type
[8] == '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
);
341 if (dff
->type
.in("$ff", "$dff") && mux_drivers
.has(sig_d
)) {
342 std::set
<RTLIL::Cell
*> muxes
;
343 mux_drivers
.find(sig_d
, muxes
);
344 for (auto mux
: muxes
) {
345 RTLIL::SigSpec sig_a
= assign_map(mux
->getPort("\\A"));
346 RTLIL::SigSpec sig_b
= assign_map(mux
->getPort("\\B"));
347 if (sig_a
== sig_q
&& sig_b
.is_fully_const() && (!has_init
|| val_init
== sig_b
.as_const())) {
348 mod
->connect(sig_q
, sig_b
);
351 if (sig_b
== sig_q
&& sig_a
.is_fully_const() && (!has_init
|| val_init
== sig_a
.as_const())) {
352 mod
->connect(sig_q
, sig_a
);
358 // If clock is driven by a constant and (i) no reset signal
359 // (ii) Q has no initial value
360 // (iii) initial value is same as reset value
361 if (!sig_c
.empty() && sig_c
.is_fully_const() && (!sig_r
.size() || !has_init
|| val_init
== val_rv
)) {
362 if (val_rv
.bits
.size() == 0)
364 // Q is permanently reset value or initial value
365 mod
->connect(sig_q
, val_rv
);
369 // If D is fully undefined and reset signal present and (i) Q has no initial value
370 // (ii) initial value is same as reset value
371 if (sig_d
.is_fully_undef() && sig_r
.size() && (!has_init
|| val_init
== val_rv
)) {
372 // Q is permanently reset value
373 mod
->connect(sig_q
, val_rv
);
377 // If D is fully undefined and no reset signal and Q has an initial value
378 if (sig_d
.is_fully_undef() && !sig_r
.size() && has_init
) {
379 // Q is permanently initial value
380 mod
->connect(sig_q
, val_init
);
384 // If D is fully constant and (i) no reset signal
385 // (ii) reset value is same as constant D
386 // and (a) has no initial value
387 // (b) initial value same as constant D
388 if (sig_d
.is_fully_const() && (!sig_r
.size() || val_rv
== sig_d
.as_const()) && (!has_init
|| val_init
== sig_d
.as_const())) {
389 // Q is permanently D
390 mod
->connect(sig_q
, sig_d
);
394 // If D input is same as Q output and (i) no reset signal
395 // (ii) no initial signal
396 // (iii) initial value is same as reset value
397 if (sig_d
== sig_q
&& (sig_r
.empty() || !has_init
|| val_init
== val_rv
)) {
398 // Q is permanently reset value or initial value
400 mod
->connect(sig_q
, val_rv
);
402 mod
->connect(sig_q
, val_init
);
406 // If reset signal is present, and is fully constant
407 if (!sig_r
.empty() && sig_r
.is_fully_const())
409 // If reset value is permanently active or if reset is undefined
410 if (sig_r
== val_rp
|| sig_r
.is_fully_undef()) {
411 // Q is permanently reset value
412 mod
->connect(sig_q
, val_rv
);
416 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
418 if (dff
->type
== "$adff") {
420 dff
->unsetPort("\\ARST");
421 dff
->unsetParam("\\ARST_POLARITY");
422 dff
->unsetParam("\\ARST_VALUE");
426 log_assert(dff
->type
.substr(0,6) == "$_DFF_");
427 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[6]);
428 dff
->unsetPort("\\R");
431 // If enable signal is present, and is fully constant
432 if (!sig_e
.empty() && sig_e
.is_fully_const())
434 // If enable value is permanently inactive
435 if (sig_e
!= val_ep
) {
436 // Q is permanently initial value
437 mod
->connect(sig_q
, val_init
);
441 log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
443 if (dff
->type
== "$dffe") {
445 dff
->unsetPort("\\EN");
446 dff
->unsetParam("\\EN_POLARITY");
450 log_assert(dff
->type
.substr(0,7) == "$_DFFE_");
451 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[7]);
452 dff
->unsetPort("\\E");
458 log("Removing %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
459 remove_init_attr(dff
->getPort("\\Q"));
464 struct OptRmdffPass
: public Pass
{
465 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
466 void help() YS_OVERRIDE
468 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
470 log(" opt_rmdff [-keepdc] [selection]\n");
472 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
473 log("a constant driver.\n");
476 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
478 int total_count
= 0, total_initdrv
= 0;
479 log_header(design
, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
484 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
485 if (args
[argidx
] == "-keepdc") {
491 extra_args(args
, argidx
, design
);
493 for (auto module
: design
->selected_modules())
495 pool
<SigBit
> driven_bits
;
496 dict
<SigBit
, State
> init_bits
;
498 assign_map
.set(module
);
499 dff_init_map
.set(module
);
501 init_attributes
.clear();
503 for (auto wire
: module
->wires())
505 if (wire
->attributes
.count("\\init") != 0) {
506 Const initval
= wire
->attributes
.at("\\init");
507 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++)
508 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
)
509 dff_init_map
.add(SigBit(wire
, i
), initval
[i
]);
510 for (int i
= 0; i
< GetSize(wire
); i
++) {
511 SigBit
wire_bit(wire
, i
), mapped_bit
= assign_map(wire_bit
);
512 if (mapped_bit
.wire
) {
513 init_attributes
[mapped_bit
].insert(wire_bit
);
514 if (i
< GetSize(initval
))
515 init_bits
[mapped_bit
] = initval
[i
];
520 if (wire
->port_input
) {
521 for (auto bit
: assign_map(wire
))
522 driven_bits
.insert(bit
);
527 std::vector
<RTLIL::IdString
> dff_list
;
528 std::vector
<RTLIL::IdString
> dffsr_list
;
529 std::vector
<RTLIL::IdString
> dlatch_list
;
530 for (auto cell
: module
->cells())
532 for (auto &conn
: cell
->connections())
533 if (cell
->output(conn
.first
) || !cell
->known())
534 for (auto bit
: assign_map(conn
.second
))
535 driven_bits
.insert(bit
);
537 if (cell
->type
== "$mux" || cell
->type
== "$pmux") {
538 if (cell
->getPort("\\A").size() == cell
->getPort("\\B").size())
539 mux_drivers
.insert(assign_map(cell
->getPort("\\Y")), cell
);
543 if (!design
->selected(module
, cell
))
546 if (cell
->type
.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
547 "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
548 "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
549 "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
550 dffsr_list
.push_back(cell
->name
);
552 if (cell
->type
.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
553 "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
554 "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
555 "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
556 "$ff", "$dff", "$dffe", "$adff"))
557 dff_list
.push_back(cell
->name
);
559 if (cell
->type
.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
560 dlatch_list
.push_back(cell
->name
);
563 for (auto &id
: dffsr_list
) {
564 if (module
->cell(id
) != nullptr &&
565 handle_dffsr(module
, module
->cells_
[id
]))
569 for (auto &id
: dff_list
) {
570 if (module
->cell(id
) != nullptr &&
571 handle_dff(module
, module
->cells_
[id
]))
575 for (auto &id
: dlatch_list
) {
576 if (module
->cell(id
) != nullptr &&
577 handle_dlatch(module
, module
->cells_
[id
]))
581 SigSpec const_init_sigs
;
583 for (auto bit
: init_bits
)
584 if (!driven_bits
.count(bit
.first
))
585 const_init_sigs
.append(bit
.first
);
587 const_init_sigs
.sort_and_unify();
589 for (SigSpec sig
: const_init_sigs
.chunks())
594 val
.bits
.push_back(init_bits
.at(bit
));
596 log("Promoting init spec %s = %s to constant driver in module %s.\n",
597 log_signal(sig
), log_signal(val
), log_id(module
));
599 module
->connect(sig
, val
);
600 remove_init_attr(sig
);
607 init_attributes
.clear();
609 if (total_count
|| total_initdrv
)
610 design
->scratchpad_set_bool("opt.did_something", true);
613 log("Promoted %d init specs to constant drivers.\n", total_initdrv
);
616 log("Replaced %d DFF cells.\n", total_count
);
620 PRIVATE_NAMESPACE_END