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
,
121 const std::string
&info
YS_ATTRIBUTE(unused
), IdString out_port
, RTLIL::SigSpec out_val
)
123 RTLIL::SigSpec Y
= cell
->getPort(out_port
);
124 out_val
.extend_u0(Y
.size(), false);
126 log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
127 cell
->type
.c_str(), cell
->name
.c_str(), info
.c_str(),
128 module
->name
.c_str(), log_signal(Y
), log_signal(out_val
));
130 assign_map
.add(Y
, out_val
);
131 module
->connect(Y
, out_val
);
132 module
->remove(cell
);
133 did_something
= true;
136 bool group_cell_inputs(RTLIL::Module
*module
, RTLIL::Cell
*cell
, bool commutative
, SigMap
&sigmap
)
138 std::string b_name
= cell
->hasPort("\\B") ? "\\B" : "\\A";
140 bool a_signed
= cell
->parameters
.at("\\A_SIGNED").as_bool();
141 bool b_signed
= cell
->parameters
.at(b_name
+ "_SIGNED").as_bool();
143 RTLIL::SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
144 RTLIL::SigSpec sig_b
= sigmap(cell
->getPort(b_name
));
145 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
147 sig_a
.extend_u0(sig_y
.size(), a_signed
);
148 sig_b
.extend_u0(sig_y
.size(), b_signed
);
150 std::vector
<RTLIL::SigBit
> bits_a
= sig_a
, bits_b
= sig_b
, bits_y
= sig_y
;
152 enum { GRP_DYN
, GRP_CONST_A
, GRP_CONST_B
, GRP_CONST_AB
, GRP_N
};
153 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::set
<RTLIL::SigBit
>> grouped_bits
[GRP_N
];
155 for (int i
= 0; i
< GetSize(bits_y
); i
++)
157 int group_idx
= GRP_DYN
;
158 RTLIL::SigBit bit_a
= bits_a
[i
], bit_b
= bits_b
[i
];
160 if (cell
->type
== "$or" && (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
))
161 bit_a
= bit_b
= RTLIL::State::S1
;
163 if (cell
->type
== "$and" && (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
))
164 bit_a
= bit_b
= RTLIL::State::S0
;
166 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
167 group_idx
= GRP_CONST_AB
;
168 else if (bit_a
.wire
== NULL
)
169 group_idx
= GRP_CONST_A
;
170 else if (bit_b
.wire
== NULL
&& commutative
)
171 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
172 else if (bit_b
.wire
== NULL
)
173 group_idx
= GRP_CONST_B
;
175 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
178 for (int i
= 0; i
< GRP_N
; i
++)
179 if (GetSize(grouped_bits
[i
]) == GetSize(bits_y
))
182 log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
183 log_id(cell
->type
), log_id(cell
), log_id(module
));
185 for (int i
= 0; i
< GRP_N
; i
++)
187 if (grouped_bits
[i
].empty())
190 RTLIL::Wire
*new_y
= module
->addWire(NEW_ID
, GetSize(grouped_bits
[i
]));
191 RTLIL::SigSpec new_a
, new_b
;
192 RTLIL::SigSig new_conn
;
194 for (auto &it
: grouped_bits
[i
]) {
195 for (auto &bit
: it
.second
) {
196 new_conn
.first
.append_bit(bit
);
197 new_conn
.second
.append_bit(RTLIL::SigBit(new_y
, new_a
.size()));
199 new_a
.append_bit(it
.first
.first
);
200 new_b
.append_bit(it
.first
.second
);
203 if (cell
->type
.in("$and", "$or") && i
== GRP_CONST_A
) {
204 log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b
), log_id(cell
->type
), log_signal(new_a
));
205 module
->connect(new_y
, new_b
);
206 module
->connect(new_conn
);
210 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
212 c
->setPort("\\A", new_a
);
213 c
->parameters
["\\A_WIDTH"] = new_a
.size();
214 c
->parameters
["\\A_SIGNED"] = false;
216 if (b_name
== "\\B") {
217 c
->setPort("\\B", new_b
);
218 c
->parameters
["\\B_WIDTH"] = new_b
.size();
219 c
->parameters
["\\B_SIGNED"] = false;
222 c
->setPort("\\Y", new_y
);
223 c
->parameters
["\\Y_WIDTH"] = new_y
->width
;
226 module
->connect(new_conn
);
228 log_debug(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
230 log_debug(", B=%s", log_signal(new_b
));
234 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell
->type
.str());
236 module
->remove(cell
);
237 did_something
= true;
241 void handle_polarity_inv(Cell
*cell
, IdString port
, IdString param
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
243 SigSpec sig
= assign_map(cell
->getPort(port
));
244 if (invert_map
.count(sig
)) {
245 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
246 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
247 log_signal(sig
), log_signal(invert_map
.at(sig
)));
248 cell
->setPort(port
, (invert_map
.at(sig
)));
249 cell
->setParam(param
, !cell
->getParam(param
).as_bool());
253 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
)
255 log_assert(GetSize(type1
) == GetSize(type2
));
256 string cell_type
= cell
->type
.str();
258 if (GetSize(type1
) != GetSize(cell_type
))
261 for (int i
= 0; i
< GetSize(type1
); i
++) {
262 log_assert((type1
[i
] == '?') == (type2
[i
] == '?'));
263 if (type1
[i
] == '?') {
264 if (cell_type
[i
] != '0' && cell_type
[i
] != '1' && cell_type
[i
] != 'N' && cell_type
[i
] != 'P')
266 type1
[i
] = cell_type
[i
];
267 type2
[i
] = cell_type
[i
];
271 if (cell
->type
.in(type1
, type2
)) {
272 SigSpec sig
= assign_map(cell
->getPort(port
));
273 if (invert_map
.count(sig
)) {
274 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
275 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
276 log_signal(sig
), log_signal(invert_map
.at(sig
)));
277 cell
->setPort(port
, (invert_map
.at(sig
)));
278 cell
->type
= cell
->type
== type1
? type2
: type1
;
283 bool is_one_or_minus_one(const Const
&value
, bool is_signed
, bool &is_negative
)
285 bool all_bits_one
= true;
286 bool last_bit_one
= true;
288 if (GetSize(value
.bits
) < 1)
291 if (GetSize(value
.bits
) == 1) {
292 if (value
.bits
[0] != State::S1
)
299 for (int i
= 0; i
< GetSize(value
.bits
); i
++) {
300 if (value
.bits
[i
] != State::S1
)
301 all_bits_one
= false;
302 if (value
.bits
[i
] != (i
? State::S0
: State::S1
))
303 last_bit_one
= false;
306 if (all_bits_one
&& is_signed
) {
314 int get_highest_hot_index(RTLIL::SigSpec signal
)
316 for (int i
= GetSize(signal
) - 1; i
>= 0; i
--)
318 if (signal
[i
] == RTLIL::State::S0
)
321 if (signal
[i
] == RTLIL::State::S1
)
330 // if the signal has only one bit set, return the index of that bit.
331 // otherwise return -1
332 int get_onehot_bit_index(RTLIL::SigSpec signal
)
336 for (int i
= 0; i
< GetSize(signal
); i
++)
338 if (signal
[i
] == RTLIL::State::S0
)
341 if (signal
[i
] != RTLIL::State::S1
)
353 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
)
355 if (!design
->selected(module
))
358 CellTypes ct_combinational
;
359 ct_combinational
.setup_internals();
360 ct_combinational
.setup_stdcells();
362 SigMap
assign_map(module
);
363 dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
365 TopoSort
<RTLIL::Cell
*, RTLIL::IdString::compare_ptr_by_name
<RTLIL::Cell
>> cells
;
366 dict
<RTLIL::Cell
*, std::set
<RTLIL::SigBit
>> cell_to_inbit
;
367 dict
<RTLIL::SigBit
, std::set
<RTLIL::Cell
*>> outbit_to_cell
;
369 for (auto cell
: module
->cells())
370 if (design
->selected(module
, cell
) && cell
->type
[0] == '$') {
371 if (cell
->type
.in("$_NOT_", "$not", "$logic_not") &&
372 cell
->getPort("\\A").size() == 1 && cell
->getPort("\\Y").size() == 1)
373 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\A"));
374 if (cell
->type
.in("$mux", "$_MUX_") &&
375 cell
->getPort("\\A") == SigSpec(State::S1
) && cell
->getPort("\\B") == SigSpec(State::S0
))
376 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\S"));
377 if (ct_combinational
.cell_known(cell
->type
))
378 for (auto &conn
: cell
->connections()) {
379 RTLIL::SigSpec sig
= assign_map(conn
.second
);
381 if (ct_combinational
.cell_input(cell
->type
, conn
.first
))
382 cell_to_inbit
[cell
].insert(sig
.begin(), sig
.end());
383 if (ct_combinational
.cell_output(cell
->type
, conn
.first
))
384 for (auto &bit
: sig
)
385 outbit_to_cell
[bit
].insert(cell
);
390 for (auto &it_right
: cell_to_inbit
)
391 for (auto &it_sigbit
: it_right
.second
)
392 for (auto &it_left
: outbit_to_cell
[it_sigbit
])
393 cells
.edge(it_left
, it_right
.first
);
397 for (auto cell
: cells
.sorted
)
399 #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)
400 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
404 if (cell
->type
.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
405 handle_polarity_inv(cell
, "\\CLK", "\\CLK_POLARITY", assign_map
, invert_map
);
407 if (cell
->type
.in("$sr", "$dffsr", "$dlatchsr")) {
408 handle_polarity_inv(cell
, "\\SET", "\\SET_POLARITY", assign_map
, invert_map
);
409 handle_polarity_inv(cell
, "\\CLR", "\\CLR_POLARITY", assign_map
, invert_map
);
412 if (cell
->type
.in("$dffe", "$dlatch", "$dlatchsr"))
413 handle_polarity_inv(cell
, "\\EN", "\\EN_POLARITY", assign_map
, invert_map
);
415 handle_clkpol_celltype_swap(cell
, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map
, invert_map
);
416 handle_clkpol_celltype_swap(cell
, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map
, invert_map
);
418 handle_clkpol_celltype_swap(cell
, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map
, invert_map
);
420 handle_clkpol_celltype_swap(cell
, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map
, invert_map
);
421 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map
, invert_map
);
423 handle_clkpol_celltype_swap(cell
, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map
, invert_map
);
424 handle_clkpol_celltype_swap(cell
, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map
, invert_map
);
426 handle_clkpol_celltype_swap(cell
, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map
, invert_map
);
427 handle_clkpol_celltype_swap(cell
, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map
, invert_map
);
428 handle_clkpol_celltype_swap(cell
, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map
, invert_map
);
430 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map
, invert_map
);
432 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map
, invert_map
);
433 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map
, invert_map
);
434 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map
, invert_map
);
437 bool detect_const_and
= false;
438 bool detect_const_or
= false;
440 if (cell
->type
.in("$reduce_and", "$_AND_"))
441 detect_const_and
= true;
443 if (cell
->type
.in("$and", "$logic_and") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
444 detect_const_and
= true;
446 if (cell
->type
.in("$reduce_or", "$reduce_bool", "$_OR_"))
447 detect_const_or
= true;
449 if (cell
->type
.in("$or", "$logic_or") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
450 detect_const_or
= true;
452 if (detect_const_and
|| detect_const_or
)
454 pool
<SigBit
> input_bits
= assign_map(cell
->getPort("\\A")).to_sigbit_pool();
455 bool found_zero
= false, found_one
= false, found_undef
= false, found_inv
= false, many_conconst
= false;
456 SigBit non_const_input
= State::Sm
;
458 if (cell
->hasPort("\\B")) {
459 vector
<SigBit
> more_bits
= assign_map(cell
->getPort("\\B")).to_sigbit_vector();
460 input_bits
.insert(more_bits
.begin(), more_bits
.end());
463 for (auto bit
: input_bits
) {
465 if (invert_map
.count(bit
) && input_bits
.count(invert_map
.at(bit
)))
467 if (non_const_input
!= State::Sm
)
468 many_conconst
= true;
469 non_const_input
= many_conconst
? State::Sm
: bit
;
471 if (bit
== State::S0
)
473 else if (bit
== State::S1
)
480 if (detect_const_and
&& (found_zero
|| found_inv
)) {
481 cover("opt.opt_expr.const_and");
482 replace_cell(assign_map
, module
, cell
, "const_and", "\\Y", RTLIL::State::S0
);
486 if (detect_const_or
&& (found_one
|| found_inv
)) {
487 cover("opt.opt_expr.const_or");
488 replace_cell(assign_map
, module
, cell
, "const_or", "\\Y", RTLIL::State::S1
);
492 if (non_const_input
!= State::Sm
&& !found_undef
) {
493 cover("opt.opt_expr.and_or_buffer");
494 replace_cell(assign_map
, module
, cell
, "and_or_buffer", "\\Y", non_const_input
);
499 if (cell
->type
.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
500 GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\Y")) == 1)
502 if (cell
->type
== "$reduce_xnor") {
503 cover("opt.opt_expr.reduce_xnor_not");
504 log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
505 log_id(cell
->type
), log_id(cell
->name
), log_id(module
));
507 did_something
= true;
509 cover("opt.opt_expr.unary_buffer");
510 replace_cell(assign_map
, module
, cell
, "unary_buffer", "\\Y", cell
->getPort("\\A"));
517 if (cell
->type
.in("$not", "$pos", "$and", "$or", "$xor", "$xnor"))
518 if (group_cell_inputs(module
, cell
, true, assign_map
))
521 if (cell
->type
.in("$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$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
.in("$logic_and", "$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
.in("$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$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
.in("$logic_and", "$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;
645 if (cell
->type
.in("$add", "$sub")) {
646 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
647 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
648 RTLIL::SigSpec sig_y
= cell
->getPort("\\Y");
649 bool sub
= cell
->type
== "$sub";
652 for (i
= 0; i
< GetSize(sig_y
); i
++) {
653 if (sig_b
.at(i
, State::Sx
) == State::S0
&& sig_a
.at(i
, State::Sx
) != State::Sx
)
654 module
->connect(sig_y
[i
], sig_a
[i
]);
655 else if (!sub
&& sig_a
.at(i
, State::Sx
) == State::S0
&& sig_b
.at(i
, State::Sx
) != State::Sx
)
656 module
->connect(sig_y
[i
], sig_b
[i
]);
661 cover_list("opt.opt_expr.fine", "$add", "$sub", cell
->type
.str());
662 cell
->setPort("\\A", sig_a
.extract_end(i
));
663 cell
->setPort("\\B", sig_b
.extract_end(i
));
664 cell
->setPort("\\Y", sig_y
.extract_end(i
));
665 cell
->fixup_parameters();
666 did_something
= true;
671 if (cell
->type
.in("$reduce_xor", "$reduce_xnor", "$shift", "$shiftx", "$shl", "$shr", "$sshl", "$sshr",
672 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow"))
674 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
675 RTLIL::SigSpec sig_b
= cell
->hasPort("\\B") ? assign_map(cell
->getPort("\\B")) : RTLIL::SigSpec();
677 if (cell
->type
.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx"))
678 sig_a
= RTLIL::SigSpec();
680 for (auto &bit
: sig_a
.to_sigbit_vector())
681 if (bit
== RTLIL::State::Sx
)
682 goto found_the_x_bit
;
684 for (auto &bit
: sig_b
.to_sigbit_vector())
685 if (bit
== RTLIL::State::Sx
)
686 goto found_the_x_bit
;
690 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
691 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell
->type
.str());
692 if (cell
->type
.in("$reduce_xor", "$reduce_xnor", "$lt", "$le", "$ge", "$gt"))
693 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::State::Sx
);
695 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx
, cell
->getPort("\\Y").size()));
700 if (cell
->type
.in("$_NOT_", "$not", "$logic_not") && cell
->getPort("\\Y").size() == 1 &&
701 invert_map
.count(assign_map(cell
->getPort("\\A"))) != 0) {
702 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell
->type
.str());
703 replace_cell(assign_map
, module
, cell
, "double_invert", "\\Y", invert_map
.at(assign_map(cell
->getPort("\\A"))));
707 if (cell
->type
.in("$_MUX_", "$mux") && invert_map
.count(assign_map(cell
->getPort("\\S"))) != 0) {
708 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell
->type
.str());
709 log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
710 RTLIL::SigSpec tmp
= cell
->getPort("\\A");
711 cell
->setPort("\\A", cell
->getPort("\\B"));
712 cell
->setPort("\\B", tmp
);
713 cell
->setPort("\\S", invert_map
.at(assign_map(cell
->getPort("\\S"))));
714 did_something
= true;
718 if (cell
->type
== "$_NOT_") {
719 RTLIL::SigSpec input
= cell
->getPort("\\A");
720 assign_map
.apply(input
);
721 if (input
.match("1")) ACTION_DO_Y(0);
722 if (input
.match("0")) ACTION_DO_Y(1);
723 if (input
.match("*")) ACTION_DO_Y(x
);
726 if (cell
->type
== "$_AND_") {
727 RTLIL::SigSpec input
;
728 input
.append(cell
->getPort("\\B"));
729 input
.append(cell
->getPort("\\A"));
730 assign_map
.apply(input
);
731 if (input
.match(" 0")) ACTION_DO_Y(0);
732 if (input
.match("0 ")) ACTION_DO_Y(0);
733 if (input
.match("11")) ACTION_DO_Y(1);
734 if (input
.match("**")) ACTION_DO_Y(x
);
735 if (input
.match("1*")) ACTION_DO_Y(x
);
736 if (input
.match("*1")) ACTION_DO_Y(x
);
738 if (input
.match(" *")) ACTION_DO_Y(0);
739 if (input
.match("* ")) ACTION_DO_Y(0);
741 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
742 if (input
.match("1 ")) ACTION_DO("\\Y", input
.extract(0, 1));
745 if (cell
->type
== "$_OR_") {
746 RTLIL::SigSpec input
;
747 input
.append(cell
->getPort("\\B"));
748 input
.append(cell
->getPort("\\A"));
749 assign_map
.apply(input
);
750 if (input
.match(" 1")) ACTION_DO_Y(1);
751 if (input
.match("1 ")) ACTION_DO_Y(1);
752 if (input
.match("00")) ACTION_DO_Y(0);
753 if (input
.match("**")) ACTION_DO_Y(x
);
754 if (input
.match("0*")) ACTION_DO_Y(x
);
755 if (input
.match("*0")) ACTION_DO_Y(x
);
757 if (input
.match(" *")) ACTION_DO_Y(1);
758 if (input
.match("* ")) ACTION_DO_Y(1);
760 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
761 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
764 if (cell
->type
== "$_XOR_") {
765 RTLIL::SigSpec input
;
766 input
.append(cell
->getPort("\\B"));
767 input
.append(cell
->getPort("\\A"));
768 assign_map
.apply(input
);
769 if (input
.match("00")) ACTION_DO_Y(0);
770 if (input
.match("01")) ACTION_DO_Y(1);
771 if (input
.match("10")) ACTION_DO_Y(1);
772 if (input
.match("11")) ACTION_DO_Y(0);
773 if (input
.match(" *")) ACTION_DO_Y(x
);
774 if (input
.match("* ")) ACTION_DO_Y(x
);
775 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
776 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
779 if (cell
->type
== "$_MUX_") {
780 RTLIL::SigSpec input
;
781 input
.append(cell
->getPort("\\S"));
782 input
.append(cell
->getPort("\\B"));
783 input
.append(cell
->getPort("\\A"));
784 assign_map
.apply(input
);
785 if (input
.extract(2, 1) == input
.extract(1, 1))
786 ACTION_DO("\\Y", input
.extract(2, 1));
787 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(2, 1));
788 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
789 if (input
.match("01 ")) ACTION_DO("\\Y", input
.extract(0, 1));
790 if (input
.match("10 ")) {
791 cover("opt.opt_expr.mux_to_inv");
792 cell
->type
= "$_NOT_";
793 cell
->setPort("\\A", input
.extract(0, 1));
794 cell
->unsetPort("\\B");
795 cell
->unsetPort("\\S");
798 if (input
.match("11 ")) ACTION_DO_Y(1);
799 if (input
.match("00 ")) ACTION_DO_Y(0);
800 if (input
.match("** ")) ACTION_DO_Y(x
);
801 if (input
.match("01*")) ACTION_DO_Y(x
);
802 if (input
.match("10*")) ACTION_DO_Y(x
);
804 if (input
.match("* ")) ACTION_DO("\\Y", input
.extract(1, 1));
805 if (input
.match(" * ")) ACTION_DO("\\Y", input
.extract(2, 1));
806 if (input
.match(" *")) ACTION_DO("\\Y", input
.extract(2, 1));
810 if (cell
->type
.in("$_TBUF_", "$tribuf")) {
811 RTLIL::SigSpec input
= cell
->getPort(cell
->type
== "$_TBUF_" ? "\\E" : "\\EN");
812 RTLIL::SigSpec a
= cell
->getPort("\\A");
813 assign_map
.apply(input
);
815 if (input
== State::S1
)
816 ACTION_DO("\\Y", cell
->getPort("\\A"));
817 if (input
== State::S0
&& !a
.is_fully_undef()) {
818 cover("opt.opt_expr.action_" S__LINE__
);
819 log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
820 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str());
821 cell
->setPort("\\A", SigSpec(State::Sx
, GetSize(a
)));
822 did_something
= true;
827 if (cell
->type
.in("$eq", "$ne", "$eqx", "$nex"))
829 RTLIL::SigSpec a
= cell
->getPort("\\A");
830 RTLIL::SigSpec b
= cell
->getPort("\\B");
832 if (cell
->parameters
["\\A_WIDTH"].as_int() != cell
->parameters
["\\B_WIDTH"].as_int()) {
833 int width
= max(cell
->parameters
["\\A_WIDTH"].as_int(), cell
->parameters
["\\B_WIDTH"].as_int());
834 a
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
835 b
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
838 RTLIL::SigSpec new_a
, new_b
;
840 log_assert(GetSize(a
) == GetSize(b
));
841 for (int i
= 0; i
< GetSize(a
); i
++) {
842 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
) {
843 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
844 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in("$eq", "$eqx") ? RTLIL::State::S0
: RTLIL::State::S1
);
845 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
846 replace_cell(assign_map
, module
, cell
, "isneq", "\\Y", new_y
);
855 if (new_a
.size() == 0) {
856 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
857 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in("$eq", "$eqx") ? RTLIL::State::S1
: RTLIL::State::S0
);
858 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
859 replace_cell(assign_map
, module
, cell
, "empty", "\\Y", new_y
);
863 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
864 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
865 cell
->setPort("\\A", new_a
);
866 cell
->setPort("\\B", new_b
);
867 cell
->parameters
["\\A_WIDTH"] = new_a
.size();
868 cell
->parameters
["\\B_WIDTH"] = new_b
.size();
872 if (cell
->type
.in("$eq", "$ne") && cell
->parameters
["\\Y_WIDTH"].as_int() == 1 &&
873 cell
->parameters
["\\A_WIDTH"].as_int() == 1 && cell
->parameters
["\\B_WIDTH"].as_int() == 1)
875 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
876 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
878 if (a
.is_fully_const() && !b
.is_fully_const()) {
879 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell
->type
.str());
880 cell
->setPort("\\A", b
);
881 cell
->setPort("\\B", a
);
885 if (b
.is_fully_const()) {
886 if (b
.as_bool() == (cell
->type
== "$eq")) {
887 RTLIL::SigSpec input
= b
;
888 ACTION_DO("\\Y", cell
->getPort("\\A"));
890 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell
->type
.str());
891 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
893 cell
->parameters
.erase("\\B_WIDTH");
894 cell
->parameters
.erase("\\B_SIGNED");
895 cell
->unsetPort("\\B");
896 did_something
= true;
902 if (cell
->type
.in("$eq", "$ne") &&
903 (assign_map(cell
->getPort("\\A")).is_fully_zero() || assign_map(cell
->getPort("\\B")).is_fully_zero()))
905 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell
->type
.str());
906 log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell
->type
), log_id(cell
),
907 log_id(module
), "$eq" ? "$logic_not" : "$reduce_bool");
908 cell
->type
= cell
->type
== "$eq" ? "$logic_not" : "$reduce_bool";
909 if (assign_map(cell
->getPort("\\A")).is_fully_zero()) {
910 cell
->setPort("\\A", cell
->getPort("\\B"));
911 cell
->setParam("\\A_SIGNED", cell
->getParam("\\B_SIGNED"));
912 cell
->setParam("\\A_WIDTH", cell
->getParam("\\B_WIDTH"));
914 cell
->unsetPort("\\B");
915 cell
->unsetParam("\\B_SIGNED");
916 cell
->unsetParam("\\B_WIDTH");
917 did_something
= true;
921 if (cell
->type
.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell
->getPort("\\B")).is_fully_const())
923 bool sign_ext
= cell
->type
== "$sshr" && cell
->getParam("\\A_SIGNED").as_bool();
924 int shift_bits
= assign_map(cell
->getPort("\\B")).as_int(cell
->type
.in("$shift", "$shiftx") && cell
->getParam("\\B_SIGNED").as_bool());
926 if (cell
->type
.in("$shl", "$sshl"))
929 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
930 RTLIL::SigSpec
sig_y(cell
->type
== "$shiftx" ? RTLIL::State::Sx
: RTLIL::State::S0
, cell
->getParam("\\Y_WIDTH").as_int());
932 if (GetSize(sig_a
) < GetSize(sig_y
))
933 sig_a
.extend_u0(GetSize(sig_y
), cell
->getParam("\\A_SIGNED").as_bool());
935 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
936 int idx
= i
+ shift_bits
;
937 if (0 <= idx
&& idx
< GetSize(sig_a
))
938 sig_y
[i
] = sig_a
[idx
];
939 else if (GetSize(sig_a
) <= idx
&& sign_ext
)
940 sig_y
[i
] = sig_a
[GetSize(sig_a
)-1];
943 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell
->type
.str());
945 log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
946 log_id(cell
->type
), log_id(cell
), log_signal(assign_map(cell
->getPort("\\B"))), shift_bits
, log_id(module
), log_signal(sig_y
));
948 module
->connect(cell
->getPort("\\Y"), sig_y
);
949 module
->remove(cell
);
951 did_something
= true;
957 bool identity_wrt_a
= false;
958 bool identity_wrt_b
= false;
959 bool arith_inverse
= false;
961 if (cell
->type
.in("$add", "$sub", "$or", "$xor"))
963 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
964 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
966 if (cell
->type
!= "$sub" && a
.is_fully_const() && a
.as_bool() == false)
967 identity_wrt_b
= true;
969 if (b
.is_fully_const() && b
.as_bool() == false)
970 identity_wrt_a
= true;
973 if (cell
->type
.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx"))
975 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
977 if (b
.is_fully_const() && b
.as_bool() == false)
978 identity_wrt_a
= true;
981 if (cell
->type
== "$mul")
983 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
984 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
986 if (a
.is_fully_const() && is_one_or_minus_one(a
.as_const(), cell
->getParam("\\A_SIGNED").as_bool(), arith_inverse
))
987 identity_wrt_b
= true;
989 if (b
.is_fully_const() && is_one_or_minus_one(b
.as_const(), cell
->getParam("\\B_SIGNED").as_bool(), arith_inverse
))
990 identity_wrt_a
= true;
993 if (cell
->type
== "$div")
995 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
997 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
998 identity_wrt_a
= true;
1001 if (identity_wrt_a
|| identity_wrt_b
)
1004 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1006 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1008 log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
1009 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
1011 if (!identity_wrt_a
) {
1012 cell
->setPort("\\A", cell
->getPort("\\B"));
1013 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
1014 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
1017 cell
->type
= arith_inverse
? "$neg" : "$pos";
1018 cell
->unsetPort("\\B");
1019 cell
->parameters
.erase("\\B_WIDTH");
1020 cell
->parameters
.erase("\\B_SIGNED");
1023 did_something
= true;
1028 if (mux_bool
&& cell
->type
.in("$mux", "$_MUX_") &&
1029 cell
->getPort("\\A") == State::S0
&& cell
->getPort("\\B") == State::S1
) {
1030 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell
->type
.str());
1031 replace_cell(assign_map
, module
, cell
, "mux_bool", "\\Y", cell
->getPort("\\S"));
1035 if (mux_bool
&& cell
->type
.in("$mux", "$_MUX_") &&
1036 cell
->getPort("\\A") == State::S1
&& cell
->getPort("\\B") == State::S0
) {
1037 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell
->type
.str());
1038 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1039 cell
->setPort("\\A", cell
->getPort("\\S"));
1040 cell
->unsetPort("\\B");
1041 cell
->unsetPort("\\S");
1042 if (cell
->type
== "$mux") {
1043 Const width
= cell
->parameters
["\\WIDTH"];
1044 cell
->parameters
["\\A_WIDTH"] = width
;
1045 cell
->parameters
["\\Y_WIDTH"] = width
;
1046 cell
->parameters
["\\A_SIGNED"] = 0;
1047 cell
->parameters
.erase("\\WIDTH");
1048 cell
->type
= "$not";
1050 cell
->type
= "$_NOT_";
1051 did_something
= true;
1055 if (consume_x
&& mux_bool
&& cell
->type
.in("$mux", "$_MUX_") && cell
->getPort("\\A") == State::S0
) {
1056 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell
->type
.str());
1057 log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1058 cell
->setPort("\\A", cell
->getPort("\\S"));
1059 cell
->unsetPort("\\S");
1060 if (cell
->type
== "$mux") {
1061 Const width
= cell
->parameters
["\\WIDTH"];
1062 cell
->parameters
["\\A_WIDTH"] = width
;
1063 cell
->parameters
["\\B_WIDTH"] = width
;
1064 cell
->parameters
["\\Y_WIDTH"] = width
;
1065 cell
->parameters
["\\A_SIGNED"] = 0;
1066 cell
->parameters
["\\B_SIGNED"] = 0;
1067 cell
->parameters
.erase("\\WIDTH");
1068 cell
->type
= "$and";
1070 cell
->type
= "$_AND_";
1071 did_something
= true;
1075 if (consume_x
&& mux_bool
&& cell
->type
.in("$mux", "$_MUX_") && cell
->getPort("\\B") == State::S1
) {
1076 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell
->type
.str());
1077 log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1078 cell
->setPort("\\B", cell
->getPort("\\S"));
1079 cell
->unsetPort("\\S");
1080 if (cell
->type
== "$mux") {
1081 Const width
= cell
->parameters
["\\WIDTH"];
1082 cell
->parameters
["\\A_WIDTH"] = width
;
1083 cell
->parameters
["\\B_WIDTH"] = width
;
1084 cell
->parameters
["\\Y_WIDTH"] = width
;
1085 cell
->parameters
["\\A_SIGNED"] = 0;
1086 cell
->parameters
["\\B_SIGNED"] = 0;
1087 cell
->parameters
.erase("\\WIDTH");
1090 cell
->type
= "$_OR_";
1091 did_something
= true;
1095 if (mux_undef
&& cell
->type
.in("$mux", "$pmux")) {
1096 RTLIL::SigSpec new_a
, new_b
, new_s
;
1097 int width
= cell
->getPort("\\A").size();
1098 if ((cell
->getPort("\\A").is_fully_undef() && cell
->getPort("\\B").is_fully_undef()) ||
1099 cell
->getPort("\\S").is_fully_undef()) {
1100 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell
->type
.str());
1101 replace_cell(assign_map
, module
, cell
, "mux_undef", "\\Y", cell
->getPort("\\A"));
1104 for (int i
= 0; i
< cell
->getPort("\\S").size(); i
++) {
1105 RTLIL::SigSpec old_b
= cell
->getPort("\\B").extract(i
*width
, width
);
1106 RTLIL::SigSpec old_s
= cell
->getPort("\\S").extract(i
, 1);
1107 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
1109 new_b
.append(old_b
);
1110 new_s
.append(old_s
);
1112 new_a
= cell
->getPort("\\A");
1113 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
1114 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
1115 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
1116 new_s
= new_s
.extract(0, new_s
.size()-1);
1118 if (new_s
.size() == 0) {
1119 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell
->type
.str());
1120 replace_cell(assign_map
, module
, cell
, "mux_empty", "\\Y", new_a
);
1123 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
1124 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell
->type
.str());
1125 replace_cell(assign_map
, module
, cell
, "mux_sel01", "\\Y", new_s
);
1128 if (cell
->getPort("\\S").size() != new_s
.size()) {
1129 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell
->type
.str());
1130 log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1131 GetSize(cell
->getPort("\\S")) - GetSize(new_s
), log_id(cell
->type
), log_id(cell
), log_id(module
));
1132 cell
->setPort("\\A", new_a
);
1133 cell
->setPort("\\B", new_b
);
1134 cell
->setPort("\\S", new_s
);
1135 if (new_s
.size() > 1) {
1136 cell
->type
= "$pmux";
1137 cell
->parameters
["\\S_WIDTH"] = new_s
.size();
1139 cell
->type
= "$mux";
1140 cell
->parameters
.erase("\\S_WIDTH");
1142 did_something
= true;
1146 #define FOLD_1ARG_CELL(_t) \
1147 if (cell->type == "$" #_t) { \
1148 RTLIL::SigSpec a = cell->getPort("\\A"); \
1149 assign_map.apply(a); \
1150 if (a.is_fully_const()) { \
1151 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1152 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1153 cell->parameters["\\A_SIGNED"].as_bool(), false, \
1154 cell->parameters["\\Y_WIDTH"].as_int())); \
1155 cover("opt.opt_expr.const.$" #_t); \
1156 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
1160 #define FOLD_2ARG_CELL(_t) \
1161 if (cell->type == "$" #_t) { \
1162 RTLIL::SigSpec a = cell->getPort("\\A"); \
1163 RTLIL::SigSpec b = cell->getPort("\\B"); \
1164 assign_map.apply(a), assign_map.apply(b); \
1165 if (a.is_fully_const() && b.is_fully_const()) { \
1166 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1167 cell->parameters["\\A_SIGNED"].as_bool(), \
1168 cell->parameters["\\B_SIGNED"].as_bool(), \
1169 cell->parameters["\\Y_WIDTH"].as_int())); \
1170 cover("opt.opt_expr.const.$" #_t); \
1171 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
1180 FOLD_2ARG_CELL(xnor
)
1182 FOLD_1ARG_CELL(reduce_and
)
1183 FOLD_1ARG_CELL(reduce_or
)
1184 FOLD_1ARG_CELL(reduce_xor
)
1185 FOLD_1ARG_CELL(reduce_xnor
)
1186 FOLD_1ARG_CELL(reduce_bool
)
1188 FOLD_1ARG_CELL(logic_not
)
1189 FOLD_2ARG_CELL(logic_and
)
1190 FOLD_2ARG_CELL(logic_or
)
1194 FOLD_2ARG_CELL(sshl
)
1195 FOLD_2ARG_CELL(sshr
)
1196 FOLD_2ARG_CELL(shift
)
1197 FOLD_2ARG_CELL(shiftx
)
1216 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1217 if (cell
->type
== "$mux") {
1218 RTLIL::SigSpec input
= assign_map(cell
->getPort("\\S"));
1219 RTLIL::SigSpec inA
= assign_map(cell
->getPort("\\A"));
1220 RTLIL::SigSpec inB
= assign_map(cell
->getPort("\\B"));
1221 if (input
.is_fully_const())
1222 ACTION_DO("\\Y", input
.as_bool() ? cell
->getPort("\\B") : cell
->getPort("\\A"));
1223 else if (inA
== inB
)
1224 ACTION_DO("\\Y", cell
->getPort("\\A"));
1227 if (!keepdc
&& cell
->type
== "$mul")
1229 bool a_signed
= cell
->parameters
["\\A_SIGNED"].as_bool();
1230 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1231 bool swapped_ab
= false;
1233 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
1234 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1235 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1237 if (sig_b
.is_fully_const() && sig_b
.size() <= 32)
1238 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
1240 if (sig_a
.is_fully_def() && sig_a
.size() <= 32)
1242 int a_val
= sig_a
.as_int();
1246 cover("opt.opt_expr.mul_shift.zero");
1248 log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1249 cell
->name
.c_str(), module
->name
.c_str());
1251 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
1252 module
->remove(cell
);
1254 did_something
= true;
1258 for (int i
= 1; i
< (a_signed
? sig_a
.size()-1 : sig_a
.size()); i
++)
1259 if (a_val
== (1 << i
))
1262 cover("opt.opt_expr.mul_shift.swapped");
1264 cover("opt.opt_expr.mul_shift.unswapped");
1266 log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1267 a_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1270 cell
->setPort("\\A", cell
->getPort("\\B"));
1271 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
1272 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
1275 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1277 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1280 cell
->type
= "$shl";
1281 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1282 cell
->parameters
["\\B_SIGNED"] = false;
1283 cell
->setPort("\\B", new_b
);
1286 did_something
= true;
1292 if (!keepdc
&& cell
->type
.in("$div", "$mod"))
1294 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1295 SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1296 SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1298 if (sig_b
.is_fully_def() && sig_b
.size() <= 32)
1300 int b_val
= sig_b
.as_int();
1304 cover("opt.opt_expr.divmod_zero");
1306 log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1307 cell
->name
.c_str(), module
->name
.c_str());
1309 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(State::Sx
, sig_y
.size())));
1310 module
->remove(cell
);
1312 did_something
= true;
1316 for (int i
= 1; i
< (b_signed
? sig_b
.size()-1 : sig_b
.size()); i
++)
1317 if (b_val
== (1 << i
))
1319 if (cell
->type
== "$div")
1321 cover("opt.opt_expr.div_shift");
1323 log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1324 b_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1326 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1328 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1331 cell
->type
= "$shr";
1332 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1333 cell
->parameters
["\\B_SIGNED"] = false;
1334 cell
->setPort("\\B", new_b
);
1339 cover("opt.opt_expr.mod_mask");
1341 log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
1342 b_val
, cell
->name
.c_str(), module
->name
.c_str());
1344 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(State::S1
, i
);
1347 new_b
.push_back(State::S0
);
1349 cell
->type
= "$and";
1350 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1351 cell
->setPort("\\B", new_b
);
1355 did_something
= true;
1361 // remove redundant pairs of bits in ==, ===, !=, and !==
1362 // replace cell with const driver if inputs can't be equal
1363 if (do_fine
&& cell
->type
.in("$eq", "$ne", "$eqx", "$nex"))
1365 pool
<pair
<SigBit
, SigBit
>> redundant_cache
;
1366 mfp
<SigBit
> contradiction_cache
;
1368 contradiction_cache
.promote(State::S0
);
1369 contradiction_cache
.promote(State::S1
);
1371 int a_width
= cell
->getParam("\\A_WIDTH").as_int();
1372 int b_width
= cell
->getParam("\\B_WIDTH").as_int();
1374 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
1375 int width
= is_signed
? std::min(a_width
, b_width
) : std::max(a_width
, b_width
);
1377 SigSpec sig_a
= cell
->getPort("\\A");
1378 SigSpec sig_b
= cell
->getPort("\\B");
1380 int redundant_bits
= 0;
1382 for (int i
= width
-1; i
>= 0; i
--)
1384 SigBit bit_a
= i
< a_width
? assign_map(sig_a
[i
]) : State::S0
;
1385 SigBit bit_b
= i
< b_width
? assign_map(sig_b
[i
]) : State::S0
;
1387 if (bit_a
!= State::Sx
&& bit_a
!= State::Sz
&&
1388 bit_b
!= State::Sx
&& bit_b
!= State::Sz
)
1389 contradiction_cache
.merge(bit_a
, bit_b
);
1392 std::swap(bit_a
, bit_b
);
1394 pair
<SigBit
, SigBit
> key(bit_a
, bit_b
);
1396 if (redundant_cache
.count(key
)) {
1397 if (i
< a_width
) sig_a
.remove(i
);
1398 if (i
< b_width
) sig_b
.remove(i
);
1403 redundant_cache
.insert(key
);
1406 if (contradiction_cache
.find(State::S0
) == contradiction_cache
.find(State::S1
))
1408 SigSpec y_sig
= cell
->getPort("\\Y");
1409 Const
y_value(cell
->type
.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig
));
1411 log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
1412 log_id(cell
), log_id(module
), log_signal(y_value
));
1414 module
->connect(y_sig
, y_value
);
1415 module
->remove(cell
);
1417 did_something
= true;
1423 log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
1424 redundant_bits
, log_id(cell
->type
), log_id(cell
), log_id(module
));
1426 cell
->setPort("\\A", sig_a
);
1427 cell
->setPort("\\B", sig_b
);
1428 cell
->setParam("\\A_WIDTH", GetSize(sig_a
));
1429 cell
->setParam("\\B_WIDTH", GetSize(sig_b
));
1431 did_something
= true;
1436 // simplify comparisons
1437 if (do_fine
&& cell
->type
.in("$lt", "$ge", "$gt", "$le"))
1439 IdString cmp_type
= cell
->type
;
1440 SigSpec var_sig
= cell
->getPort("\\A");
1441 SigSpec const_sig
= cell
->getPort("\\B");
1442 int var_width
= cell
->parameters
["\\A_WIDTH"].as_int();
1443 int const_width
= cell
->parameters
["\\B_WIDTH"].as_int();
1444 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
1446 if (!const_sig
.is_fully_const())
1448 std::swap(var_sig
, const_sig
);
1449 std::swap(var_width
, const_width
);
1450 if (cmp_type
== "$gt")
1452 else if (cmp_type
== "$lt")
1454 else if (cmp_type
== "$ge")
1456 else if (cmp_type
== "$le")
1460 if (const_sig
.is_fully_def() && const_sig
.is_fully_const())
1462 std::string condition
, replacement
;
1463 SigSpec
replace_sig(State::S0
, GetSize(cell
->getPort("\\Y")));
1464 bool replace
= false;
1465 bool remove
= false;
1469 if (const_sig
.is_fully_zero() && cmp_type
== "$lt") {
1470 condition
= "unsigned X<0";
1471 replacement
= "constant 0";
1472 replace_sig
[0] = State::S0
;
1475 if (const_sig
.is_fully_zero() && cmp_type
== "$ge") {
1476 condition
= "unsigned X>=0";
1477 replacement
= "constant 1";
1478 replace_sig
[0] = State::S1
;
1481 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== "$gt") {
1482 condition
= "unsigned X>~0";
1483 replacement
= "constant 0";
1484 replace_sig
[0] = State::S0
;
1487 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== "$le") {
1488 condition
= "unsigned X<=~0";
1489 replacement
= "constant 1";
1490 replace_sig
[0] = State::S1
;
1494 int const_bit_hot
= get_onehot_bit_index(const_sig
);
1495 if (const_bit_hot
>= 0 && const_bit_hot
< var_width
)
1497 RTLIL::SigSpec
var_high_sig(RTLIL::State::S0
, var_width
- const_bit_hot
);
1498 for (int i
= const_bit_hot
; i
< var_width
; i
++) {
1499 var_high_sig
[i
- const_bit_hot
] = var_sig
[i
];
1502 if (cmp_type
== "$lt")
1504 condition
= stringf("unsigned X<%s", log_signal(const_sig
));
1505 replacement
= stringf("!X[%d:%d]", var_width
- 1, const_bit_hot
);
1506 module
->addLogicNot(NEW_ID
, var_high_sig
, cell
->getPort("\\Y"));
1509 if (cmp_type
== "$ge")
1511 condition
= stringf("unsigned X>=%s", log_signal(const_sig
));
1512 replacement
= stringf("|X[%d:%d]", var_width
- 1, const_bit_hot
);
1513 module
->addReduceOr(NEW_ID
, var_high_sig
, cell
->getPort("\\Y"));
1518 int const_bit_set
= get_highest_hot_index(const_sig
);
1519 if(const_bit_set
>= var_width
)
1522 if (cmp_type
== "$lt" || cmp_type
== "$le")
1524 if (cmp_type
== "$lt") cmp_name
= "<";
1525 if (cmp_type
== "$le") cmp_name
= "<=";
1526 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1527 replacement
= "constant 1";
1528 replace_sig
[0] = State::S1
;
1531 if (cmp_type
== "$gt" || cmp_type
== "$ge")
1533 if (cmp_type
== "$gt") cmp_name
= ">";
1534 if (cmp_type
== "$ge") cmp_name
= ">=";
1535 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1536 replacement
= "constant 0";
1537 replace_sig
[0] = State::S0
;
1544 if (const_sig
.is_fully_zero() && cmp_type
== "$lt")
1546 condition
= "signed X<0";
1547 replacement
= stringf("X[%d]", var_width
- 1);
1548 replace_sig
[0] = var_sig
[var_width
- 1];
1551 if (const_sig
.is_fully_zero() && cmp_type
== "$ge")
1553 condition
= "signed X>=0";
1554 replacement
= stringf("X[%d]", var_width
- 1);
1555 module
->addNot(NEW_ID
, var_sig
[var_width
- 1], cell
->getPort("\\Y"));
1560 if (replace
|| remove
)
1562 log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
1563 log_id(cell
->type
), log_id(cell
), condition
.c_str(), replacement
.c_str());
1565 module
->connect(cell
->getPort("\\Y"), replace_sig
);
1566 module
->remove(cell
);
1567 did_something
= true;
1576 #undef FOLD_1ARG_CELL
1577 #undef FOLD_2ARG_CELL
1581 struct OptExprPass
: public Pass
{
1582 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
1583 void help() YS_OVERRIDE
1585 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1587 log(" opt_expr [options] [selection]\n");
1589 log("This pass performs const folding on internal cell types with constant inputs.\n");
1590 log("It also performs some simple expression rewriting.\n");
1592 log(" -mux_undef\n");
1593 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
1595 log(" -mux_bool\n");
1596 log(" replace $mux cells with inverters or buffers when possible\n");
1598 log(" -undriven\n");
1599 log(" replace undriven nets with undef (x) constants\n");
1602 log(" optimize clock inverters by changing FF types\n");
1605 log(" perform fine-grain optimizations\n");
1608 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
1611 log(" some optimizations change the behavior of the circuit with respect to\n");
1612 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
1613 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
1614 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
1617 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1619 bool mux_undef
= false;
1620 bool mux_bool
= false;
1621 bool undriven
= false;
1622 bool clkinv
= false;
1623 bool do_fine
= false;
1624 bool keepdc
= false;
1626 log_header(design
, "Executing OPT_EXPR pass (perform const folding).\n");
1630 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1631 if (args
[argidx
] == "-mux_undef") {
1635 if (args
[argidx
] == "-mux_bool") {
1639 if (args
[argidx
] == "-undriven") {
1643 if (args
[argidx
] == "-clkinv") {
1647 if (args
[argidx
] == "-fine") {
1651 if (args
[argidx
] == "-full") {
1658 if (args
[argidx
] == "-keepdc") {
1664 extra_args(args
, argidx
, design
);
1666 for (auto module
: design
->selected_modules())
1668 log("Optimizing module %s.\n", log_id(module
));
1671 did_something
= false;
1672 replace_undriven(design
, module
);
1674 design
->scratchpad_set_bool("opt.did_something", true);
1679 did_something
= false;
1680 replace_const_cells(design
, module
, false, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1682 design
->scratchpad_set_bool("opt.did_something", true);
1683 } while (did_something
);
1684 replace_const_cells(design
, module
, true, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1686 design
->scratchpad_set_bool("opt.did_something", true);
1687 } while (did_something
);
1696 PRIVATE_NAMESPACE_END