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/celltypes.h"
23 #include "kernel/utils.h"
24 #include "kernel/log.h"
30 PRIVATE_NAMESPACE_BEGIN
34 void replace_undriven(RTLIL::Design
*design
, RTLIL::Module
*module
)
37 SigMap
sigmap(module
);
38 SigPool driven_signals
;
42 dict
<SigBit
, pair
<Wire
*, State
>> initbits
;
43 pool
<Wire
*> revisit_initwires
;
45 for (auto cell
: module
->cells())
46 for (auto &conn
: cell
->connections()) {
47 if (!ct
.cell_known(cell
->type
) || ct
.cell_output(cell
->type
, conn
.first
))
48 driven_signals
.add(sigmap(conn
.second
));
49 if (!ct
.cell_known(cell
->type
) || ct
.cell_input(cell
->type
, conn
.first
))
50 used_signals
.add(sigmap(conn
.second
));
53 for (auto wire
: module
->wires()) {
54 if (wire
->attributes
.count("\\init")) {
55 SigSpec sig
= sigmap(wire
);
56 Const initval
= wire
->attributes
.at("\\init");
57 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++) {
58 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
)
59 initbits
[sig
[i
]] = make_pair(wire
, initval
[i
]);
63 driven_signals
.add(sigmap(wire
));
64 if (wire
->port_output
|| wire
->get_bool_attribute("\\keep"))
65 used_signals
.add(sigmap(wire
));
66 all_signals
.add(sigmap(wire
));
69 all_signals
.del(driven_signals
);
70 RTLIL::SigSpec undriven_signals
= all_signals
.export_all();
72 for (auto &c
: undriven_signals
.chunks())
74 RTLIL::SigSpec sig
= c
;
76 if (c
.wire
->name
[0] == '$')
77 sig
= used_signals
.extract(sig
);
81 Const
val(RTLIL::State::Sx
, GetSize(sig
));
82 for (int i
= 0; i
< GetSize(sig
); i
++) {
83 SigBit bit
= sigmap(sig
[i
]);
84 auto cursor
= initbits
.find(bit
);
85 if (cursor
!= initbits
.end()) {
86 revisit_initwires
.insert(cursor
->second
.first
);
87 val
[i
] = cursor
->second
.second
;
91 log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module
), log_signal(sig
), log_signal(val
));
92 module
->connect(sig
, val
);
96 if (!revisit_initwires
.empty())
100 for (auto wire
: revisit_initwires
) {
101 SigSpec sig
= sm2(wire
);
102 Const initval
= wire
->attributes
.at("\\init");
103 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++) {
104 if (SigBit(initval
[i
]) == sig
[i
])
105 initval
[i
] = State::Sx
;
107 if (initval
.is_fully_undef()) {
108 log_debug("Removing init attribute from %s/%s.\n", log_id(module
), log_id(wire
));
109 wire
->attributes
.erase("\\init");
110 did_something
= true;
111 } else if (initval
!= wire
->attributes
.at("\\init")) {
112 log_debug("Updating init attribute on %s/%s: %s\n", log_id(module
), log_id(wire
), log_signal(initval
));
113 wire
->attributes
["\\init"] = initval
;
114 did_something
= true;
120 void replace_cell(SigMap
&assign_map
, RTLIL::Module
*module
, RTLIL::Cell
*cell
, std::string info
, std::string out_port
, RTLIL::SigSpec out_val
)
122 RTLIL::SigSpec Y
= cell
->getPort(out_port
);
123 out_val
.extend_u0(Y
.size(), false);
125 log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
126 cell
->type
.c_str(), cell
->name
.c_str(), info
.c_str(),
127 module
->name
.c_str(), log_signal(Y
), log_signal(out_val
));
129 assign_map
.add(Y
, out_val
);
130 module
->connect(Y
, out_val
);
131 module
->remove(cell
);
132 did_something
= true;
135 bool group_cell_inputs(RTLIL::Module
*module
, RTLIL::Cell
*cell
, bool commutative
, SigMap
&sigmap
)
137 std::string b_name
= cell
->hasPort("\\B") ? "\\B" : "\\A";
139 bool a_signed
= cell
->parameters
.at("\\A_SIGNED").as_bool();
140 bool b_signed
= cell
->parameters
.at(b_name
+ "_SIGNED").as_bool();
142 RTLIL::SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
143 RTLIL::SigSpec sig_b
= sigmap(cell
->getPort(b_name
));
144 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
146 sig_a
.extend_u0(sig_y
.size(), a_signed
);
147 sig_b
.extend_u0(sig_y
.size(), b_signed
);
149 std::vector
<RTLIL::SigBit
> bits_a
= sig_a
, bits_b
= sig_b
, bits_y
= sig_y
;
151 enum { GRP_DYN
, GRP_CONST_A
, GRP_CONST_B
, GRP_CONST_AB
, GRP_N
};
152 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::set
<RTLIL::SigBit
>> grouped_bits
[GRP_N
];
154 for (int i
= 0; i
< GetSize(bits_y
); i
++)
156 int group_idx
= GRP_DYN
;
157 RTLIL::SigBit bit_a
= bits_a
[i
], bit_b
= bits_b
[i
];
159 if (cell
->type
== "$or" && (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
))
160 bit_a
= bit_b
= RTLIL::State::S1
;
162 if (cell
->type
== "$and" && (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
))
163 bit_a
= bit_b
= RTLIL::State::S0
;
165 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
166 group_idx
= GRP_CONST_AB
;
167 else if (bit_a
.wire
== NULL
)
168 group_idx
= GRP_CONST_A
;
169 else if (bit_b
.wire
== NULL
&& commutative
)
170 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
171 else if (bit_b
.wire
== NULL
)
172 group_idx
= GRP_CONST_B
;
174 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
177 for (int i
= 0; i
< GRP_N
; i
++)
178 if (GetSize(grouped_bits
[i
]) == GetSize(bits_y
))
181 log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
182 log_id(cell
->type
), log_id(cell
), log_id(module
));
184 for (int i
= 0; i
< GRP_N
; i
++)
186 if (grouped_bits
[i
].empty())
189 RTLIL::Wire
*new_y
= module
->addWire(NEW_ID
, GetSize(grouped_bits
[i
]));
190 RTLIL::SigSpec new_a
, new_b
;
191 RTLIL::SigSig new_conn
;
193 for (auto &it
: grouped_bits
[i
]) {
194 for (auto &bit
: it
.second
) {
195 new_conn
.first
.append_bit(bit
);
196 new_conn
.second
.append_bit(RTLIL::SigBit(new_y
, new_a
.size()));
198 new_a
.append_bit(it
.first
.first
);
199 new_b
.append_bit(it
.first
.second
);
202 if (cell
->type
.in("$and", "$or") && i
== GRP_CONST_A
) {
203 log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b
), log_id(cell
->type
), log_signal(new_a
));
204 module
->connect(new_y
, new_b
);
205 module
->connect(new_conn
);
209 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
211 c
->setPort("\\A", new_a
);
212 c
->parameters
["\\A_WIDTH"] = new_a
.size();
213 c
->parameters
["\\A_SIGNED"] = false;
215 if (b_name
== "\\B") {
216 c
->setPort("\\B", new_b
);
217 c
->parameters
["\\B_WIDTH"] = new_b
.size();
218 c
->parameters
["\\B_SIGNED"] = false;
221 c
->setPort("\\Y", new_y
);
222 c
->parameters
["\\Y_WIDTH"] = new_y
->width
;
225 module
->connect(new_conn
);
227 log_debug(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
229 log_debug(", B=%s", log_signal(new_b
));
233 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell
->type
.str());
235 module
->remove(cell
);
236 did_something
= true;
240 void handle_polarity_inv(Cell
*cell
, IdString port
, IdString param
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
242 SigSpec sig
= assign_map(cell
->getPort(port
));
243 if (invert_map
.count(sig
)) {
244 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
245 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
246 log_signal(sig
), log_signal(invert_map
.at(sig
)));
247 cell
->setPort(port
, (invert_map
.at(sig
)));
248 cell
->setParam(param
, !cell
->getParam(param
).as_bool());
252 void handle_clkpol_celltype_swap(Cell
*cell
, string type1
, string type2
, IdString port
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
254 log_assert(GetSize(type1
) == GetSize(type2
));
255 string cell_type
= cell
->type
.str();
257 if (GetSize(type1
) != GetSize(cell_type
))
260 for (int i
= 0; i
< GetSize(type1
); i
++) {
261 log_assert((type1
[i
] == '?') == (type2
[i
] == '?'));
262 if (type1
[i
] == '?') {
263 if (cell_type
[i
] != '0' && cell_type
[i
] != '1' && cell_type
[i
] != 'N' && cell_type
[i
] != 'P')
265 type1
[i
] = cell_type
[i
];
266 type2
[i
] = cell_type
[i
];
270 if (cell
->type
.in(type1
, type2
)) {
271 SigSpec sig
= assign_map(cell
->getPort(port
));
272 if (invert_map
.count(sig
)) {
273 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
274 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
275 log_signal(sig
), log_signal(invert_map
.at(sig
)));
276 cell
->setPort(port
, (invert_map
.at(sig
)));
277 cell
->type
= cell
->type
== type1
? type2
: type1
;
282 bool is_one_or_minus_one(const Const
&value
, bool is_signed
, bool &is_negative
)
284 bool all_bits_one
= true;
285 bool last_bit_one
= true;
287 if (GetSize(value
.bits
) < 1)
290 if (GetSize(value
.bits
) == 1) {
291 if (value
.bits
[0] != State::S1
)
298 for (int i
= 0; i
< GetSize(value
.bits
); i
++) {
299 if (value
.bits
[i
] != State::S1
)
300 all_bits_one
= false;
301 if (value
.bits
[i
] != (i
? State::S0
: State::S1
))
302 last_bit_one
= false;
305 if (all_bits_one
&& is_signed
) {
313 int get_highest_hot_index(RTLIL::SigSpec signal
)
315 for (int i
= GetSize(signal
) - 1; i
>= 0; i
--)
317 if (signal
[i
] == RTLIL::State::S0
)
320 if (signal
[i
] == RTLIL::State::S1
)
329 // if the signal has only one bit set, return the index of that bit.
330 // otherwise return -1
331 int get_onehot_bit_index(RTLIL::SigSpec signal
)
335 for (int i
= 0; i
< GetSize(signal
); i
++)
337 if (signal
[i
] == RTLIL::State::S0
)
340 if (signal
[i
] != RTLIL::State::S1
)
352 void replace_const_cells(RTLIL::Design
*design
, RTLIL::Module
*module
, bool consume_x
, bool mux_undef
, bool mux_bool
, bool do_fine
, bool keepdc
, bool clkinv
)
354 if (!design
->selected(module
))
357 CellTypes ct_combinational
;
358 ct_combinational
.setup_internals();
359 ct_combinational
.setup_stdcells();
361 SigMap
assign_map(module
);
362 dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
364 TopoSort
<RTLIL::Cell
*, RTLIL::IdString::compare_ptr_by_name
<RTLIL::Cell
>> cells
;
365 dict
<RTLIL::Cell
*, std::set
<RTLIL::SigBit
>> cell_to_inbit
;
366 dict
<RTLIL::SigBit
, std::set
<RTLIL::Cell
*>> outbit_to_cell
;
368 for (auto cell
: module
->cells())
369 if (design
->selected(module
, cell
) && cell
->type
[0] == '$') {
370 if ((cell
->type
== "$_NOT_" || cell
->type
== "$not" || cell
->type
== "$logic_not") &&
371 cell
->getPort("\\A").size() == 1 && cell
->getPort("\\Y").size() == 1)
372 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\A"));
373 if ((cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\A") == SigSpec(State::S1
) && cell
->getPort("\\B") == SigSpec(State::S0
))
374 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\S"));
375 if (ct_combinational
.cell_known(cell
->type
))
376 for (auto &conn
: cell
->connections()) {
377 RTLIL::SigSpec sig
= assign_map(conn
.second
);
379 if (ct_combinational
.cell_input(cell
->type
, conn
.first
))
380 cell_to_inbit
[cell
].insert(sig
.begin(), sig
.end());
381 if (ct_combinational
.cell_output(cell
->type
, conn
.first
))
382 for (auto &bit
: sig
)
383 outbit_to_cell
[bit
].insert(cell
);
388 for (auto &it_right
: cell_to_inbit
)
389 for (auto &it_sigbit
: it_right
.second
)
390 for (auto &it_left
: outbit_to_cell
[it_sigbit
])
391 cells
.edge(it_left
, it_right
.first
);
395 for (auto cell
: cells
.sorted
)
397 #define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
398 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
402 if (cell
->type
.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
403 handle_polarity_inv(cell
, "\\CLK", "\\CLK_POLARITY", assign_map
, invert_map
);
405 if (cell
->type
.in("$sr", "$dffsr", "$dlatchsr")) {
406 handle_polarity_inv(cell
, "\\SET", "\\SET_POLARITY", assign_map
, invert_map
);
407 handle_polarity_inv(cell
, "\\CLR", "\\CLR_POLARITY", assign_map
, invert_map
);
410 if (cell
->type
.in("$dffe", "$dlatch", "$dlatchsr"))
411 handle_polarity_inv(cell
, "\\EN", "\\EN_POLARITY", assign_map
, invert_map
);
413 handle_clkpol_celltype_swap(cell
, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map
, invert_map
);
414 handle_clkpol_celltype_swap(cell
, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map
, invert_map
);
416 handle_clkpol_celltype_swap(cell
, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map
, invert_map
);
418 handle_clkpol_celltype_swap(cell
, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map
, invert_map
);
419 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map
, invert_map
);
421 handle_clkpol_celltype_swap(cell
, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map
, invert_map
);
422 handle_clkpol_celltype_swap(cell
, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map
, invert_map
);
424 handle_clkpol_celltype_swap(cell
, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map
, invert_map
);
425 handle_clkpol_celltype_swap(cell
, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map
, invert_map
);
426 handle_clkpol_celltype_swap(cell
, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map
, invert_map
);
428 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map
, invert_map
);
430 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map
, invert_map
);
431 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map
, invert_map
);
432 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map
, invert_map
);
435 bool detect_const_and
= false;
436 bool detect_const_or
= false;
438 if (cell
->type
.in("$reduce_and", "$_AND_"))
439 detect_const_and
= true;
441 if (cell
->type
.in("$and", "$logic_and") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
442 detect_const_and
= true;
444 if (cell
->type
.in("$reduce_or", "$reduce_bool", "$_OR_"))
445 detect_const_or
= true;
447 if (cell
->type
.in("$or", "$logic_or") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
448 detect_const_or
= true;
450 if (detect_const_and
|| detect_const_or
)
452 pool
<SigBit
> input_bits
= assign_map(cell
->getPort("\\A")).to_sigbit_pool();
453 bool found_zero
= false, found_one
= false, found_undef
= false, found_inv
= false, many_conconst
= false;
454 SigBit non_const_input
= State::Sm
;
456 if (cell
->hasPort("\\B")) {
457 vector
<SigBit
> more_bits
= assign_map(cell
->getPort("\\B")).to_sigbit_vector();
458 input_bits
.insert(more_bits
.begin(), more_bits
.end());
461 for (auto bit
: input_bits
) {
463 if (invert_map
.count(bit
) && input_bits
.count(invert_map
.at(bit
)))
465 if (non_const_input
!= State::Sm
)
466 many_conconst
= true;
467 non_const_input
= many_conconst
? State::Sm
: bit
;
469 if (bit
== State::S0
)
471 else if (bit
== State::S1
)
478 if (detect_const_and
&& (found_zero
|| found_inv
)) {
479 cover("opt.opt_expr.const_and");
480 replace_cell(assign_map
, module
, cell
, "const_and", "\\Y", RTLIL::State::S0
);
484 if (detect_const_or
&& (found_one
|| found_inv
)) {
485 cover("opt.opt_expr.const_or");
486 replace_cell(assign_map
, module
, cell
, "const_or", "\\Y", RTLIL::State::S1
);
490 if (non_const_input
!= State::Sm
&& !found_undef
) {
491 cover("opt.opt_expr.and_or_buffer");
492 replace_cell(assign_map
, module
, cell
, "and_or_buffer", "\\Y", non_const_input
);
497 if (cell
->type
.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
498 GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\Y")) == 1)
500 if (cell
->type
== "$reduce_xnor") {
501 cover("opt.opt_expr.reduce_xnor_not");
502 log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
503 log_id(cell
->type
), log_id(cell
->name
), log_id(module
));
505 did_something
= true;
507 cover("opt.opt_expr.unary_buffer");
508 replace_cell(assign_map
, module
, cell
, "unary_buffer", "\\Y", cell
->getPort("\\A"));
515 if (cell
->type
== "$not" || cell
->type
== "$pos" ||
516 cell
->type
== "$and" || cell
->type
== "$or" || cell
->type
== "$xor" || cell
->type
== "$xnor")
517 if (group_cell_inputs(module
, cell
, true, assign_map
))
520 if (cell
->type
== "$logic_not" || cell
->type
== "$logic_and" || cell
->type
== "$logic_or" ||
521 cell
->type
== "$reduce_or" || cell
->type
== "$reduce_and" || cell
->type
== "$reduce_bool")
523 SigBit neutral_bit
= cell
->type
== "$reduce_and" ? State::S1
: State::S0
;
525 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
526 RTLIL::SigSpec new_sig_a
;
528 for (auto bit
: sig_a
)
529 if (bit
!= neutral_bit
) new_sig_a
.append(bit
);
531 if (GetSize(new_sig_a
) == 0)
532 new_sig_a
.append(neutral_bit
);
534 if (GetSize(new_sig_a
) < GetSize(sig_a
)) {
535 cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell
->type
.str());
536 log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
537 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_sig_a
));
538 cell
->setPort("\\A", new_sig_a
);
539 cell
->parameters
.at("\\A_WIDTH") = GetSize(new_sig_a
);
540 did_something
= true;
544 if (cell
->type
== "$logic_and" || cell
->type
== "$logic_or")
546 SigBit neutral_bit
= State::S0
;
548 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
549 RTLIL::SigSpec new_sig_b
;
551 for (auto bit
: sig_b
)
552 if (bit
!= neutral_bit
) new_sig_b
.append(bit
);
554 if (GetSize(new_sig_b
) == 0)
555 new_sig_b
.append(neutral_bit
);
557 if (GetSize(new_sig_b
) < GetSize(sig_b
)) {
558 cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell
->type
.str());
559 log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
560 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_sig_b
));
561 cell
->setPort("\\B", new_sig_b
);
562 cell
->parameters
.at("\\B_WIDTH") = GetSize(new_sig_b
);
563 did_something
= true;
567 if (cell
->type
== "$reduce_and")
569 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
571 RTLIL::State new_a
= RTLIL::State::S1
;
572 for (auto &bit
: sig_a
.to_sigbit_vector())
573 if (bit
== RTLIL::State::Sx
) {
574 if (new_a
== RTLIL::State::S1
)
575 new_a
= RTLIL::State::Sx
;
576 } else if (bit
== RTLIL::State::S0
) {
577 new_a
= RTLIL::State::S0
;
579 } else if (bit
.wire
!= NULL
) {
580 new_a
= RTLIL::State::Sm
;
583 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
584 cover("opt.opt_expr.fine.$reduce_and");
585 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
586 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
587 cell
->setPort("\\A", sig_a
= new_a
);
588 cell
->parameters
.at("\\A_WIDTH") = 1;
589 did_something
= true;
593 if (cell
->type
== "$logic_not" || cell
->type
== "$logic_and" || cell
->type
== "$logic_or" || cell
->type
== "$reduce_or" || cell
->type
== "$reduce_bool")
595 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
597 RTLIL::State new_a
= RTLIL::State::S0
;
598 for (auto &bit
: sig_a
.to_sigbit_vector())
599 if (bit
== RTLIL::State::Sx
) {
600 if (new_a
== RTLIL::State::S0
)
601 new_a
= RTLIL::State::Sx
;
602 } else if (bit
== RTLIL::State::S1
) {
603 new_a
= RTLIL::State::S1
;
605 } else if (bit
.wire
!= NULL
) {
606 new_a
= RTLIL::State::Sm
;
609 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
610 cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell
->type
.str());
611 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
612 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
613 cell
->setPort("\\A", sig_a
= new_a
);
614 cell
->parameters
.at("\\A_WIDTH") = 1;
615 did_something
= true;
619 if (cell
->type
== "$logic_and" || cell
->type
== "$logic_or")
621 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
623 RTLIL::State new_b
= RTLIL::State::S0
;
624 for (auto &bit
: sig_b
.to_sigbit_vector())
625 if (bit
== RTLIL::State::Sx
) {
626 if (new_b
== RTLIL::State::S0
)
627 new_b
= RTLIL::State::Sx
;
628 } else if (bit
== RTLIL::State::S1
) {
629 new_b
= RTLIL::State::S1
;
631 } else if (bit
.wire
!= NULL
) {
632 new_b
= RTLIL::State::Sm
;
635 if (new_b
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_b
) != sig_b
) {
636 cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell
->type
.str());
637 log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
638 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_b
));
639 cell
->setPort("\\B", sig_b
= new_b
);
640 cell
->parameters
.at("\\B_WIDTH") = 1;
641 did_something
= true;
646 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" || cell
->type
== "$shift" || cell
->type
== "$shiftx" ||
647 cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" ||
648 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt" ||
649 cell
->type
== "$neg" || cell
->type
== "$add" || cell
->type
== "$sub" ||
650 cell
->type
== "$mul" || cell
->type
== "$div" || cell
->type
== "$mod" || cell
->type
== "$pow")
652 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
653 RTLIL::SigSpec sig_b
= cell
->hasPort("\\B") ? assign_map(cell
->getPort("\\B")) : RTLIL::SigSpec();
655 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" || cell
->type
== "$shift" || cell
->type
== "$shiftx")
656 sig_a
= RTLIL::SigSpec();
658 for (auto &bit
: sig_a
.to_sigbit_vector())
659 if (bit
== RTLIL::State::Sx
)
660 goto found_the_x_bit
;
662 for (auto &bit
: sig_b
.to_sigbit_vector())
663 if (bit
== RTLIL::State::Sx
)
664 goto found_the_x_bit
;
668 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
669 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell
->type
.str());
670 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" ||
671 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt")
672 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::State::Sx
);
674 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx
, cell
->getPort("\\Y").size()));
679 if ((cell
->type
== "$_NOT_" || cell
->type
== "$not" || cell
->type
== "$logic_not") && cell
->getPort("\\Y").size() == 1 &&
680 invert_map
.count(assign_map(cell
->getPort("\\A"))) != 0) {
681 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell
->type
.str());
682 replace_cell(assign_map
, module
, cell
, "double_invert", "\\Y", invert_map
.at(assign_map(cell
->getPort("\\A"))));
686 if ((cell
->type
== "$_MUX_" || cell
->type
== "$mux") && invert_map
.count(assign_map(cell
->getPort("\\S"))) != 0) {
687 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell
->type
.str());
688 log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
689 RTLIL::SigSpec tmp
= cell
->getPort("\\A");
690 cell
->setPort("\\A", cell
->getPort("\\B"));
691 cell
->setPort("\\B", tmp
);
692 cell
->setPort("\\S", invert_map
.at(assign_map(cell
->getPort("\\S"))));
693 did_something
= true;
697 if (cell
->type
== "$_NOT_") {
698 RTLIL::SigSpec input
= cell
->getPort("\\A");
699 assign_map
.apply(input
);
700 if (input
.match("1")) ACTION_DO_Y(0);
701 if (input
.match("0")) ACTION_DO_Y(1);
702 if (input
.match("*")) ACTION_DO_Y(x
);
705 if (cell
->type
== "$_AND_") {
706 RTLIL::SigSpec input
;
707 input
.append(cell
->getPort("\\B"));
708 input
.append(cell
->getPort("\\A"));
709 assign_map
.apply(input
);
710 if (input
.match(" 0")) ACTION_DO_Y(0);
711 if (input
.match("0 ")) ACTION_DO_Y(0);
712 if (input
.match("11")) ACTION_DO_Y(1);
713 if (input
.match("**")) ACTION_DO_Y(x
);
714 if (input
.match("1*")) ACTION_DO_Y(x
);
715 if (input
.match("*1")) ACTION_DO_Y(x
);
717 if (input
.match(" *")) ACTION_DO_Y(0);
718 if (input
.match("* ")) ACTION_DO_Y(0);
720 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
721 if (input
.match("1 ")) ACTION_DO("\\Y", input
.extract(0, 1));
724 if (cell
->type
== "$_OR_") {
725 RTLIL::SigSpec input
;
726 input
.append(cell
->getPort("\\B"));
727 input
.append(cell
->getPort("\\A"));
728 assign_map
.apply(input
);
729 if (input
.match(" 1")) ACTION_DO_Y(1);
730 if (input
.match("1 ")) ACTION_DO_Y(1);
731 if (input
.match("00")) ACTION_DO_Y(0);
732 if (input
.match("**")) ACTION_DO_Y(x
);
733 if (input
.match("0*")) ACTION_DO_Y(x
);
734 if (input
.match("*0")) ACTION_DO_Y(x
);
736 if (input
.match(" *")) ACTION_DO_Y(1);
737 if (input
.match("* ")) ACTION_DO_Y(1);
739 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
740 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
743 if (cell
->type
== "$_XOR_") {
744 RTLIL::SigSpec input
;
745 input
.append(cell
->getPort("\\B"));
746 input
.append(cell
->getPort("\\A"));
747 assign_map
.apply(input
);
748 if (input
.match("00")) ACTION_DO_Y(0);
749 if (input
.match("01")) ACTION_DO_Y(1);
750 if (input
.match("10")) ACTION_DO_Y(1);
751 if (input
.match("11")) ACTION_DO_Y(0);
752 if (input
.match(" *")) ACTION_DO_Y(x
);
753 if (input
.match("* ")) ACTION_DO_Y(x
);
754 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
755 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
758 if (cell
->type
== "$_MUX_") {
759 RTLIL::SigSpec input
;
760 input
.append(cell
->getPort("\\S"));
761 input
.append(cell
->getPort("\\B"));
762 input
.append(cell
->getPort("\\A"));
763 assign_map
.apply(input
);
764 if (input
.extract(2, 1) == input
.extract(1, 1))
765 ACTION_DO("\\Y", input
.extract(2, 1));
766 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(2, 1));
767 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
768 if (input
.match("01 ")) ACTION_DO("\\Y", input
.extract(0, 1));
769 if (input
.match("10 ")) {
770 cover("opt.opt_expr.mux_to_inv");
771 cell
->type
= "$_NOT_";
772 cell
->setPort("\\A", input
.extract(0, 1));
773 cell
->unsetPort("\\B");
774 cell
->unsetPort("\\S");
777 if (input
.match("11 ")) ACTION_DO_Y(1);
778 if (input
.match("00 ")) ACTION_DO_Y(0);
779 if (input
.match("** ")) ACTION_DO_Y(x
);
780 if (input
.match("01*")) ACTION_DO_Y(x
);
781 if (input
.match("10*")) ACTION_DO_Y(x
);
783 if (input
.match("* ")) ACTION_DO("\\Y", input
.extract(1, 1));
784 if (input
.match(" * ")) ACTION_DO("\\Y", input
.extract(2, 1));
785 if (input
.match(" *")) ACTION_DO("\\Y", input
.extract(2, 1));
789 if (cell
->type
== "$_TBUF_" || cell
->type
== "$tribuf") {
790 RTLIL::SigSpec input
= cell
->getPort(cell
->type
== "$_TBUF_" ? "\\E" : "\\EN");
791 RTLIL::SigSpec a
= cell
->getPort("\\A");
792 assign_map
.apply(input
);
794 if (input
== State::S1
)
795 ACTION_DO("\\Y", cell
->getPort("\\A"));
796 if (input
== State::S0
&& !a
.is_fully_undef()) {
797 cover("opt.opt_expr.action_" S__LINE__
);
798 log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
799 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str());
800 cell
->setPort("\\A", SigSpec(State::Sx
, GetSize(a
)));
801 did_something
= true;
806 if (cell
->type
== "$eq" || cell
->type
== "$ne" || cell
->type
== "$eqx" || cell
->type
== "$nex")
808 RTLIL::SigSpec a
= cell
->getPort("\\A");
809 RTLIL::SigSpec b
= cell
->getPort("\\B");
811 if (cell
->parameters
["\\A_WIDTH"].as_int() != cell
->parameters
["\\B_WIDTH"].as_int()) {
812 int width
= max(cell
->parameters
["\\A_WIDTH"].as_int(), cell
->parameters
["\\B_WIDTH"].as_int());
813 a
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
814 b
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
817 RTLIL::SigSpec new_a
, new_b
;
819 log_assert(GetSize(a
) == GetSize(b
));
820 for (int i
= 0; i
< GetSize(a
); i
++) {
821 if (a
[i
].wire
== NULL
&& b
[i
].wire
== NULL
&& a
[i
] != b
[i
] && a
[i
].data
<= RTLIL::State::S1
&& b
[i
].data
<= RTLIL::State::S1
) {
822 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
823 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S0
: RTLIL::State::S1
);
824 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
825 replace_cell(assign_map
, module
, cell
, "isneq", "\\Y", new_y
);
834 if (new_a
.size() == 0) {
835 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
836 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S1
: RTLIL::State::S0
);
837 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
838 replace_cell(assign_map
, module
, cell
, "empty", "\\Y", new_y
);
842 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
843 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
844 cell
->setPort("\\A", new_a
);
845 cell
->setPort("\\B", new_b
);
846 cell
->parameters
["\\A_WIDTH"] = new_a
.size();
847 cell
->parameters
["\\B_WIDTH"] = new_b
.size();
851 if ((cell
->type
== "$eq" || cell
->type
== "$ne") && cell
->parameters
["\\Y_WIDTH"].as_int() == 1 &&
852 cell
->parameters
["\\A_WIDTH"].as_int() == 1 && cell
->parameters
["\\B_WIDTH"].as_int() == 1)
854 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
855 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
857 if (a
.is_fully_const() && !b
.is_fully_const()) {
858 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell
->type
.str());
859 cell
->setPort("\\A", b
);
860 cell
->setPort("\\B", a
);
864 if (b
.is_fully_const()) {
865 if (b
.as_bool() == (cell
->type
== "$eq")) {
866 RTLIL::SigSpec input
= b
;
867 ACTION_DO("\\Y", cell
->getPort("\\A"));
869 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell
->type
.str());
870 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
872 cell
->parameters
.erase("\\B_WIDTH");
873 cell
->parameters
.erase("\\B_SIGNED");
874 cell
->unsetPort("\\B");
875 did_something
= true;
881 if ((cell
->type
== "$eq" || cell
->type
== "$ne") &&
882 (assign_map(cell
->getPort("\\A")).is_fully_zero() || assign_map(cell
->getPort("\\B")).is_fully_zero()))
884 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell
->type
.str());
885 log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell
->type
), log_id(cell
),
886 log_id(module
), "$eq" ? "$logic_not" : "$reduce_bool");
887 cell
->type
= cell
->type
== "$eq" ? "$logic_not" : "$reduce_bool";
888 if (assign_map(cell
->getPort("\\A")).is_fully_zero()) {
889 cell
->setPort("\\A", cell
->getPort("\\B"));
890 cell
->setParam("\\A_SIGNED", cell
->getParam("\\B_SIGNED"));
891 cell
->setParam("\\A_WIDTH", cell
->getParam("\\B_WIDTH"));
893 cell
->unsetPort("\\B");
894 cell
->unsetParam("\\B_SIGNED");
895 cell
->unsetParam("\\B_WIDTH");
896 did_something
= true;
900 if (cell
->type
.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell
->getPort("\\B")).is_fully_const())
902 bool sign_ext
= cell
->type
== "$sshr" && cell
->getParam("\\A_SIGNED").as_bool();
903 int shift_bits
= assign_map(cell
->getPort("\\B")).as_int(cell
->type
.in("$shift", "$shiftx") && cell
->getParam("\\B_SIGNED").as_bool());
905 if (cell
->type
.in("$shl", "$sshl"))
908 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
909 RTLIL::SigSpec
sig_y(cell
->type
== "$shiftx" ? RTLIL::State::Sx
: RTLIL::State::S0
, cell
->getParam("\\Y_WIDTH").as_int());
911 if (GetSize(sig_a
) < GetSize(sig_y
))
912 sig_a
.extend_u0(GetSize(sig_y
), cell
->getParam("\\A_SIGNED").as_bool());
914 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
915 int idx
= i
+ shift_bits
;
916 if (0 <= idx
&& idx
< GetSize(sig_a
))
917 sig_y
[i
] = sig_a
[idx
];
918 else if (GetSize(sig_a
) <= idx
&& sign_ext
)
919 sig_y
[i
] = sig_a
[GetSize(sig_a
)-1];
922 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell
->type
.str());
924 log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
925 log_id(cell
->type
), log_id(cell
), log_signal(assign_map(cell
->getPort("\\B"))), shift_bits
, log_id(module
), log_signal(sig_y
));
927 module
->connect(cell
->getPort("\\Y"), sig_y
);
928 module
->remove(cell
);
930 did_something
= true;
936 bool identity_wrt_a
= false;
937 bool identity_wrt_b
= false;
938 bool arith_inverse
= false;
940 if (cell
->type
== "$add" || cell
->type
== "$sub" || cell
->type
== "$or" || cell
->type
== "$xor")
942 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
943 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
945 if (cell
->type
!= "$sub" && a
.is_fully_const() && a
.as_bool() == false)
946 identity_wrt_b
= true;
948 if (b
.is_fully_const() && b
.as_bool() == false)
949 identity_wrt_a
= true;
952 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" || cell
->type
== "$shift" || cell
->type
== "$shiftx")
954 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
956 if (b
.is_fully_const() && b
.as_bool() == false)
957 identity_wrt_a
= true;
960 if (cell
->type
== "$mul")
962 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
963 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
965 if (a
.is_fully_const() && is_one_or_minus_one(a
.as_const(), cell
->getParam("\\A_SIGNED").as_bool(), arith_inverse
))
966 identity_wrt_b
= true;
968 if (b
.is_fully_const() && is_one_or_minus_one(b
.as_const(), cell
->getParam("\\B_SIGNED").as_bool(), arith_inverse
))
969 identity_wrt_a
= true;
972 if (cell
->type
== "$div")
974 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
976 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
977 identity_wrt_a
= true;
980 if (identity_wrt_a
|| identity_wrt_b
)
983 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
985 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
987 log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
988 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
990 if (!identity_wrt_a
) {
991 cell
->setPort("\\A", cell
->getPort("\\B"));
992 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
993 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
996 cell
->type
= arith_inverse
? "$neg" : "$pos";
997 cell
->unsetPort("\\B");
998 cell
->parameters
.erase("\\B_WIDTH");
999 cell
->parameters
.erase("\\B_SIGNED");
1002 did_something
= true;
1007 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
1008 cell
->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell
->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
1009 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell
->type
.str());
1010 replace_cell(assign_map
, module
, cell
, "mux_bool", "\\Y", cell
->getPort("\\S"));
1014 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
1015 cell
->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell
->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
1016 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell
->type
.str());
1017 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1018 cell
->setPort("\\A", cell
->getPort("\\S"));
1019 cell
->unsetPort("\\B");
1020 cell
->unsetPort("\\S");
1021 if (cell
->type
== "$mux") {
1022 Const width
= cell
->parameters
["\\WIDTH"];
1023 cell
->parameters
["\\A_WIDTH"] = width
;
1024 cell
->parameters
["\\Y_WIDTH"] = width
;
1025 cell
->parameters
["\\A_SIGNED"] = 0;
1026 cell
->parameters
.erase("\\WIDTH");
1027 cell
->type
= "$not";
1029 cell
->type
= "$_NOT_";
1030 did_something
= true;
1034 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
1035 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell
->type
.str());
1036 log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1037 cell
->setPort("\\A", cell
->getPort("\\S"));
1038 cell
->unsetPort("\\S");
1039 if (cell
->type
== "$mux") {
1040 Const width
= cell
->parameters
["\\WIDTH"];
1041 cell
->parameters
["\\A_WIDTH"] = width
;
1042 cell
->parameters
["\\B_WIDTH"] = width
;
1043 cell
->parameters
["\\Y_WIDTH"] = width
;
1044 cell
->parameters
["\\A_SIGNED"] = 0;
1045 cell
->parameters
["\\B_SIGNED"] = 0;
1046 cell
->parameters
.erase("\\WIDTH");
1047 cell
->type
= "$and";
1049 cell
->type
= "$_AND_";
1050 did_something
= true;
1054 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
1055 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell
->type
.str());
1056 log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1057 cell
->setPort("\\B", cell
->getPort("\\S"));
1058 cell
->unsetPort("\\S");
1059 if (cell
->type
== "$mux") {
1060 Const width
= cell
->parameters
["\\WIDTH"];
1061 cell
->parameters
["\\A_WIDTH"] = width
;
1062 cell
->parameters
["\\B_WIDTH"] = width
;
1063 cell
->parameters
["\\Y_WIDTH"] = width
;
1064 cell
->parameters
["\\A_SIGNED"] = 0;
1065 cell
->parameters
["\\B_SIGNED"] = 0;
1066 cell
->parameters
.erase("\\WIDTH");
1069 cell
->type
= "$_OR_";
1070 did_something
= true;
1074 if (mux_undef
&& (cell
->type
== "$mux" || cell
->type
== "$pmux")) {
1075 RTLIL::SigSpec new_a
, new_b
, new_s
;
1076 int width
= cell
->getPort("\\A").size();
1077 if ((cell
->getPort("\\A").is_fully_undef() && cell
->getPort("\\B").is_fully_undef()) ||
1078 cell
->getPort("\\S").is_fully_undef()) {
1079 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell
->type
.str());
1080 replace_cell(assign_map
, module
, cell
, "mux_undef", "\\Y", cell
->getPort("\\A"));
1083 for (int i
= 0; i
< cell
->getPort("\\S").size(); i
++) {
1084 RTLIL::SigSpec old_b
= cell
->getPort("\\B").extract(i
*width
, width
);
1085 RTLIL::SigSpec old_s
= cell
->getPort("\\S").extract(i
, 1);
1086 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
1088 new_b
.append(old_b
);
1089 new_s
.append(old_s
);
1091 new_a
= cell
->getPort("\\A");
1092 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
1093 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
1094 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
1095 new_s
= new_s
.extract(0, new_s
.size()-1);
1097 if (new_s
.size() == 0) {
1098 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell
->type
.str());
1099 replace_cell(assign_map
, module
, cell
, "mux_empty", "\\Y", new_a
);
1102 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
1103 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell
->type
.str());
1104 replace_cell(assign_map
, module
, cell
, "mux_sel01", "\\Y", new_s
);
1107 if (cell
->getPort("\\S").size() != new_s
.size()) {
1108 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell
->type
.str());
1109 log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1110 GetSize(cell
->getPort("\\S")) - GetSize(new_s
), log_id(cell
->type
), log_id(cell
), log_id(module
));
1111 cell
->setPort("\\A", new_a
);
1112 cell
->setPort("\\B", new_b
);
1113 cell
->setPort("\\S", new_s
);
1114 if (new_s
.size() > 1) {
1115 cell
->type
= "$pmux";
1116 cell
->parameters
["\\S_WIDTH"] = new_s
.size();
1118 cell
->type
= "$mux";
1119 cell
->parameters
.erase("\\S_WIDTH");
1121 did_something
= true;
1125 #define FOLD_1ARG_CELL(_t) \
1126 if (cell->type == "$" #_t) { \
1127 RTLIL::SigSpec a = cell->getPort("\\A"); \
1128 assign_map.apply(a); \
1129 if (a.is_fully_const()) { \
1130 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1131 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1132 cell->parameters["\\A_SIGNED"].as_bool(), false, \
1133 cell->parameters["\\Y_WIDTH"].as_int())); \
1134 cover("opt.opt_expr.const.$" #_t); \
1135 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
1139 #define FOLD_2ARG_CELL(_t) \
1140 if (cell->type == "$" #_t) { \
1141 RTLIL::SigSpec a = cell->getPort("\\A"); \
1142 RTLIL::SigSpec b = cell->getPort("\\B"); \
1143 assign_map.apply(a), assign_map.apply(b); \
1144 if (a.is_fully_const() && b.is_fully_const()) { \
1145 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1146 cell->parameters["\\A_SIGNED"].as_bool(), \
1147 cell->parameters["\\B_SIGNED"].as_bool(), \
1148 cell->parameters["\\Y_WIDTH"].as_int())); \
1149 cover("opt.opt_expr.const.$" #_t); \
1150 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
1159 FOLD_2ARG_CELL(xnor
)
1161 FOLD_1ARG_CELL(reduce_and
)
1162 FOLD_1ARG_CELL(reduce_or
)
1163 FOLD_1ARG_CELL(reduce_xor
)
1164 FOLD_1ARG_CELL(reduce_xnor
)
1165 FOLD_1ARG_CELL(reduce_bool
)
1167 FOLD_1ARG_CELL(logic_not
)
1168 FOLD_2ARG_CELL(logic_and
)
1169 FOLD_2ARG_CELL(logic_or
)
1173 FOLD_2ARG_CELL(sshl
)
1174 FOLD_2ARG_CELL(sshr
)
1175 FOLD_2ARG_CELL(shift
)
1176 FOLD_2ARG_CELL(shiftx
)
1195 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1196 if (cell
->type
== "$mux") {
1197 RTLIL::SigSpec input
= assign_map(cell
->getPort("\\S"));
1198 RTLIL::SigSpec inA
= assign_map(cell
->getPort("\\A"));
1199 RTLIL::SigSpec inB
= assign_map(cell
->getPort("\\B"));
1200 if (input
.is_fully_const())
1201 ACTION_DO("\\Y", input
.as_bool() ? cell
->getPort("\\B") : cell
->getPort("\\A"));
1202 else if (inA
== inB
)
1203 ACTION_DO("\\Y", cell
->getPort("\\A"));
1206 if (!keepdc
&& cell
->type
== "$mul")
1208 bool a_signed
= cell
->parameters
["\\A_SIGNED"].as_bool();
1209 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1210 bool swapped_ab
= false;
1212 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
1213 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1214 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1216 if (sig_b
.is_fully_const() && sig_b
.size() <= 32)
1217 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
1219 if (sig_a
.is_fully_def() && sig_a
.size() <= 32)
1221 int a_val
= sig_a
.as_int();
1225 cover("opt.opt_expr.mul_shift.zero");
1227 log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1228 cell
->name
.c_str(), module
->name
.c_str());
1230 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
1231 module
->remove(cell
);
1233 did_something
= true;
1237 for (int i
= 1; i
< (a_signed
? sig_a
.size()-1 : sig_a
.size()); i
++)
1238 if (a_val
== (1 << i
))
1241 cover("opt.opt_expr.mul_shift.swapped");
1243 cover("opt.opt_expr.mul_shift.unswapped");
1245 log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1246 a_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1249 cell
->setPort("\\A", cell
->getPort("\\B"));
1250 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
1251 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
1254 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1256 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1259 cell
->type
= "$shl";
1260 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1261 cell
->parameters
["\\B_SIGNED"] = false;
1262 cell
->setPort("\\B", new_b
);
1265 did_something
= true;
1271 if (!keepdc
&& cell
->type
.in("$div", "$mod"))
1273 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1274 SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1275 SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1277 if (sig_b
.is_fully_def() && sig_b
.size() <= 32)
1279 int b_val
= sig_b
.as_int();
1283 cover("opt.opt_expr.divmod_zero");
1285 log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1286 cell
->name
.c_str(), module
->name
.c_str());
1288 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(State::Sx
, sig_y
.size())));
1289 module
->remove(cell
);
1291 did_something
= true;
1295 for (int i
= 1; i
< (b_signed
? sig_b
.size()-1 : sig_b
.size()); i
++)
1296 if (b_val
== (1 << i
))
1298 if (cell
->type
== "$div")
1300 cover("opt.opt_expr.div_shift");
1302 log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1303 b_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1305 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1307 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1310 cell
->type
= "$shr";
1311 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1312 cell
->parameters
["\\B_SIGNED"] = false;
1313 cell
->setPort("\\B", new_b
);
1318 cover("opt.opt_expr.mod_mask");
1320 log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
1321 b_val
, cell
->name
.c_str(), module
->name
.c_str());
1323 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(State::S1
, i
);
1326 new_b
.push_back(State::S0
);
1328 cell
->type
= "$and";
1329 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1330 cell
->setPort("\\B", new_b
);
1334 did_something
= true;
1340 // remove redundant pairs of bits in ==, ===, !=, and !==
1341 // replace cell with const driver if inputs can't be equal
1342 if (do_fine
&& cell
->type
.in("$eq", "$ne", "$eqx", "$nex"))
1344 pool
<pair
<SigBit
, SigBit
>> redundant_cache
;
1345 mfp
<SigBit
> contradiction_cache
;
1347 contradiction_cache
.promote(State::S0
);
1348 contradiction_cache
.promote(State::S1
);
1350 int a_width
= cell
->getParam("\\A_WIDTH").as_int();
1351 int b_width
= cell
->getParam("\\B_WIDTH").as_int();
1353 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
1354 int width
= is_signed
? std::min(a_width
, b_width
) : std::max(a_width
, b_width
);
1356 SigSpec sig_a
= cell
->getPort("\\A");
1357 SigSpec sig_b
= cell
->getPort("\\B");
1359 int redundant_bits
= 0;
1361 for (int i
= width
-1; i
>= 0; i
--)
1363 SigBit bit_a
= i
< a_width
? assign_map(sig_a
[i
]) : State::S0
;
1364 SigBit bit_b
= i
< b_width
? assign_map(sig_b
[i
]) : State::S0
;
1366 if (bit_a
!= State::Sx
&& bit_a
!= State::Sz
&&
1367 bit_b
!= State::Sx
&& bit_b
!= State::Sz
)
1368 contradiction_cache
.merge(bit_a
, bit_b
);
1371 std::swap(bit_a
, bit_b
);
1373 pair
<SigBit
, SigBit
> key(bit_a
, bit_b
);
1375 if (redundant_cache
.count(key
)) {
1376 if (i
< a_width
) sig_a
.remove(i
);
1377 if (i
< b_width
) sig_b
.remove(i
);
1382 redundant_cache
.insert(key
);
1385 if (contradiction_cache
.find(State::S0
) == contradiction_cache
.find(State::S1
))
1387 SigSpec y_sig
= cell
->getPort("\\Y");
1388 Const
y_value(cell
->type
.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig
));
1390 log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
1391 log_id(cell
), log_id(module
), log_signal(y_value
));
1393 module
->connect(y_sig
, y_value
);
1394 module
->remove(cell
);
1396 did_something
= true;
1402 log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
1403 redundant_bits
, log_id(cell
->type
), log_id(cell
), log_id(module
));
1405 cell
->setPort("\\A", sig_a
);
1406 cell
->setPort("\\B", sig_b
);
1407 cell
->setParam("\\A_WIDTH", GetSize(sig_a
));
1408 cell
->setParam("\\B_WIDTH", GetSize(sig_b
));
1410 did_something
= true;
1415 // simplify comparisons
1416 if (do_fine
&& (cell
->type
== "$lt" || cell
->type
== "$ge" || cell
->type
== "$gt" || cell
->type
== "$le"))
1418 IdString cmp_type
= cell
->type
;
1419 SigSpec var_sig
= cell
->getPort("\\A");
1420 SigSpec const_sig
= cell
->getPort("\\B");
1421 int var_width
= cell
->parameters
["\\A_WIDTH"].as_int();
1422 int const_width
= cell
->parameters
["\\B_WIDTH"].as_int();
1423 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
1425 if (!const_sig
.is_fully_const())
1427 std::swap(var_sig
, const_sig
);
1428 std::swap(var_width
, const_width
);
1429 if (cmp_type
== "$gt")
1431 else if (cmp_type
== "$lt")
1433 else if (cmp_type
== "$ge")
1435 else if (cmp_type
== "$le")
1439 if (const_sig
.is_fully_def() && const_sig
.is_fully_const())
1441 std::string condition
, replacement
;
1442 SigSpec
replace_sig(State::S0
, GetSize(cell
->getPort("\\Y")));
1443 bool replace
= false;
1444 bool remove
= false;
1448 if (const_sig
.is_fully_zero() && cmp_type
== "$lt") {
1449 condition
= "unsigned X<0";
1450 replacement
= "constant 0";
1451 replace_sig
[0] = State::S0
;
1454 if (const_sig
.is_fully_zero() && cmp_type
== "$ge") {
1455 condition
= "unsigned X>=0";
1456 replacement
= "constant 1";
1457 replace_sig
[0] = State::S1
;
1460 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== "$gt") {
1461 condition
= "unsigned X>~0";
1462 replacement
= "constant 0";
1463 replace_sig
[0] = State::S0
;
1466 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== "$le") {
1467 condition
= "unsigned X<=~0";
1468 replacement
= "constant 1";
1469 replace_sig
[0] = State::S1
;
1473 int const_bit_hot
= get_onehot_bit_index(const_sig
);
1474 if (const_bit_hot
>= 0 && const_bit_hot
< var_width
)
1476 RTLIL::SigSpec
var_high_sig(RTLIL::State::S0
, var_width
- const_bit_hot
);
1477 for (int i
= const_bit_hot
; i
< var_width
; i
++) {
1478 var_high_sig
[i
- const_bit_hot
] = var_sig
[i
];
1481 if (cmp_type
== "$lt")
1483 condition
= stringf("unsigned X<%s", log_signal(const_sig
));
1484 replacement
= stringf("!X[%d:%d]", var_width
- 1, const_bit_hot
);
1485 module
->addLogicNot(NEW_ID
, var_high_sig
, cell
->getPort("\\Y"));
1488 if (cmp_type
== "$ge")
1490 condition
= stringf("unsigned X>=%s", log_signal(const_sig
));
1491 replacement
= stringf("|X[%d:%d]", var_width
- 1, const_bit_hot
);
1492 module
->addReduceOr(NEW_ID
, var_high_sig
, cell
->getPort("\\Y"));
1497 int const_bit_set
= get_highest_hot_index(const_sig
);
1498 if(const_bit_set
>= var_width
)
1501 if (cmp_type
== "$lt" || cmp_type
== "$le")
1503 if (cmp_type
== "$lt") cmp_name
= "<";
1504 if (cmp_type
== "$le") cmp_name
= "<=";
1505 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1506 replacement
= "constant 1";
1507 replace_sig
[0] = State::S1
;
1510 if (cmp_type
== "$gt" || cmp_type
== "$ge")
1512 if (cmp_type
== "$gt") cmp_name
= ">";
1513 if (cmp_type
== "$ge") cmp_name
= ">=";
1514 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1515 replacement
= "constant 0";
1516 replace_sig
[0] = State::S0
;
1523 if (const_sig
.is_fully_zero() && cmp_type
== "$lt")
1525 condition
= "signed X<0";
1526 replacement
= stringf("X[%d]", var_width
- 1);
1527 replace_sig
[0] = var_sig
[var_width
- 1];
1530 if (const_sig
.is_fully_zero() && cmp_type
== "$ge")
1532 condition
= "signed X>=0";
1533 replacement
= stringf("X[%d]", var_width
- 1);
1534 module
->addNot(NEW_ID
, var_sig
[var_width
- 1], cell
->getPort("\\Y"));
1539 if (replace
|| remove
)
1541 log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
1542 log_id(cell
->type
), log_id(cell
), condition
.c_str(), replacement
.c_str());
1544 module
->connect(cell
->getPort("\\Y"), replace_sig
);
1545 module
->remove(cell
);
1546 did_something
= true;
1555 #undef FOLD_1ARG_CELL
1556 #undef FOLD_2ARG_CELL
1560 struct OptExprPass
: public Pass
{
1561 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
1562 void help() YS_OVERRIDE
1564 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1566 log(" opt_expr [options] [selection]\n");
1568 log("This pass performs const folding on internal cell types with constant inputs.\n");
1569 log("It also performs some simple expression rewriting.\n");
1571 log(" -mux_undef\n");
1572 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
1574 log(" -mux_bool\n");
1575 log(" replace $mux cells with inverters or buffers when possible\n");
1577 log(" -undriven\n");
1578 log(" replace undriven nets with undef (x) constants\n");
1581 log(" optimize clock inverters by changing FF types\n");
1584 log(" perform fine-grain optimizations\n");
1587 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
1590 log(" some optimizations change the behavior of the circuit with respect to\n");
1591 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
1592 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
1593 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
1596 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1598 bool mux_undef
= false;
1599 bool mux_bool
= false;
1600 bool undriven
= false;
1601 bool clkinv
= false;
1602 bool do_fine
= false;
1603 bool keepdc
= false;
1605 log_header(design
, "Executing OPT_EXPR pass (perform const folding).\n");
1609 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1610 if (args
[argidx
] == "-mux_undef") {
1614 if (args
[argidx
] == "-mux_bool") {
1618 if (args
[argidx
] == "-undriven") {
1622 if (args
[argidx
] == "-clkinv") {
1626 if (args
[argidx
] == "-fine") {
1630 if (args
[argidx
] == "-full") {
1637 if (args
[argidx
] == "-keepdc") {
1643 extra_args(args
, argidx
, design
);
1645 for (auto module
: design
->selected_modules())
1647 log("Optimizing module %s.\n", log_id(module
));
1650 did_something
= false;
1651 replace_undriven(design
, module
);
1653 design
->scratchpad_set_bool("opt.did_something", true);
1658 did_something
= false;
1659 replace_const_cells(design
, module
, false, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1661 design
->scratchpad_set_bool("opt.did_something", true);
1662 } while (did_something
);
1663 replace_const_cells(design
, module
, true, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1665 design
->scratchpad_set_bool("opt.did_something", true);
1666 } while (did_something
);
1675 PRIVATE_NAMESPACE_END