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 for (auto cell
: module
->cells())
43 for (auto &conn
: cell
->connections()) {
44 if (!ct
.cell_known(cell
->type
) || ct
.cell_output(cell
->type
, conn
.first
))
45 driven_signals
.add(sigmap(conn
.second
));
46 if (!ct
.cell_known(cell
->type
) || ct
.cell_input(cell
->type
, conn
.first
))
47 used_signals
.add(sigmap(conn
.second
));
50 for (auto wire
: module
->wires()) {
52 driven_signals
.add(sigmap(wire
));
53 if (wire
->port_output
)
54 used_signals
.add(sigmap(wire
));
55 all_signals
.add(sigmap(wire
));
58 all_signals
.del(driven_signals
);
59 RTLIL::SigSpec undriven_signals
= all_signals
.export_all();
61 for (auto &c
: undriven_signals
.chunks())
63 RTLIL::SigSpec sig
= c
;
65 if (c
.wire
->name
[0] == '$')
66 sig
= used_signals
.extract(sig
);
70 log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module
->name
), log_signal(c
));
71 module
->connect(RTLIL::SigSig(c
, RTLIL::SigSpec(RTLIL::State::Sx
, c
.width
)));
76 void replace_cell(SigMap
&assign_map
, RTLIL::Module
*module
, RTLIL::Cell
*cell
, std::string info
, std::string out_port
, RTLIL::SigSpec out_val
)
78 RTLIL::SigSpec Y
= cell
->getPort(out_port
);
79 out_val
.extend_u0(Y
.size(), false);
81 log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
82 cell
->type
.c_str(), cell
->name
.c_str(), info
.c_str(),
83 module
->name
.c_str(), log_signal(Y
), log_signal(out_val
));
85 assign_map
.add(Y
, out_val
);
86 module
->connect(Y
, out_val
);
91 bool group_cell_inputs(RTLIL::Module
*module
, RTLIL::Cell
*cell
, bool commutative
, SigMap
&sigmap
)
93 std::string b_name
= cell
->hasPort("\\B") ? "\\B" : "\\A";
95 bool a_signed
= cell
->parameters
.at("\\A_SIGNED").as_bool();
96 bool b_signed
= cell
->parameters
.at(b_name
+ "_SIGNED").as_bool();
98 RTLIL::SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
99 RTLIL::SigSpec sig_b
= sigmap(cell
->getPort(b_name
));
100 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
102 sig_a
.extend_u0(sig_y
.size(), a_signed
);
103 sig_b
.extend_u0(sig_y
.size(), b_signed
);
105 std::vector
<RTLIL::SigBit
> bits_a
= sig_a
, bits_b
= sig_b
, bits_y
= sig_y
;
107 enum { GRP_DYN
, GRP_CONST_A
, GRP_CONST_B
, GRP_CONST_AB
, GRP_N
};
108 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::set
<RTLIL::SigBit
>> grouped_bits
[GRP_N
];
110 for (int i
= 0; i
< GetSize(bits_y
); i
++)
112 int group_idx
= GRP_DYN
;
113 RTLIL::SigBit bit_a
= bits_a
[i
], bit_b
= bits_b
[i
];
115 if (cell
->type
== "$or" && (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
))
116 bit_a
= bit_b
= RTLIL::State::S1
;
118 if (cell
->type
== "$and" && (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
))
119 bit_a
= bit_b
= RTLIL::State::S0
;
121 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
122 group_idx
= GRP_CONST_AB
;
123 else if (bit_a
.wire
== NULL
)
124 group_idx
= GRP_CONST_A
;
125 else if (bit_b
.wire
== NULL
&& commutative
)
126 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
127 else if (bit_b
.wire
== NULL
)
128 group_idx
= GRP_CONST_B
;
130 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
133 for (int i
= 0; i
< GRP_N
; i
++)
134 if (GetSize(grouped_bits
[i
]) == GetSize(bits_y
))
137 log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
138 log_id(cell
->type
), log_id(cell
), log_id(module
));
140 for (int i
= 0; i
< GRP_N
; i
++)
142 if (grouped_bits
[i
].empty())
145 RTLIL::Wire
*new_y
= module
->addWire(NEW_ID
, GetSize(grouped_bits
[i
]));
146 RTLIL::SigSpec new_a
, new_b
;
147 RTLIL::SigSig new_conn
;
149 for (auto &it
: grouped_bits
[i
]) {
150 for (auto &bit
: it
.second
) {
151 new_conn
.first
.append_bit(bit
);
152 new_conn
.second
.append_bit(RTLIL::SigBit(new_y
, new_a
.size()));
154 new_a
.append_bit(it
.first
.first
);
155 new_b
.append_bit(it
.first
.second
);
158 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
160 c
->setPort("\\A", new_a
);
161 c
->parameters
["\\A_WIDTH"] = new_a
.size();
162 c
->parameters
["\\A_SIGNED"] = false;
164 if (b_name
== "\\B") {
165 c
->setPort("\\B", new_b
);
166 c
->parameters
["\\B_WIDTH"] = new_b
.size();
167 c
->parameters
["\\B_SIGNED"] = false;
170 c
->setPort("\\Y", new_y
);
171 c
->parameters
["\\Y_WIDTH"] = new_y
->width
;
174 module
->connect(new_conn
);
176 log(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
178 log(", B=%s", log_signal(new_b
));
182 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell
->type
.str());
184 module
->remove(cell
);
185 did_something
= true;
189 void handle_polarity_inv(Cell
*cell
, IdString port
, IdString param
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
191 SigSpec sig
= assign_map(cell
->getPort(port
));
192 if (invert_map
.count(sig
)) {
193 log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
194 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
195 log_signal(sig
), log_signal(invert_map
.at(sig
)));
196 cell
->setPort(port
, (invert_map
.at(sig
)));
197 cell
->setParam(param
, !cell
->getParam(param
).as_bool());
201 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
)
203 log_assert(GetSize(type1
) == GetSize(type2
));
204 string cell_type
= cell
->type
.str();
206 if (GetSize(type1
) != GetSize(cell_type
))
209 for (int i
= 0; i
< GetSize(type1
); i
++) {
210 log_assert((type1
[i
] == '?') == (type2
[i
] == '?'));
211 if (type1
[i
] == '?') {
212 if (cell_type
[i
] != '0' && cell_type
[i
] != '1' && cell_type
[i
] != 'N' && cell_type
[i
] != 'P')
214 type1
[i
] = cell_type
[i
];
215 type2
[i
] = cell_type
[i
];
219 if (cell
->type
.in(type1
, type2
)) {
220 SigSpec sig
= assign_map(cell
->getPort(port
));
221 if (invert_map
.count(sig
)) {
222 log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
223 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
224 log_signal(sig
), log_signal(invert_map
.at(sig
)));
225 cell
->setPort(port
, (invert_map
.at(sig
)));
226 cell
->type
= cell
->type
== type1
? type2
: type1
;
231 bool is_one_or_minus_one(const Const
&value
, bool is_signed
, bool &is_negative
)
233 bool all_bits_one
= true;
234 bool last_bit_one
= true;
236 if (GetSize(value
.bits
) < 1)
239 if (GetSize(value
.bits
) == 1) {
240 if (value
.bits
[0] != State::S1
)
247 for (int i
= 0; i
< GetSize(value
.bits
); i
++) {
248 if (value
.bits
[i
] != State::S1
)
249 all_bits_one
= false;
250 if (value
.bits
[i
] != (i
? State::S0
: State::S1
))
251 last_bit_one
= false;
254 if (all_bits_one
&& is_signed
) {
262 // if the signal has only one bit set, return the index of that bit.
263 // otherwise return -1
264 int get_onehot_bit_index(RTLIL::SigSpec signal
)
268 for (int i
= 0; i
< GetSize(signal
); i
++)
270 if (signal
[i
] == RTLIL::State::S0
)
273 if (signal
[i
] != RTLIL::State::S1
)
285 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
)
287 if (!design
->selected(module
))
290 CellTypes ct_combinational
;
291 ct_combinational
.setup_internals();
292 ct_combinational
.setup_stdcells();
294 SigMap
assign_map(module
);
295 dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
297 TopoSort
<RTLIL::Cell
*, RTLIL::IdString::compare_ptr_by_name
<RTLIL::Cell
>> cells
;
298 dict
<RTLIL::Cell
*, std::set
<RTLIL::SigBit
>> cell_to_inbit
;
299 dict
<RTLIL::SigBit
, std::set
<RTLIL::Cell
*>> outbit_to_cell
;
301 for (auto cell
: module
->cells())
302 if (design
->selected(module
, cell
) && cell
->type
[0] == '$') {
303 if ((cell
->type
== "$_NOT_" || cell
->type
== "$not" || cell
->type
== "$logic_not") &&
304 cell
->getPort("\\A").size() == 1 && cell
->getPort("\\Y").size() == 1)
305 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\A"));
306 if ((cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\A") == SigSpec(State::S1
) && cell
->getPort("\\B") == SigSpec(State::S0
))
307 invert_map
[assign_map(cell
->getPort("\\Y"))] = assign_map(cell
->getPort("\\S"));
308 if (ct_combinational
.cell_known(cell
->type
))
309 for (auto &conn
: cell
->connections()) {
310 RTLIL::SigSpec sig
= assign_map(conn
.second
);
312 if (ct_combinational
.cell_input(cell
->type
, conn
.first
))
313 cell_to_inbit
[cell
].insert(sig
.begin(), sig
.end());
314 if (ct_combinational
.cell_output(cell
->type
, conn
.first
))
315 for (auto &bit
: sig
)
316 outbit_to_cell
[bit
].insert(cell
);
321 for (auto &it_right
: cell_to_inbit
)
322 for (auto &it_sigbit
: it_right
.second
)
323 for (auto &it_left
: outbit_to_cell
[it_sigbit
])
324 cells
.edge(it_left
, it_right
.first
);
328 for (auto cell
: cells
.sorted
)
330 #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)
331 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
335 if (cell
->type
.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
336 handle_polarity_inv(cell
, "\\CLK", "\\CLK_POLARITY", assign_map
, invert_map
);
338 if (cell
->type
.in("$sr", "$dffsr", "$dlatchsr")) {
339 handle_polarity_inv(cell
, "\\SET", "\\SET_POLARITY", assign_map
, invert_map
);
340 handle_polarity_inv(cell
, "\\CLR", "\\CLR_POLARITY", assign_map
, invert_map
);
343 if (cell
->type
.in("$dffe", "$dlatch", "$dlatchsr"))
344 handle_polarity_inv(cell
, "\\EN", "\\EN_POLARITY", assign_map
, invert_map
);
346 handle_clkpol_celltype_swap(cell
, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map
, invert_map
);
347 handle_clkpol_celltype_swap(cell
, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map
, invert_map
);
349 handle_clkpol_celltype_swap(cell
, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map
, invert_map
);
351 handle_clkpol_celltype_swap(cell
, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map
, invert_map
);
352 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map
, invert_map
);
354 handle_clkpol_celltype_swap(cell
, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map
, invert_map
);
355 handle_clkpol_celltype_swap(cell
, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map
, invert_map
);
357 handle_clkpol_celltype_swap(cell
, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map
, invert_map
);
358 handle_clkpol_celltype_swap(cell
, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map
, invert_map
);
359 handle_clkpol_celltype_swap(cell
, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map
, invert_map
);
361 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map
, invert_map
);
363 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map
, invert_map
);
364 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map
, invert_map
);
365 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map
, invert_map
);
368 bool detect_const_and
= false;
369 bool detect_const_or
= false;
371 if (cell
->type
.in("$reduce_and", "$_AND_"))
372 detect_const_and
= true;
374 if (cell
->type
.in("$and", "$logic_and") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
375 detect_const_and
= true;
377 if (cell
->type
.in("$reduce_or", "$reduce_bool", "$_OR_"))
378 detect_const_or
= true;
380 if (cell
->type
.in("$or", "$logic_or") && GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\B")) == 1 && !cell
->getParam("\\A_SIGNED").as_bool())
381 detect_const_or
= true;
383 if (detect_const_and
|| detect_const_or
)
385 pool
<SigBit
> input_bits
= assign_map(cell
->getPort("\\A")).to_sigbit_pool();
386 bool found_zero
= false, found_one
= false, found_undef
= false, found_inv
= false, many_conconst
= false;
387 SigBit non_const_input
= State::Sm
;
389 if (cell
->hasPort("\\B")) {
390 vector
<SigBit
> more_bits
= assign_map(cell
->getPort("\\B")).to_sigbit_vector();
391 input_bits
.insert(more_bits
.begin(), more_bits
.end());
394 for (auto bit
: input_bits
) {
396 if (invert_map
.count(bit
) && input_bits
.count(invert_map
.at(bit
)))
398 if (non_const_input
!= State::Sm
)
399 many_conconst
= true;
400 non_const_input
= many_conconst
? State::Sm
: bit
;
402 if (bit
== State::S0
)
404 else if (bit
== State::S1
)
411 if (detect_const_and
&& (found_zero
|| found_inv
)) {
412 cover("opt.opt_expr.const_and");
413 replace_cell(assign_map
, module
, cell
, "const_and", "\\Y", RTLIL::State::S0
);
417 if (detect_const_or
&& (found_one
|| found_inv
)) {
418 cover("opt.opt_expr.const_or");
419 replace_cell(assign_map
, module
, cell
, "const_or", "\\Y", RTLIL::State::S1
);
423 if (non_const_input
!= State::Sm
&& !found_undef
) {
424 cover("opt.opt_expr.and_or_buffer");
425 replace_cell(assign_map
, module
, cell
, "and_or_buffer", "\\Y", non_const_input
);
430 if (cell
->type
.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
431 GetSize(cell
->getPort("\\A")) == 1 && GetSize(cell
->getPort("\\Y")) == 1)
433 if (cell
->type
== "$reduce_xnor") {
434 cover("opt.opt_expr.reduce_xnor_not");
435 log("Replacing %s cell `%s' in module `%s' with $not cell.\n",
436 log_id(cell
->type
), log_id(cell
->name
), log_id(module
));
439 cover("opt.opt_expr.unary_buffer");
440 replace_cell(assign_map
, module
, cell
, "unary_buffer", "\\Y", cell
->getPort("\\A"));
447 if (cell
->type
== "$not" || cell
->type
== "$pos" ||
448 cell
->type
== "$and" || cell
->type
== "$or" || cell
->type
== "$xor" || cell
->type
== "$xnor")
449 if (group_cell_inputs(module
, cell
, true, assign_map
))
452 if (cell
->type
== "$logic_not" || cell
->type
== "$logic_and" || cell
->type
== "$logic_or" ||
453 cell
->type
== "$reduce_or" || cell
->type
== "$reduce_and" || cell
->type
== "$reduce_bool")
455 SigBit neutral_bit
= cell
->type
== "$reduce_and" ? State::S1
: State::S0
;
457 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
458 RTLIL::SigSpec new_sig_a
;
460 for (auto bit
: sig_a
)
461 if (bit
!= neutral_bit
) new_sig_a
.append(bit
);
463 if (GetSize(new_sig_a
) == 0)
464 new_sig_a
.append(neutral_bit
);
466 if (GetSize(new_sig_a
) < GetSize(sig_a
)) {
467 cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell
->type
.str());
468 log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
469 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_sig_a
));
470 cell
->setPort("\\A", new_sig_a
);
471 cell
->parameters
.at("\\A_WIDTH") = GetSize(new_sig_a
);
472 did_something
= true;
476 if (cell
->type
== "$logic_and" || cell
->type
== "$logic_or")
478 SigBit neutral_bit
= State::S0
;
480 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
481 RTLIL::SigSpec new_sig_b
;
483 for (auto bit
: sig_b
)
484 if (bit
!= neutral_bit
) new_sig_b
.append(bit
);
486 if (GetSize(new_sig_b
) == 0)
487 new_sig_b
.append(neutral_bit
);
489 if (GetSize(new_sig_b
) < GetSize(sig_b
)) {
490 cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell
->type
.str());
491 log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
492 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_sig_b
));
493 cell
->setPort("\\B", new_sig_b
);
494 cell
->parameters
.at("\\B_WIDTH") = GetSize(new_sig_b
);
495 did_something
= true;
499 if (cell
->type
== "$reduce_and")
501 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
503 RTLIL::State new_a
= RTLIL::State::S1
;
504 for (auto &bit
: sig_a
.to_sigbit_vector())
505 if (bit
== RTLIL::State::Sx
) {
506 if (new_a
== RTLIL::State::S1
)
507 new_a
= RTLIL::State::Sx
;
508 } else if (bit
== RTLIL::State::S0
) {
509 new_a
= RTLIL::State::S0
;
511 } else if (bit
.wire
!= NULL
) {
512 new_a
= RTLIL::State::Sm
;
515 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
516 cover("opt.opt_expr.fine.$reduce_and");
517 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
518 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
519 cell
->setPort("\\A", sig_a
= new_a
);
520 cell
->parameters
.at("\\A_WIDTH") = 1;
521 did_something
= true;
525 if (cell
->type
== "$logic_not" || cell
->type
== "$logic_and" || cell
->type
== "$logic_or" || cell
->type
== "$reduce_or" || cell
->type
== "$reduce_bool")
527 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
529 RTLIL::State new_a
= RTLIL::State::S0
;
530 for (auto &bit
: sig_a
.to_sigbit_vector())
531 if (bit
== RTLIL::State::Sx
) {
532 if (new_a
== RTLIL::State::S0
)
533 new_a
= RTLIL::State::Sx
;
534 } else if (bit
== RTLIL::State::S1
) {
535 new_a
= RTLIL::State::S1
;
537 } else if (bit
.wire
!= NULL
) {
538 new_a
= RTLIL::State::Sm
;
541 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
542 cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell
->type
.str());
543 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
544 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
545 cell
->setPort("\\A", sig_a
= new_a
);
546 cell
->parameters
.at("\\A_WIDTH") = 1;
547 did_something
= true;
551 if (cell
->type
== "$logic_and" || cell
->type
== "$logic_or")
553 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
555 RTLIL::State new_b
= RTLIL::State::S0
;
556 for (auto &bit
: sig_b
.to_sigbit_vector())
557 if (bit
== RTLIL::State::Sx
) {
558 if (new_b
== RTLIL::State::S0
)
559 new_b
= RTLIL::State::Sx
;
560 } else if (bit
== RTLIL::State::S1
) {
561 new_b
= RTLIL::State::S1
;
563 } else if (bit
.wire
!= NULL
) {
564 new_b
= RTLIL::State::Sm
;
567 if (new_b
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_b
) != sig_b
) {
568 cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell
->type
.str());
569 log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
570 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_b
));
571 cell
->setPort("\\B", sig_b
= new_b
);
572 cell
->parameters
.at("\\B_WIDTH") = 1;
573 did_something
= true;
578 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" || cell
->type
== "$shift" || cell
->type
== "$shiftx" ||
579 cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" ||
580 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt" ||
581 cell
->type
== "$neg" || cell
->type
== "$add" || cell
->type
== "$sub" ||
582 cell
->type
== "$mul" || cell
->type
== "$div" || cell
->type
== "$mod" || cell
->type
== "$pow")
584 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
585 RTLIL::SigSpec sig_b
= cell
->hasPort("\\B") ? assign_map(cell
->getPort("\\B")) : RTLIL::SigSpec();
587 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" || cell
->type
== "$shift" || cell
->type
== "$shiftx")
588 sig_a
= RTLIL::SigSpec();
590 for (auto &bit
: sig_a
.to_sigbit_vector())
591 if (bit
== RTLIL::State::Sx
)
592 goto found_the_x_bit
;
594 for (auto &bit
: sig_b
.to_sigbit_vector())
595 if (bit
== RTLIL::State::Sx
)
596 goto found_the_x_bit
;
600 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
601 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell
->type
.str());
602 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" ||
603 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt")
604 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::State::Sx
);
606 replace_cell(assign_map
, module
, cell
, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx
, cell
->getPort("\\Y").size()));
611 if ((cell
->type
== "$_NOT_" || cell
->type
== "$not" || cell
->type
== "$logic_not") && cell
->getPort("\\Y").size() == 1 &&
612 invert_map
.count(assign_map(cell
->getPort("\\A"))) != 0) {
613 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell
->type
.str());
614 replace_cell(assign_map
, module
, cell
, "double_invert", "\\Y", invert_map
.at(assign_map(cell
->getPort("\\A"))));
618 if ((cell
->type
== "$_MUX_" || cell
->type
== "$mux") && invert_map
.count(assign_map(cell
->getPort("\\S"))) != 0) {
619 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell
->type
.str());
620 log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
621 RTLIL::SigSpec tmp
= cell
->getPort("\\A");
622 cell
->setPort("\\A", cell
->getPort("\\B"));
623 cell
->setPort("\\B", tmp
);
624 cell
->setPort("\\S", invert_map
.at(assign_map(cell
->getPort("\\S"))));
625 did_something
= true;
629 if (cell
->type
== "$_NOT_") {
630 RTLIL::SigSpec input
= cell
->getPort("\\A");
631 assign_map
.apply(input
);
632 if (input
.match("1")) ACTION_DO_Y(0);
633 if (input
.match("0")) ACTION_DO_Y(1);
634 if (input
.match("*")) ACTION_DO_Y(x
);
637 if (cell
->type
== "$_AND_") {
638 RTLIL::SigSpec input
;
639 input
.append(cell
->getPort("\\B"));
640 input
.append(cell
->getPort("\\A"));
641 assign_map
.apply(input
);
642 if (input
.match(" 0")) ACTION_DO_Y(0);
643 if (input
.match("0 ")) ACTION_DO_Y(0);
644 if (input
.match("11")) ACTION_DO_Y(1);
645 if (input
.match("**")) ACTION_DO_Y(x
);
646 if (input
.match("1*")) ACTION_DO_Y(x
);
647 if (input
.match("*1")) ACTION_DO_Y(x
);
649 if (input
.match(" *")) ACTION_DO_Y(0);
650 if (input
.match("* ")) ACTION_DO_Y(0);
652 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
653 if (input
.match("1 ")) ACTION_DO("\\Y", input
.extract(0, 1));
656 if (cell
->type
== "$_OR_") {
657 RTLIL::SigSpec input
;
658 input
.append(cell
->getPort("\\B"));
659 input
.append(cell
->getPort("\\A"));
660 assign_map
.apply(input
);
661 if (input
.match(" 1")) ACTION_DO_Y(1);
662 if (input
.match("1 ")) ACTION_DO_Y(1);
663 if (input
.match("00")) ACTION_DO_Y(0);
664 if (input
.match("**")) ACTION_DO_Y(x
);
665 if (input
.match("0*")) ACTION_DO_Y(x
);
666 if (input
.match("*0")) ACTION_DO_Y(x
);
668 if (input
.match(" *")) ACTION_DO_Y(1);
669 if (input
.match("* ")) ACTION_DO_Y(1);
671 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
672 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
675 if (cell
->type
== "$_XOR_") {
676 RTLIL::SigSpec input
;
677 input
.append(cell
->getPort("\\B"));
678 input
.append(cell
->getPort("\\A"));
679 assign_map
.apply(input
);
680 if (input
.match("00")) ACTION_DO_Y(0);
681 if (input
.match("01")) ACTION_DO_Y(1);
682 if (input
.match("10")) ACTION_DO_Y(1);
683 if (input
.match("11")) ACTION_DO_Y(0);
684 if (input
.match(" *")) ACTION_DO_Y(x
);
685 if (input
.match("* ")) ACTION_DO_Y(x
);
686 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
687 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
690 if (cell
->type
== "$_MUX_") {
691 RTLIL::SigSpec input
;
692 input
.append(cell
->getPort("\\S"));
693 input
.append(cell
->getPort("\\B"));
694 input
.append(cell
->getPort("\\A"));
695 assign_map
.apply(input
);
696 if (input
.extract(2, 1) == input
.extract(1, 1))
697 ACTION_DO("\\Y", input
.extract(2, 1));
698 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(2, 1));
699 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
700 if (input
.match("01 ")) ACTION_DO("\\Y", input
.extract(0, 1));
701 if (input
.match("10 ")) {
702 cover("opt.opt_expr.mux_to_inv");
703 cell
->type
= "$_NOT_";
704 cell
->setPort("\\A", input
.extract(0, 1));
705 cell
->unsetPort("\\B");
706 cell
->unsetPort("\\S");
709 if (input
.match("11 ")) ACTION_DO_Y(1);
710 if (input
.match("00 ")) ACTION_DO_Y(0);
711 if (input
.match("** ")) ACTION_DO_Y(x
);
712 if (input
.match("01*")) ACTION_DO_Y(x
);
713 if (input
.match("10*")) ACTION_DO_Y(x
);
715 if (input
.match("* ")) ACTION_DO("\\Y", input
.extract(1, 1));
716 if (input
.match(" * ")) ACTION_DO("\\Y", input
.extract(2, 1));
717 if (input
.match(" *")) ACTION_DO("\\Y", input
.extract(2, 1));
721 if (cell
->type
== "$eq" || cell
->type
== "$ne" || cell
->type
== "$eqx" || cell
->type
== "$nex")
723 RTLIL::SigSpec a
= cell
->getPort("\\A");
724 RTLIL::SigSpec b
= cell
->getPort("\\B");
726 if (cell
->parameters
["\\A_WIDTH"].as_int() != cell
->parameters
["\\B_WIDTH"].as_int()) {
727 int width
= max(cell
->parameters
["\\A_WIDTH"].as_int(), cell
->parameters
["\\B_WIDTH"].as_int());
728 a
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
729 b
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
732 RTLIL::SigSpec new_a
, new_b
;
734 log_assert(GetSize(a
) == GetSize(b
));
735 for (int i
= 0; i
< GetSize(a
); i
++) {
736 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
) {
737 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
738 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S0
: RTLIL::State::S1
);
739 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
740 replace_cell(assign_map
, module
, cell
, "isneq", "\\Y", new_y
);
749 if (new_a
.size() == 0) {
750 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
751 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S1
: RTLIL::State::S0
);
752 new_y
.extend_u0(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
753 replace_cell(assign_map
, module
, cell
, "empty", "\\Y", new_y
);
757 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
758 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
759 cell
->setPort("\\A", new_a
);
760 cell
->setPort("\\B", new_b
);
761 cell
->parameters
["\\A_WIDTH"] = new_a
.size();
762 cell
->parameters
["\\B_WIDTH"] = new_b
.size();
766 if ((cell
->type
== "$eq" || cell
->type
== "$ne") && cell
->parameters
["\\Y_WIDTH"].as_int() == 1 &&
767 cell
->parameters
["\\A_WIDTH"].as_int() == 1 && cell
->parameters
["\\B_WIDTH"].as_int() == 1)
769 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
770 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
772 if (a
.is_fully_const() && !b
.is_fully_const()) {
773 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell
->type
.str());
774 cell
->setPort("\\A", b
);
775 cell
->setPort("\\B", a
);
779 if (b
.is_fully_const()) {
780 if (b
.as_bool() == (cell
->type
== "$eq")) {
781 RTLIL::SigSpec input
= b
;
782 ACTION_DO("\\Y", cell
->getPort("\\A"));
784 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell
->type
.str());
785 log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
787 cell
->parameters
.erase("\\B_WIDTH");
788 cell
->parameters
.erase("\\B_SIGNED");
789 cell
->unsetPort("\\B");
790 did_something
= true;
796 if ((cell
->type
== "$eq" || cell
->type
== "$ne") &&
797 (assign_map(cell
->getPort("\\A")).is_fully_zero() || assign_map(cell
->getPort("\\B")).is_fully_zero()))
799 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell
->type
.str());
800 log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell
->type
), log_id(cell
),
801 log_id(module
), "$eq" ? "$logic_not" : "$reduce_bool");
802 cell
->type
= cell
->type
== "$eq" ? "$logic_not" : "$reduce_bool";
803 if (assign_map(cell
->getPort("\\A")).is_fully_zero()) {
804 cell
->setPort("\\A", cell
->getPort("\\B"));
805 cell
->setParam("\\A_SIGNED", cell
->getParam("\\B_SIGNED"));
806 cell
->setParam("\\A_WIDTH", cell
->getParam("\\B_WIDTH"));
808 cell
->unsetPort("\\B");
809 cell
->unsetParam("\\B_SIGNED");
810 cell
->unsetParam("\\B_WIDTH");
811 did_something
= true;
815 if (cell
->type
.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell
->getPort("\\B")).is_fully_const())
817 bool sign_ext
= cell
->type
== "$sshr" && cell
->getParam("\\A_SIGNED").as_bool();
818 int shift_bits
= assign_map(cell
->getPort("\\B")).as_int(cell
->type
.in("$shift", "$shiftx") && cell
->getParam("\\B_SIGNED").as_bool());
820 if (cell
->type
.in("$shl", "$sshl"))
823 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
824 RTLIL::SigSpec
sig_y(cell
->type
== "$shiftx" ? RTLIL::State::Sx
: RTLIL::State::S0
, cell
->getParam("\\Y_WIDTH").as_int());
826 if (GetSize(sig_a
) < GetSize(sig_y
))
827 sig_a
.extend_u0(GetSize(sig_y
), cell
->getParam("\\A_SIGNED").as_bool());
829 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
830 int idx
= i
+ shift_bits
;
831 if (0 <= idx
&& idx
< GetSize(sig_a
))
832 sig_y
[i
] = sig_a
[idx
];
833 else if (GetSize(sig_a
) <= idx
&& sign_ext
)
834 sig_y
[i
] = sig_a
[GetSize(sig_a
)-1];
837 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell
->type
.str());
839 log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
840 log_id(cell
->type
), log_id(cell
), log_signal(assign_map(cell
->getPort("\\B"))), shift_bits
, log_id(module
), log_signal(sig_y
));
842 module
->connect(cell
->getPort("\\Y"), sig_y
);
843 module
->remove(cell
);
845 did_something
= true;
851 bool identity_wrt_a
= false;
852 bool identity_wrt_b
= false;
853 bool arith_inverse
= false;
855 if (cell
->type
== "$add" || cell
->type
== "$sub" || cell
->type
== "$or" || cell
->type
== "$xor")
857 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
858 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
860 if (cell
->type
!= "$sub" && a
.is_fully_const() && a
.as_bool() == false)
861 identity_wrt_b
= true;
863 if (b
.is_fully_const() && b
.as_bool() == false)
864 identity_wrt_a
= true;
867 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" || cell
->type
== "$shift" || cell
->type
== "$shiftx")
869 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
871 if (b
.is_fully_const() && b
.as_bool() == false)
872 identity_wrt_a
= true;
875 if (cell
->type
== "$mul")
877 RTLIL::SigSpec a
= assign_map(cell
->getPort("\\A"));
878 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
880 if (a
.is_fully_const() && is_one_or_minus_one(a
.as_const(), cell
->getParam("\\A_SIGNED").as_bool(), arith_inverse
))
881 identity_wrt_b
= true;
883 if (b
.is_fully_const() && is_one_or_minus_one(b
.as_const(), cell
->getParam("\\B_SIGNED").as_bool(), arith_inverse
))
884 identity_wrt_a
= true;
887 if (cell
->type
== "$div")
889 RTLIL::SigSpec b
= assign_map(cell
->getPort("\\B"));
891 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
892 identity_wrt_a
= true;
895 if (identity_wrt_a
|| identity_wrt_b
)
898 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
900 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
902 log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
903 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
905 if (!identity_wrt_a
) {
906 cell
->setPort("\\A", cell
->getPort("\\B"));
907 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
908 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
911 cell
->type
= arith_inverse
? "$neg" : "$pos";
912 cell
->unsetPort("\\B");
913 cell
->parameters
.erase("\\B_WIDTH");
914 cell
->parameters
.erase("\\B_SIGNED");
917 did_something
= true;
922 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
923 cell
->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell
->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
924 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell
->type
.str());
925 replace_cell(assign_map
, module
, cell
, "mux_bool", "\\Y", cell
->getPort("\\S"));
929 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
930 cell
->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell
->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
931 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell
->type
.str());
932 log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
933 cell
->setPort("\\A", cell
->getPort("\\S"));
934 cell
->unsetPort("\\B");
935 cell
->unsetPort("\\S");
936 if (cell
->type
== "$mux") {
937 Const width
= cell
->parameters
["\\WIDTH"];
938 cell
->parameters
["\\A_WIDTH"] = width
;
939 cell
->parameters
["\\Y_WIDTH"] = width
;
940 cell
->parameters
["\\A_SIGNED"] = 0;
941 cell
->parameters
.erase("\\WIDTH");
944 cell
->type
= "$_NOT_";
945 did_something
= true;
949 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
950 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell
->type
.str());
951 log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
952 cell
->setPort("\\A", cell
->getPort("\\S"));
953 cell
->unsetPort("\\S");
954 if (cell
->type
== "$mux") {
955 Const width
= cell
->parameters
["\\WIDTH"];
956 cell
->parameters
["\\A_WIDTH"] = width
;
957 cell
->parameters
["\\B_WIDTH"] = width
;
958 cell
->parameters
["\\Y_WIDTH"] = width
;
959 cell
->parameters
["\\A_SIGNED"] = 0;
960 cell
->parameters
["\\B_SIGNED"] = 0;
961 cell
->parameters
.erase("\\WIDTH");
964 cell
->type
= "$_AND_";
965 did_something
= true;
969 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
970 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell
->type
.str());
971 log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
972 cell
->setPort("\\B", cell
->getPort("\\S"));
973 cell
->unsetPort("\\S");
974 if (cell
->type
== "$mux") {
975 Const width
= cell
->parameters
["\\WIDTH"];
976 cell
->parameters
["\\A_WIDTH"] = width
;
977 cell
->parameters
["\\B_WIDTH"] = width
;
978 cell
->parameters
["\\Y_WIDTH"] = width
;
979 cell
->parameters
["\\A_SIGNED"] = 0;
980 cell
->parameters
["\\B_SIGNED"] = 0;
981 cell
->parameters
.erase("\\WIDTH");
984 cell
->type
= "$_OR_";
985 did_something
= true;
989 if (mux_undef
&& (cell
->type
== "$mux" || cell
->type
== "$pmux")) {
990 RTLIL::SigSpec new_a
, new_b
, new_s
;
991 int width
= cell
->getPort("\\A").size();
992 if ((cell
->getPort("\\A").is_fully_undef() && cell
->getPort("\\B").is_fully_undef()) ||
993 cell
->getPort("\\S").is_fully_undef()) {
994 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell
->type
.str());
995 replace_cell(assign_map
, module
, cell
, "mux_undef", "\\Y", cell
->getPort("\\A"));
998 for (int i
= 0; i
< cell
->getPort("\\S").size(); i
++) {
999 RTLIL::SigSpec old_b
= cell
->getPort("\\B").extract(i
*width
, width
);
1000 RTLIL::SigSpec old_s
= cell
->getPort("\\S").extract(i
, 1);
1001 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
1003 new_b
.append(old_b
);
1004 new_s
.append(old_s
);
1006 new_a
= cell
->getPort("\\A");
1007 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
1008 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
1009 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
1010 new_s
= new_s
.extract(0, new_s
.size()-1);
1012 if (new_s
.size() == 0) {
1013 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell
->type
.str());
1014 replace_cell(assign_map
, module
, cell
, "mux_empty", "\\Y", new_a
);
1017 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
1018 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell
->type
.str());
1019 replace_cell(assign_map
, module
, cell
, "mux_sel01", "\\Y", new_s
);
1022 if (cell
->getPort("\\S").size() != new_s
.size()) {
1023 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell
->type
.str());
1024 log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1025 GetSize(cell
->getPort("\\S")) - GetSize(new_s
), log_id(cell
->type
), log_id(cell
), log_id(module
));
1026 cell
->setPort("\\A", new_a
);
1027 cell
->setPort("\\B", new_b
);
1028 cell
->setPort("\\S", new_s
);
1029 if (new_s
.size() > 1) {
1030 cell
->type
= "$pmux";
1031 cell
->parameters
["\\S_WIDTH"] = new_s
.size();
1033 cell
->type
= "$mux";
1034 cell
->parameters
.erase("\\S_WIDTH");
1036 did_something
= true;
1040 #define FOLD_1ARG_CELL(_t) \
1041 if (cell->type == "$" #_t) { \
1042 RTLIL::SigSpec a = cell->getPort("\\A"); \
1043 assign_map.apply(a); \
1044 if (a.is_fully_const()) { \
1045 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1046 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1047 cell->parameters["\\A_SIGNED"].as_bool(), false, \
1048 cell->parameters["\\Y_WIDTH"].as_int())); \
1049 cover("opt.opt_expr.const.$" #_t); \
1050 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
1054 #define FOLD_2ARG_CELL(_t) \
1055 if (cell->type == "$" #_t) { \
1056 RTLIL::SigSpec a = cell->getPort("\\A"); \
1057 RTLIL::SigSpec b = cell->getPort("\\B"); \
1058 assign_map.apply(a), assign_map.apply(b); \
1059 if (a.is_fully_const() && b.is_fully_const()) { \
1060 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1061 cell->parameters["\\A_SIGNED"].as_bool(), \
1062 cell->parameters["\\B_SIGNED"].as_bool(), \
1063 cell->parameters["\\Y_WIDTH"].as_int())); \
1064 cover("opt.opt_expr.const.$" #_t); \
1065 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
1074 FOLD_2ARG_CELL(xnor
)
1076 FOLD_1ARG_CELL(reduce_and
)
1077 FOLD_1ARG_CELL(reduce_or
)
1078 FOLD_1ARG_CELL(reduce_xor
)
1079 FOLD_1ARG_CELL(reduce_xnor
)
1080 FOLD_1ARG_CELL(reduce_bool
)
1082 FOLD_1ARG_CELL(logic_not
)
1083 FOLD_2ARG_CELL(logic_and
)
1084 FOLD_2ARG_CELL(logic_or
)
1088 FOLD_2ARG_CELL(sshl
)
1089 FOLD_2ARG_CELL(sshr
)
1090 FOLD_2ARG_CELL(shift
)
1091 FOLD_2ARG_CELL(shiftx
)
1110 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1111 if (cell
->type
== "$mux") {
1112 RTLIL::SigSpec input
= assign_map(cell
->getPort("\\S"));
1113 RTLIL::SigSpec inA
= assign_map(cell
->getPort("\\A"));
1114 RTLIL::SigSpec inB
= assign_map(cell
->getPort("\\B"));
1115 if (input
.is_fully_const())
1116 ACTION_DO("\\Y", input
.as_bool() ? cell
->getPort("\\B") : cell
->getPort("\\A"));
1117 else if (inA
== inB
)
1118 ACTION_DO("\\Y", cell
->getPort("\\A"));
1121 if (!keepdc
&& cell
->type
== "$mul")
1123 bool a_signed
= cell
->parameters
["\\A_SIGNED"].as_bool();
1124 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1125 bool swapped_ab
= false;
1127 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort("\\A"));
1128 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1129 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1131 if (sig_b
.is_fully_const() && sig_b
.size() <= 32)
1132 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
1134 if (sig_a
.is_fully_def() && sig_a
.size() <= 32)
1136 int a_val
= sig_a
.as_int();
1140 cover("opt.opt_expr.mul_shift.zero");
1142 log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1143 cell
->name
.c_str(), module
->name
.c_str());
1145 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
1146 module
->remove(cell
);
1148 did_something
= true;
1152 for (int i
= 1; i
< (a_signed
? sig_a
.size()-1 : sig_a
.size()); i
++)
1153 if (a_val
== (1 << i
))
1156 cover("opt.opt_expr.mul_shift.swapped");
1158 cover("opt.opt_expr.mul_shift.unswapped");
1160 log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1161 a_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1164 cell
->setPort("\\A", cell
->getPort("\\B"));
1165 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
1166 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
1169 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1171 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1174 cell
->type
= "$shl";
1175 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1176 cell
->parameters
["\\B_SIGNED"] = false;
1177 cell
->setPort("\\B", new_b
);
1180 did_something
= true;
1186 if (!keepdc
&& cell
->type
.in("$div", "$mod"))
1188 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1189 SigSpec sig_b
= assign_map(cell
->getPort("\\B"));
1190 SigSpec sig_y
= assign_map(cell
->getPort("\\Y"));
1192 if (sig_b
.is_fully_def() && sig_b
.size() <= 32)
1194 int b_val
= sig_b
.as_int();
1198 cover("opt.opt_expr.divmod_zero");
1200 log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1201 cell
->name
.c_str(), module
->name
.c_str());
1203 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(State::Sx
, sig_y
.size())));
1204 module
->remove(cell
);
1206 did_something
= true;
1210 for (int i
= 1; i
< (b_signed
? sig_b
.size()-1 : sig_b
.size()); i
++)
1211 if (b_val
== (1 << i
))
1213 if (cell
->type
== "$div")
1215 cover("opt.opt_expr.div_shift");
1217 log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1218 b_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1220 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1222 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1225 cell
->type
= "$shr";
1226 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1227 cell
->parameters
["\\B_SIGNED"] = false;
1228 cell
->setPort("\\B", new_b
);
1233 cover("opt.opt_expr.mod_mask");
1235 log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
1236 b_val
, cell
->name
.c_str(), module
->name
.c_str());
1238 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(State::S1
, i
);
1241 new_b
.push_back(State::S0
);
1243 cell
->type
= "$and";
1244 cell
->parameters
["\\B_WIDTH"] = GetSize(new_b
);
1245 cell
->setPort("\\B", new_b
);
1249 did_something
= true;
1255 // replace a<0 or a>=0 with the top bit of a
1256 if (do_fine
&& (cell
->type
== "$lt" || cell
->type
== "$ge" || cell
->type
== "$gt" || cell
->type
== "$le"))
1258 //used to decide whether the signal needs to be negated
1261 //references the variable signal in the comparison
1262 RTLIL::SigSpec sigVar
;
1264 //references the constant signal in the comparison
1265 RTLIL::SigSpec sigConst
;
1267 // note that this signal must be constant for the optimization
1268 // to take place, but it is not checked beforehand.
1269 // If new passes are added, this signal must be checked for const-ness
1271 //width of the variable port
1277 if (cell
->type
== "$lt" || cell
->type
== "$ge") {
1278 is_lt
= cell
->type
== "$lt" ? 1 : 0;
1279 sigVar
= cell
->getPort("\\A");
1280 sigConst
= cell
->getPort("\\B");
1281 width
= cell
->parameters
["\\A_WIDTH"].as_int();
1282 const_width
= cell
->parameters
["\\B_WIDTH"].as_int();
1283 var_signed
= cell
->parameters
["\\A_SIGNED"].as_bool();
1285 if (cell
->type
== "$gt" || cell
->type
== "$le") {
1286 is_lt
= cell
->type
== "$gt" ? 1 : 0;
1287 sigVar
= cell
->getPort("\\B");
1288 sigConst
= cell
->getPort("\\A");
1289 width
= cell
->parameters
["\\B_WIDTH"].as_int();
1290 const_width
= cell
->parameters
["\\A_WIDTH"].as_int();
1291 var_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
1295 // replace a(signed) < 0 with the high bit of a
1296 if (sigConst
.is_fully_const() && sigConst
.is_fully_zero() && var_signed
== true)
1298 RTLIL::SigSpec
a_prime(RTLIL::State::S0
, cell
->parameters
["\\Y_WIDTH"].as_int());
1299 a_prime
[0] = sigVar
[width
- 1];
1301 log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
1302 log_id(cell
->type
), log_id(cell
), width
-1, log_signal(a_prime
));
1303 module
->connect(cell
->getPort("\\Y"), a_prime
);
1304 module
->remove(cell
);
1306 log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
1307 log_id(cell
->type
), log_id(cell
), width
-1, log_signal(a_prime
));
1308 module
->addNot(NEW_ID
, a_prime
, cell
->getPort("\\Y"));
1309 module
->remove(cell
);
1311 did_something
= true;
1314 if (sigConst
.is_fully_const() && sigConst
.is_fully_def() && var_signed
== false)
1316 if (sigConst
.is_fully_zero()) {
1317 RTLIL::SigSpec
a_prime(RTLIL::State::S0
, 1);
1319 log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
1320 log_id(cell
->type
), log_id(cell
));
1321 a_prime
[0] = RTLIL::State::S0
;
1323 log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
1324 log_id(cell
->type
), log_id(cell
));
1325 a_prime
[0] = RTLIL::State::S1
;
1327 module
->connect(cell
->getPort("\\Y"), a_prime
);
1328 module
->remove(cell
);
1329 did_something
= true;
1333 int const_bit_set
= get_onehot_bit_index(sigConst
);
1334 if (const_bit_set
>= 0 && const_bit_set
< width
) {
1335 int bit_set
= const_bit_set
;
1336 RTLIL::SigSpec
a_prime(RTLIL::State::S0
, width
- bit_set
);
1337 for (int i
= bit_set
; i
< width
; i
++) {
1338 a_prime
[i
- bit_set
] = sigVar
[i
];
1341 log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
1342 log_id(cell
->type
), log_id(cell
), log_signal(sigConst
), width
- 1, bit_set
, log_signal(a_prime
));
1343 module
->addLogicNot(NEW_ID
, a_prime
, cell
->getPort("\\Y"));
1345 log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
1346 log_id(cell
->type
), log_id(cell
), log_signal(sigConst
), width
- 1, bit_set
, log_signal(a_prime
));
1347 module
->addReduceOr(NEW_ID
, a_prime
, cell
->getPort("\\Y"));
1349 module
->remove(cell
);
1350 did_something
= true;
1353 else if(const_bit_set
>= width
&& const_bit_set
>= 0){
1354 RTLIL::SigSpec
a_prime(RTLIL::State::S0
, 1);
1356 a_prime
[0] = RTLIL::State::S1
;
1357 log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell
->type
), log_id(cell
), width
-1, log_signal(sigConst
),const_width
-1);
1360 log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell
->type
), log_id(cell
), width
-1, log_signal(sigConst
),const_width
-1);
1362 module
->connect(cell
->getPort("\\Y"), a_prime
);
1363 module
->remove(cell
);
1364 did_something
= true;
1374 #undef FOLD_1ARG_CELL
1375 #undef FOLD_2ARG_CELL
1379 struct OptExprPass
: public Pass
{
1380 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
1383 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1385 log(" opt_expr [options] [selection]\n");
1387 log("This pass performs const folding on internal cell types with constant inputs.\n");
1388 log("It also performs some simple expression rewritring.\n");
1390 log(" -mux_undef\n");
1391 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
1393 log(" -mux_bool\n");
1394 log(" replace $mux cells with inverters or buffers when possible\n");
1396 log(" -undriven\n");
1397 log(" replace undriven nets with undef (x) constants\n");
1400 log(" optimize clock inverters by changing FF types\n");
1403 log(" perform fine-grain optimizations\n");
1406 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
1409 log(" some optimizations change the behavior of the circuit with respect to\n");
1410 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
1411 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
1412 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
1415 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
1417 bool mux_undef
= false;
1418 bool mux_bool
= false;
1419 bool undriven
= false;
1420 bool clkinv
= false;
1421 bool do_fine
= false;
1422 bool keepdc
= false;
1424 log_header(design
, "Executing OPT_EXPR pass (perform const folding).\n");
1428 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1429 if (args
[argidx
] == "-mux_undef") {
1433 if (args
[argidx
] == "-mux_bool") {
1437 if (args
[argidx
] == "-undriven") {
1441 if (args
[argidx
] == "-clkinv") {
1445 if (args
[argidx
] == "-fine") {
1449 if (args
[argidx
] == "-full") {
1456 if (args
[argidx
] == "-keepdc") {
1462 extra_args(args
, argidx
, design
);
1464 for (auto module
: design
->selected_modules())
1467 replace_undriven(design
, module
);
1471 did_something
= false;
1472 replace_const_cells(design
, module
, false, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1474 design
->scratchpad_set_bool("opt.did_something", true);
1475 } while (did_something
);
1476 replace_const_cells(design
, module
, true, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1477 } while (did_something
);
1484 PRIVATE_NAMESPACE_END