41bbdcd5735b689fa0c891e09ee6a17020a24bbd
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/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"
30 PRIVATE_NAMESPACE_BEGIN
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
;
41 void remove_init_attr(SigSpec sig
)
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
;
49 bool handle_dffsr(RTLIL::Module
*mod
, RTLIL::Cell
*cell
)
51 SigSpec sig_set
, sig_clr
;
52 State pol_set
, pol_clr
;
54 if (cell
->hasPort("\\S"))
55 sig_set
= cell
->getPort("\\S");
57 if (cell
->hasPort("\\R"))
58 sig_clr
= cell
->getPort("\\R");
60 if (cell
->hasPort("\\SET"))
61 sig_set
= cell
->getPort("\\SET");
63 if (cell
->hasPort("\\CLR"))
64 sig_clr
= cell
->getPort("\\CLR");
66 log_assert(GetSize(sig_set
) == GetSize(sig_clr
));
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
;
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
;
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
;
82 State npol_set
= pol_set
== State::S0
? State::S1
: State::S0
;
83 State npol_clr
= pol_clr
== State::S0
? State::S1
: State::S0
;
85 SigSpec sig_d
= cell
->getPort("\\D");
86 SigSpec sig_q
= cell
->getPort("\\Q");
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;
96 for (int i
= 0; i
< GetSize(sig_set
); i
++)
98 SigBit s
= sig_set
[i
], c
= sig_clr
[i
];
100 if (s
!= npol_set
|| c
!= npol_clr
)
103 if (s
== pol_set
|| c
== pol_clr
)
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
));
109 remove_init_attr(sig_q
[i
]);
110 mod
->connect(sig_q
[i
], s
== pol_set
? State::S1
: State::S0
);
115 did_something
= true;
118 if (sig_reset
.empty() && s
.wire
!= nullptr) sig_reset
= s
;
119 if (sig_reset
.empty() && c
.wire
!= nullptr) sig_reset
= c
;
121 if (s
.wire
!= nullptr && s
!= sig_reset
) proper_sr
= true;
122 if (c
.wire
!= nullptr && c
!= sig_reset
) proper_sr
= true;
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
);
135 if (GetSize(sig_set
) == 0)
137 log("Removing %s (%s) from module %s.\n", log_id(cell
), log_id(cell
->type
), log_id(mod
));
142 if (cell
->type
== "$dffsr" || cell
->type
== "$dlatchsr")
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
);
152 cell
->setPort("\\S", sig_set
);
153 cell
->setPort("\\R", sig_clr
);
154 cell
->setPort("\\D", sig_d
);
155 cell
->setPort("\\Q", sig_q
);
159 return did_something
;
161 if (used_pol_set
&& used_pol_clr
&& pol_set
!= pol_clr
)
162 return did_something
;
164 if (cell
->type
== "$dlatchsr")
165 return did_something
;
167 State unified_pol
= used_pol_set
? pol_set
: pol_clr
;
169 if (cell
->type
== "$dffsr")
173 log("Converting %s (%s) to %s in module %s.\n", log_id(cell
), log_id(cell
->type
), "$adff", log_id(mod
));
175 cell
->type
= "$adff";
176 cell
->setParam("\\ARST_POLARITY", unified_pol
);
177 cell
->setParam("\\ARST_VALUE", reset_val
);
178 cell
->setPort("\\ARST", sig_reset
);
180 cell
->unsetParam("\\SET_POLARITY");
181 cell
->unsetParam("\\CLR_POLARITY");
182 cell
->unsetPort("\\SET");
183 cell
->unsetPort("\\CLR");
187 log("Converting %s (%s) to %s in module %s.\n", log_id(cell
), log_id(cell
->type
), "$dff", log_id(mod
));
190 cell
->unsetParam("\\SET_POLARITY");
191 cell
->unsetParam("\\CLR_POLARITY");
192 cell
->unsetPort("\\SET");
193 cell
->unsetPort("\\CLR");
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]);
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
));
212 cell
->type
= new_type
;
213 cell
->unsetPort("\\S");
214 cell
->unsetPort("\\R");
219 return did_something
;
222 bool handle_dlatch(RTLIL::Module
*mod
, RTLIL::Cell
*dlatch
)
225 State on_state
, off_state
;
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
;
232 if (dlatch
->type
== "$_DLATCH_P_") {
233 sig_e
= assign_map(dlatch
->getPort("\\E"));
234 on_state
= State::S1
;
235 off_state
= State::S0
;
237 if (dlatch
->type
== "$_DLATCH_N_") {
238 sig_e
= assign_map(dlatch
->getPort("\\E"));
239 on_state
= State::S0
;
240 off_state
= State::S1
;
244 if (sig_e
== off_state
)
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
);
253 if (sig_e
== on_state
)
255 mod
->connect(dlatch
->getPort("\\Q"), dlatch
->getPort("\\D"));
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"));
268 bool handle_dff(RTLIL::Module
*mod
, RTLIL::Cell
*dff
)
270 RTLIL::SigSpec sig_d
, sig_q
, sig_c
, sig_r
, sig_e
;
271 RTLIL::Const val_cp
, val_rp
, val_rv
, val_ep
;
273 if (dff
->type
== "$_FF_") {
274 sig_d
= dff
->getPort("\\D");
275 sig_q
= dff
->getPort("\\Q");
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);
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);
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);
305 else if (dff
->type
== "$ff") {
306 sig_d
= dff
->getPort("\\D");
307 sig_q
= dff
->getPort("\\Q");
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);
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);
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"];
335 assign_map
.apply(sig_d
);
336 assign_map
.apply(sig_q
);
337 assign_map
.apply(sig_c
);
338 assign_map
.apply(sig_r
);
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
)
345 val_init
.bits
.push_back(bit
.wire
== NULL
? bit
.data
: RTLIL::State::Sx
);
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
);
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
);
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)
371 // Q is permanently reset value or initial value
372 mod
->connect(sig_q
, val_rv
);
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
);
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
);
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
);
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
407 mod
->connect(sig_q
, val_rv
);
409 mod
->connect(sig_q
, val_init
);
413 // If reset signal is present, and is fully constant
414 if (!sig_r
.empty() && sig_r
.is_fully_const())
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
);
423 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
425 if (dff
->type
== "$adff") {
427 dff
->unsetPort("\\ARST");
428 dff
->unsetParam("\\ARST_POLARITY");
429 dff
->unsetParam("\\ARST_VALUE");
433 log_assert(dff
->type
.substr(0,6) == "$_DFF_");
434 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[6]);
435 dff
->unsetPort("\\R");
438 // If enable signal is present, and is fully constant
439 if (!sig_e
.empty() && sig_e
.is_fully_const())
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
);
448 log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
450 if (dff
->type
== "$dffe") {
452 dff
->unsetPort("\\EN");
453 dff
->unsetParam("\\EN_POLARITY");
457 log_assert(dff
->type
.substr(0,7) == "$_DFFE_");
458 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[7]);
459 dff
->unsetPort("\\E");
462 if (sat
&& has_init
) {
463 bool removed_sigbits
= false;
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());
471 // Load netlist for the module from the pool
472 Netlist
&net
= netlists
.at(mod
);
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
];
480 if ((!q_sigbit
.wire
) || (!d_sigbit
.wire
)) {
485 SatGen
satgen(ez
.get(), &net
.sigmap
);
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
));
494 RTLIL::Const sigbit_init_val
= val_init
.extract(position
);
495 int init_sat_pi
= satgen
.importSigSpec(sigbit_init_val
).front();
497 int q_sat_pi
= satgen
.importSigBit(q_sigbit
);
498 int d_sat_pi
= satgen
.importSigBit(d_sigbit
);
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
)));
503 // If the register bit cannot change, we can replace it with a constant
504 if (!counter_example_found
) {
506 RTLIL::SigBit
&driver_port
= net
.driver_port(q_sigbit
);
507 RTLIL::Wire
*dummy_wire
= mod
->addWire(NEW_ID
, 1);
509 for (auto &conn
: mod
->connections_
)
510 net
.sigmap(conn
.first
).replace(driver_port
, dummy_wire
, &conn
.first
);
512 remove_init_attr(driver_port
);
513 driver_port
= dummy_wire
;
515 mod
->connect(RTLIL::SigSig(q_sigbit
, sigbit_init_val
));
517 removed_sigbits
= true;
521 if (removed_sigbits
) {
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"));
536 struct OptRmdffPass
: public Pass
{
537 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
538 void help() YS_OVERRIDE
540 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
542 log(" opt_rmdff [-keepdc] [-sat] [selection]\n");
544 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
545 log("a constant driver.\n");
548 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
550 int total_count
= 0, total_initdrv
= 0;
551 log_header(design
, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
557 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
558 if (args
[argidx
] == "-keepdc") {
562 if (args
[argidx
] == "-sat") {
568 extra_args(args
, argidx
, design
);
570 comb_filters
.clear();
572 for (auto module
: design
->selected_modules()) {
573 pool
<SigBit
> driven_bits
;
574 dict
<SigBit
, State
> init_bits
;
576 assign_map
.set(module
);
577 dff_init_map
.set(module
);
579 init_attributes
.clear();
581 for (auto wire
: module
->wires())
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
];
598 if (wire
->port_input
) {
599 for (auto bit
: assign_map(wire
))
600 driven_bits
.insert(bit
);
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())
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
);
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
);
621 if (!design
->selected(module
, cell
))
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
);
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
);
637 if (cell
->type
.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
638 dlatch_list
.push_back(cell
->name
);
641 for (auto &id
: dffsr_list
) {
642 if (module
->cell(id
) != nullptr &&
643 handle_dffsr(module
, module
->cells_
[id
]))
647 for (auto &id
: dff_list
) {
648 if (module
->cell(id
) != nullptr &&
649 handle_dff(module
, module
->cells_
[id
]))
653 for (auto &id
: dlatch_list
) {
654 if (module
->cell(id
) != nullptr &&
655 handle_dlatch(module
, module
->cells_
[id
]))
659 SigSpec const_init_sigs
;
661 for (auto bit
: init_bits
)
662 if (!driven_bits
.count(bit
.first
))
663 const_init_sigs
.append(bit
.first
);
665 const_init_sigs
.sort_and_unify();
667 for (SigSpec sig
: const_init_sigs
.chunks())
672 val
.bits
.push_back(init_bits
.at(bit
));
674 log("Promoting init spec %s = %s to constant driver in module %s.\n",
675 log_signal(sig
), log_signal(val
), log_id(module
));
677 module
->connect(sig
, val
);
678 remove_init_attr(sig
);
685 init_attributes
.clear();
687 if (total_count
|| total_initdrv
)
688 design
->scratchpad_set_bool("opt.did_something", true);
691 log("Promoted %d init specs to constant drivers.\n", total_initdrv
);
694 log("Replaced %d DFF cells.\n", total_count
);
698 PRIVATE_NAMESPACE_END