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");
182 log("Converting %s (%s) to %s in module %s.\n", log_id(cell
), log_id(cell
->type
), "$dff", log_id(mod
));
185 cell
->unsetParam("\\SET_POLARITY");
186 cell
->unsetParam("\\CLR_POLARITY");
187 cell
->unsetPort("\\SET");
188 cell
->unsetPort("\\CLR");
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]);
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
));
206 cell
->type
= new_type
;
207 cell
->unsetPort("\\S");
208 cell
->unsetPort("\\R");
210 return did_something
;
214 bool handle_dlatch(RTLIL::Module
*mod
, RTLIL::Cell
*dlatch
)
217 State on_state
, off_state
;
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
;
224 if (dlatch
->type
== "$_DLATCH_P_") {
225 sig_e
= assign_map(dlatch
->getPort("\\E"));
226 on_state
= State::S1
;
227 off_state
= State::S0
;
229 if (dlatch
->type
== "$_DLATCH_N_") {
230 sig_e
= assign_map(dlatch
->getPort("\\E"));
231 on_state
= State::S0
;
232 off_state
= State::S1
;
236 if (sig_e
== off_state
)
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
);
245 if (sig_e
== on_state
)
247 mod
->connect(dlatch
->getPort("\\Q"), dlatch
->getPort("\\D"));
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"));
260 bool handle_dff(RTLIL::Module
*mod
, RTLIL::Cell
*dff
)
262 RTLIL::SigSpec sig_d
, sig_q
, sig_c
, sig_r
;
263 RTLIL::Const val_cp
, val_rp
, val_rv
;
265 if (dff
->type
== "$_FF_") {
266 sig_d
= dff
->getPort("\\D");
267 sig_q
= dff
->getPort("\\Q");
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);
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);
287 else if (dff
->type
== "$ff") {
288 sig_d
= dff
->getPort("\\D");
289 sig_q
= dff
->getPort("\\Q");
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);
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"];
309 assign_map
.apply(sig_d
);
310 assign_map
.apply(sig_q
);
311 assign_map
.apply(sig_c
);
312 assign_map
.apply(sig_r
);
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
)
319 val_init
.bits
.push_back(bit
.wire
== NULL
? bit
.data
: RTLIL::State::Sx
);
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
);
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
);
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)
342 mod
->connect(sig_q
, val_rv
);
346 if (sig_d
.is_fully_undef() && sig_r
.size() && (!has_init
|| val_init
== val_rv
)) {
347 mod
->connect(sig_q
, val_rv
);
351 if (sig_d
.is_fully_undef() && !sig_r
.size() && has_init
) {
352 mod
->connect(sig_q
, val_init
);
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
);
361 if (sig_d
== sig_q
&& (sig_r
.empty() || !has_init
|| val_init
== val_rv
)) {
363 mod
->connect(sig_q
, val_rv
);
365 mod
->connect(sig_q
, val_init
);
369 if (!sig_r
.empty() && sig_r
.is_fully_const())
371 if (sig_r
== val_rp
|| sig_r
.is_fully_undef()) {
372 mod
->connect(sig_q
, val_rv
);
376 log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff
), log_id(dff
->type
), log_id(mod
));
378 if (dff
->type
== "$adff") {
380 dff
->unsetPort("\\ARST");
381 dff
->unsetParam("\\ARST_POLARITY");
382 dff
->unsetParam("\\ARST_VALUE");
386 log_assert(dff
->type
.substr(0,6) == "$_DFF_");
387 dff
->type
= stringf("$_DFF_%c_", + dff
->type
[6]);
388 dff
->unsetPort("\\R");
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"));
400 struct OptRmdffPass
: public Pass
{
401 OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
402 void help() YS_OVERRIDE
404 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
406 log(" opt_rmdff [-keepdc] [selection]\n");
408 log("This pass identifies flip-flops with constant inputs and replaces them with\n");
409 log("a constant driver.\n");
412 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
414 int total_count
= 0, total_initdrv
= 0;
415 log_header(design
, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
420 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
421 if (args
[argidx
] == "-keepdc") {
427 extra_args(args
, argidx
, design
);
429 for (auto module
: design
->selected_modules())
431 pool
<SigBit
> driven_bits
;
432 dict
<SigBit
, State
> init_bits
;
434 assign_map
.set(module
);
435 dff_init_map
.set(module
);
437 init_attributes
.clear();
439 for (auto wire
: module
->wires())
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
];
456 if (wire
->port_input
) {
457 for (auto bit
: assign_map(wire
))
458 driven_bits
.insert(bit
);
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())
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
);
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
);
479 if (!design
->selected(module
, cell
))
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
);
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
);
494 if (cell
->type
.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
495 dlatch_list
.push_back(cell
->name
);
498 for (auto &id
: dffsr_list
) {
499 if (module
->cell(id
) != nullptr &&
500 handle_dffsr(module
, module
->cells_
[id
]))
504 for (auto &id
: dff_list
) {
505 if (module
->cell(id
) != nullptr &&
506 handle_dff(module
, module
->cells_
[id
]))
510 for (auto &id
: dlatch_list
) {
511 if (module
->cell(id
) != nullptr &&
512 handle_dlatch(module
, module
->cells_
[id
]))
516 SigSpec const_init_sigs
;
518 for (auto bit
: init_bits
)
519 if (!driven_bits
.count(bit
.first
))
520 const_init_sigs
.append(bit
.first
);
522 const_init_sigs
.sort_and_unify();
524 for (SigSpec sig
: const_init_sigs
.chunks())
529 val
.bits
.push_back(init_bits
.at(bit
));
531 log("Promoting init spec %s = %s to constant driver in module %s.\n",
532 log_signal(sig
), log_signal(val
), log_id(module
));
534 module
->connect(sig
, val
);
535 remove_init_attr(sig
);
542 init_attributes
.clear();
544 if (total_count
|| total_initdrv
)
545 design
->scratchpad_set_bool("opt.did_something", true);
548 log("Promoted %d init specs to constant drivers.\n", total_initdrv
);
551 log("Replaced %d DFF cells.\n", total_count
);
555 PRIVATE_NAMESPACE_END