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::Module
*module
, const CellTypes
&ct
)
36 SigMap
sigmap(module
);
37 SigPool driven_signals
;
41 dict
<SigBit
, pair
<Wire
*, State
>> initbits
;
42 pool
<Wire
*> revisit_initwires
;
44 for (auto cell
: module
->cells())
45 for (auto &conn
: cell
->connections()) {
46 if (!ct
.cell_known(cell
->type
) || ct
.cell_output(cell
->type
, conn
.first
))
47 driven_signals
.add(sigmap(conn
.second
));
48 if (!ct
.cell_known(cell
->type
) || ct
.cell_input(cell
->type
, conn
.first
))
49 used_signals
.add(sigmap(conn
.second
));
52 for (auto wire
: module
->wires()) {
53 if (wire
->attributes
.count(ID::init
)) {
54 SigSpec sig
= sigmap(wire
);
55 Const initval
= wire
->attributes
.at(ID::init
);
56 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++) {
57 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
)
58 initbits
[sig
[i
]] = make_pair(wire
, initval
[i
]);
62 driven_signals
.add(sigmap(wire
));
63 if (wire
->port_output
|| wire
->get_bool_attribute(ID::keep
))
64 used_signals
.add(sigmap(wire
));
65 all_signals
.add(sigmap(wire
));
68 all_signals
.del(driven_signals
);
69 RTLIL::SigSpec undriven_signals
= all_signals
.export_all();
71 for (auto &c
: undriven_signals
.chunks())
73 RTLIL::SigSpec sig
= c
;
75 if (c
.wire
->name
[0] == '$')
76 sig
= used_signals
.extract(sig
);
80 Const
val(RTLIL::State::Sx
, GetSize(sig
));
81 for (int i
= 0; i
< GetSize(sig
); i
++) {
82 SigBit bit
= sigmap(sig
[i
]);
83 auto cursor
= initbits
.find(bit
);
84 if (cursor
!= initbits
.end()) {
85 revisit_initwires
.insert(cursor
->second
.first
);
86 val
[i
] = cursor
->second
.second
;
90 log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module
), log_signal(sig
), log_signal(val
));
91 module
->connect(sig
, val
);
95 if (!revisit_initwires
.empty())
99 for (auto wire
: revisit_initwires
) {
100 SigSpec sig
= sm2(wire
);
101 Const initval
= wire
->attributes
.at(ID::init
);
102 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++) {
103 if (SigBit(initval
[i
]) == sig
[i
])
104 initval
[i
] = State::Sx
;
106 if (initval
.is_fully_undef()) {
107 log_debug("Removing init attribute from %s/%s.\n", log_id(module
), log_id(wire
));
108 wire
->attributes
.erase(ID::init
);
109 did_something
= true;
110 } else if (initval
!= wire
->attributes
.at(ID::init
)) {
111 log_debug("Updating init attribute on %s/%s: %s\n", log_id(module
), log_id(wire
), log_signal(initval
));
112 wire
->attributes
[ID::init
] = initval
;
113 did_something
= true;
119 void replace_cell(SigMap
&assign_map
, RTLIL::Module
*module
, RTLIL::Cell
*cell
,
120 const std::string
&info
YS_ATTRIBUTE(unused
), IdString out_port
, RTLIL::SigSpec out_val
)
122 RTLIL::SigSpec Y
= cell
->getPort(out_port
);
123 out_val
.extend_u0(Y
.size(), false);
125 log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
126 cell
->type
.c_str(), cell
->name
.c_str(), info
.c_str(),
127 module
->name
.c_str(), log_signal(Y
), log_signal(out_val
));
129 assign_map
.add(Y
, out_val
);
130 module
->connect(Y
, out_val
);
131 module
->remove(cell
);
132 did_something
= true;
135 bool group_cell_inputs(RTLIL::Module
*module
, RTLIL::Cell
*cell
, bool commutative
, SigMap
&sigmap
)
137 IdString b_name
= cell
->hasPort(ID::B
) ? ID::B
: ID::A
;
139 bool a_signed
= cell
->parameters
.at(ID::A_SIGNED
).as_bool();
140 bool b_signed
= cell
->parameters
.at(b_name
.str() + "_SIGNED").as_bool();
142 RTLIL::SigSpec sig_a
= sigmap(cell
->getPort(ID::A
));
143 RTLIL::SigSpec sig_b
= sigmap(cell
->getPort(b_name
));
144 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
146 sig_a
.extend_u0(sig_y
.size(), a_signed
);
147 sig_b
.extend_u0(sig_y
.size(), b_signed
);
149 std::vector
<RTLIL::SigBit
> bits_a
= sig_a
, bits_b
= sig_b
, bits_y
= sig_y
;
151 enum { GRP_DYN
, GRP_CONST_A
, GRP_CONST_B
, GRP_CONST_AB
, GRP_N
};
152 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::set
<RTLIL::SigBit
>> grouped_bits
[GRP_N
];
154 for (int i
= 0; i
< GetSize(bits_y
); i
++)
156 int group_idx
= GRP_DYN
;
157 RTLIL::SigBit bit_a
= bits_a
[i
], bit_b
= bits_b
[i
];
159 if (cell
->type
== ID($
or) && (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
))
160 bit_a
= bit_b
= RTLIL::State::S1
;
162 if (cell
->type
== ID($
and) && (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
))
163 bit_a
= bit_b
= RTLIL::State::S0
;
165 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
166 group_idx
= GRP_CONST_AB
;
167 else if (bit_a
.wire
== NULL
)
168 group_idx
= GRP_CONST_A
;
169 else if (bit_b
.wire
== NULL
&& commutative
)
170 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
171 else if (bit_b
.wire
== NULL
)
172 group_idx
= GRP_CONST_B
;
174 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
177 for (int i
= 0; i
< GRP_N
; i
++)
178 if (GetSize(grouped_bits
[i
]) == GetSize(bits_y
))
181 log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
182 log_id(cell
->type
), log_id(cell
), log_id(module
));
184 for (int i
= 0; i
< GRP_N
; i
++)
186 if (grouped_bits
[i
].empty())
189 RTLIL::Wire
*new_y
= module
->addWire(NEW_ID
, GetSize(grouped_bits
[i
]));
190 RTLIL::SigSpec new_a
, new_b
;
191 RTLIL::SigSig new_conn
;
193 for (auto &it
: grouped_bits
[i
]) {
194 for (auto &bit
: it
.second
) {
195 new_conn
.first
.append(bit
);
196 new_conn
.second
.append(RTLIL::SigBit(new_y
, new_a
.size()));
198 new_a
.append(it
.first
.first
);
199 new_b
.append(it
.first
.second
);
202 if (cell
->type
.in(ID($
and), ID($
or)) && i
== GRP_CONST_A
) {
203 log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b
), log_id(cell
->type
), log_signal(new_a
));
204 module
->connect(new_y
, new_b
);
205 module
->connect(new_conn
);
209 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
211 c
->setPort(ID::A
, new_a
);
212 c
->parameters
[ID::A_WIDTH
] = new_a
.size();
213 c
->parameters
[ID::A_SIGNED
] = false;
215 if (b_name
== ID::B
) {
216 c
->setPort(ID::B
, new_b
);
217 c
->parameters
[ID::B_WIDTH
] = new_b
.size();
218 c
->parameters
[ID::B_SIGNED
] = false;
221 c
->setPort(ID::Y
, new_y
);
222 c
->parameters
[ID::Y_WIDTH
] = new_y
->width
;
225 module
->connect(new_conn
);
227 log_debug(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
229 log_debug(", B=%s", log_signal(new_b
));
233 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell
->type
.str());
235 module
->remove(cell
);
236 did_something
= true;
240 void handle_polarity_inv(Cell
*cell
, IdString port
, IdString param
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
242 SigSpec sig
= assign_map(cell
->getPort(port
));
243 if (invert_map
.count(sig
)) {
244 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
245 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
246 log_signal(sig
), log_signal(invert_map
.at(sig
)));
247 cell
->setPort(port
, (invert_map
.at(sig
)));
248 cell
->setParam(param
, !cell
->getParam(param
).as_bool());
252 void handle_clkpol_celltype_swap(Cell
*cell
, string type1
, string type2
, IdString port
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
254 log_assert(GetSize(type1
) == GetSize(type2
));
255 string cell_type
= cell
->type
.str();
257 if (GetSize(type1
) != GetSize(cell_type
))
260 for (int i
= 0; i
< GetSize(type1
); i
++) {
261 log_assert((type1
[i
] == '?') == (type2
[i
] == '?'));
262 if (type1
[i
] == '?') {
263 if (cell_type
[i
] != '0' && cell_type
[i
] != '1' && cell_type
[i
] != 'N' && cell_type
[i
] != 'P')
265 type1
[i
] = cell_type
[i
];
266 type2
[i
] = cell_type
[i
];
270 if (cell
->type
.in(type1
, type2
)) {
271 SigSpec sig
= assign_map(cell
->getPort(port
));
272 if (invert_map
.count(sig
)) {
273 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
274 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
275 log_signal(sig
), log_signal(invert_map
.at(sig
)));
276 cell
->setPort(port
, (invert_map
.at(sig
)));
277 cell
->type
= cell
->type
== type1
? type2
: type1
;
282 bool is_one_or_minus_one(const Const
&value
, bool is_signed
, bool &is_negative
)
284 bool all_bits_one
= true;
285 bool last_bit_one
= true;
287 if (GetSize(value
.bits
) < 1)
290 if (GetSize(value
.bits
) == 1) {
291 if (value
.bits
[0] != State::S1
)
298 for (int i
= 0; i
< GetSize(value
.bits
); i
++) {
299 if (value
.bits
[i
] != State::S1
)
300 all_bits_one
= false;
301 if (value
.bits
[i
] != (i
? State::S0
: State::S1
))
302 last_bit_one
= false;
305 if (all_bits_one
&& is_signed
) {
313 int get_highest_hot_index(RTLIL::SigSpec signal
)
315 for (int i
= GetSize(signal
) - 1; i
>= 0; i
--)
317 if (signal
[i
] == RTLIL::State::S0
)
320 if (signal
[i
] == RTLIL::State::S1
)
329 // if the signal has only one bit set, return the index of that bit.
330 // otherwise return -1
331 int get_onehot_bit_index(RTLIL::SigSpec signal
)
335 for (int i
= 0; i
< GetSize(signal
); i
++)
337 if (signal
[i
] == RTLIL::State::S0
)
340 if (signal
[i
] != RTLIL::State::S1
)
352 void replace_const_cells(RTLIL::Design
*design
, RTLIL::Module
*module
, bool consume_x
, bool mux_undef
, bool mux_bool
, bool do_fine
, bool keepdc
, bool clkinv
)
354 if (!design
->selected(module
))
357 CellTypes ct_combinational
;
358 ct_combinational
.setup_internals();
359 ct_combinational
.setup_stdcells();
361 SigMap
assign_map(module
);
362 dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
364 TopoSort
<RTLIL::Cell
*, RTLIL::IdString::compare_ptr_by_name
<RTLIL::Cell
>> cells
;
365 dict
<RTLIL::Cell
*, std::set
<RTLIL::SigBit
>> cell_to_inbit
;
366 dict
<RTLIL::SigBit
, std::set
<RTLIL::Cell
*>> outbit_to_cell
;
368 for (auto cell
: module
->cells())
369 if (design
->selected(module
, cell
) && cell
->type
[0] == '$') {
370 if (cell
->type
.in(ID($_NOT_
), ID($
not), ID($logic_not
)) &&
371 GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::Y
)) == 1)
372 invert_map
[assign_map(cell
->getPort(ID::Y
))] = assign_map(cell
->getPort(ID::A
));
373 if (cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
374 cell
->getPort(ID::A
) == SigSpec(State::S1
) && cell
->getPort(ID::B
) == SigSpec(State::S0
))
375 invert_map
[assign_map(cell
->getPort(ID::Y
))] = assign_map(cell
->getPort(ID::S
));
376 if (ct_combinational
.cell_known(cell
->type
))
377 for (auto &conn
: cell
->connections()) {
378 RTLIL::SigSpec sig
= assign_map(conn
.second
);
380 if (ct_combinational
.cell_input(cell
->type
, conn
.first
))
381 cell_to_inbit
[cell
].insert(sig
.begin(), sig
.end());
382 if (ct_combinational
.cell_output(cell
->type
, conn
.first
))
383 for (auto &bit
: sig
)
384 outbit_to_cell
[bit
].insert(cell
);
389 for (auto &it_right
: cell_to_inbit
)
390 for (auto &it_sigbit
: it_right
.second
)
391 for (auto &it_left
: outbit_to_cell
[it_sigbit
])
392 cells
.edge(it_left
, it_right
.first
);
396 for (auto cell
: cells
.sorted
)
398 #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)
399 #define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
403 if (cell
->type
.in(ID($dff
), ID($dffe
), ID($dffsr
), ID($adff
), ID($fsm
), ID($memrd
), ID($memwr
)))
404 handle_polarity_inv(cell
, ID::CLK
, ID::CLK_POLARITY
, assign_map
, invert_map
);
406 if (cell
->type
.in(ID($sr
), ID($dffsr
), ID($dlatchsr
))) {
407 handle_polarity_inv(cell
, ID::SET
, ID::SET_POLARITY
, assign_map
, invert_map
);
408 handle_polarity_inv(cell
, ID::CLR
, ID::CLR_POLARITY
, assign_map
, invert_map
);
411 if (cell
->type
.in(ID($dffe
), ID($dlatch
), ID($dlatchsr
)))
412 handle_polarity_inv(cell
, ID::EN
, ID::EN_POLARITY
, assign_map
, invert_map
);
414 handle_clkpol_celltype_swap(cell
, "$_SR_N?_", "$_SR_P?_", ID::S
, assign_map
, invert_map
);
415 handle_clkpol_celltype_swap(cell
, "$_SR_?N_", "$_SR_?P_", ID::R
, assign_map
, invert_map
);
417 handle_clkpol_celltype_swap(cell
, "$_DFF_N_", "$_DFF_P_", ID::C
, assign_map
, invert_map
);
419 handle_clkpol_celltype_swap(cell
, "$_DFFE_N?_", "$_DFFE_P?_", ID::C
, assign_map
, invert_map
);
420 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N_", "$_DFFE_?P_", ID::E
, assign_map
, invert_map
);
422 handle_clkpol_celltype_swap(cell
, "$_DFF_N??_", "$_DFF_P??_", ID::C
, assign_map
, invert_map
);
423 handle_clkpol_celltype_swap(cell
, "$_DFF_?N?_", "$_DFF_?P?_", ID::R
, assign_map
, invert_map
);
425 handle_clkpol_celltype_swap(cell
, "$_DFFSR_N??_", "$_DFFSR_P??_", ID::C
, assign_map
, invert_map
);
426 handle_clkpol_celltype_swap(cell
, "$_DFFSR_?N?_", "$_DFFSR_?P?_", ID::S
, assign_map
, invert_map
);
427 handle_clkpol_celltype_swap(cell
, "$_DFFSR_??N_", "$_DFFSR_??P_", ID::R
, assign_map
, invert_map
);
429 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N_", "$_DLATCH_P_", ID::E
, assign_map
, invert_map
);
431 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID::E
, assign_map
, invert_map
);
432 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID::S
, assign_map
, invert_map
);
433 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R
, assign_map
, invert_map
);
436 bool detect_const_and
= false;
437 bool detect_const_or
= false;
439 if (cell
->type
.in(ID($reduce_and
), ID($_AND_
)))
440 detect_const_and
= true;
442 if (cell
->type
.in(ID($
and), ID($logic_and
)) && GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::B
)) == 1 && !cell
->getParam(ID::A_SIGNED
).as_bool())
443 detect_const_and
= true;
445 if (cell
->type
.in(ID($reduce_or
), ID($reduce_bool
), ID($_OR_
)))
446 detect_const_or
= true;
448 if (cell
->type
.in(ID($
or), ID($logic_or
)) && GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::B
)) == 1 && !cell
->getParam(ID::A_SIGNED
).as_bool())
449 detect_const_or
= true;
451 if (detect_const_and
|| detect_const_or
)
453 pool
<SigBit
> input_bits
= assign_map(cell
->getPort(ID::A
)).to_sigbit_pool();
454 bool found_zero
= false, found_one
= false, found_undef
= false, found_inv
= false, many_conconst
= false;
455 SigBit non_const_input
= State::Sm
;
457 if (cell
->hasPort(ID::B
)) {
458 vector
<SigBit
> more_bits
= assign_map(cell
->getPort(ID::B
)).to_sigbit_vector();
459 input_bits
.insert(more_bits
.begin(), more_bits
.end());
462 for (auto bit
: input_bits
) {
464 if (invert_map
.count(bit
) && input_bits
.count(invert_map
.at(bit
)))
466 if (non_const_input
!= State::Sm
)
467 many_conconst
= true;
468 non_const_input
= many_conconst
? State::Sm
: bit
;
470 if (bit
== State::S0
)
472 else if (bit
== State::S1
)
479 if (detect_const_and
&& (found_zero
|| found_inv
)) {
480 cover("opt.opt_expr.const_and");
481 replace_cell(assign_map
, module
, cell
, "const_and", ID::Y
, RTLIL::State::S0
);
485 if (detect_const_or
&& (found_one
|| found_inv
)) {
486 cover("opt.opt_expr.const_or");
487 replace_cell(assign_map
, module
, cell
, "const_or", ID::Y
, RTLIL::State::S1
);
491 if (non_const_input
!= State::Sm
&& !found_undef
) {
492 cover("opt.opt_expr.and_or_buffer");
493 replace_cell(assign_map
, module
, cell
, "and_or_buffer", ID::Y
, non_const_input
);
498 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)) || (cell
->type
.in(ID($
xor), ID($xnor
)) && GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::B
)) == 1 && !cell
->getParam(ID::A_SIGNED
).as_bool()))
500 SigBit sig_a
= assign_map(cell
->getPort(ID::A
));
501 SigBit sig_b
= assign_map(cell
->getPort(ID::B
));
503 std::swap(sig_a
, sig_b
);
504 if (sig_b
== State::S0
|| sig_b
== State::S1
) {
505 if (cell
->type
.in(ID($
xor), ID($_XOR_
))) {
506 cover("opt.opt_expr.xor_buffer");
508 if (cell
->type
== ID($
xor))
509 sig_y
= (sig_b
== State::S1
? module
->Not(NEW_ID
, sig_a
).as_bit() : sig_a
);
510 else if (cell
->type
== ID($_XOR_
))
511 sig_y
= (sig_b
== State::S1
? module
->NotGate(NEW_ID
, sig_a
) : sig_a
);
513 replace_cell(assign_map
, module
, cell
, "xor_buffer", ID::Y
, sig_y
);
516 if (cell
->type
.in(ID($xnor
), ID($_XNOR_
))) {
517 cover("opt.opt_expr.xnor_buffer");
519 if (cell
->type
== ID($xnor
)) {
520 sig_y
= (sig_b
== State::S1
? sig_a
: module
->Not(NEW_ID
, sig_a
).as_bit());
521 int width
= cell
->getParam(ID::Y_WIDTH
).as_int();
522 sig_y
.append(RTLIL::Const(State::S1
, width
-1));
524 else if (cell
->type
== ID($_XNOR_
))
525 sig_y
= (sig_b
== State::S1
? sig_a
: module
->NotGate(NEW_ID
, sig_a
));
527 replace_cell(assign_map
, module
, cell
, "xnor_buffer", ID::Y
, sig_y
);
534 if (cell
->type
.in(ID($reduce_and
), ID($reduce_or
), ID($reduce_bool
), ID($reduce_xor
), ID($reduce_xnor
), ID($neg
)) &&
535 GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::Y
)) == 1)
537 if (cell
->type
== ID($reduce_xnor
)) {
538 cover("opt.opt_expr.reduce_xnor_not");
539 log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
540 log_id(cell
->type
), log_id(cell
->name
), log_id(module
));
541 cell
->type
= ID($
not);
542 did_something
= true;
544 cover("opt.opt_expr.unary_buffer");
545 replace_cell(assign_map
, module
, cell
, "unary_buffer", ID::Y
, cell
->getPort(ID::A
));
552 if (cell
->type
.in(ID($
not), ID($pos
), ID($
and), ID($
or), ID($
xor), ID($xnor
)))
553 if (group_cell_inputs(module
, cell
, true, assign_map
))
556 if (cell
->type
.in(ID($logic_not
), ID($logic_and
), ID($logic_or
), ID($reduce_or
), ID($reduce_and
), ID($reduce_bool
)))
558 SigBit neutral_bit
= cell
->type
== ID($reduce_and
) ? State::S1
: State::S0
;
560 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
561 RTLIL::SigSpec new_sig_a
;
563 for (auto bit
: sig_a
)
564 if (bit
!= neutral_bit
) new_sig_a
.append(bit
);
566 if (GetSize(new_sig_a
) == 0)
567 new_sig_a
.append(neutral_bit
);
569 if (GetSize(new_sig_a
) < GetSize(sig_a
)) {
570 cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell
->type
.str());
571 log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
572 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_sig_a
));
573 cell
->setPort(ID::A
, new_sig_a
);
574 cell
->parameters
.at(ID::A_WIDTH
) = GetSize(new_sig_a
);
575 did_something
= true;
579 if (cell
->type
.in(ID($logic_and
), ID($logic_or
)))
581 SigBit neutral_bit
= State::S0
;
583 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
584 RTLIL::SigSpec new_sig_b
;
586 for (auto bit
: sig_b
)
587 if (bit
!= neutral_bit
) new_sig_b
.append(bit
);
589 if (GetSize(new_sig_b
) == 0)
590 new_sig_b
.append(neutral_bit
);
592 if (GetSize(new_sig_b
) < GetSize(sig_b
)) {
593 cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell
->type
.str());
594 log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
595 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_sig_b
));
596 cell
->setPort(ID::B
, new_sig_b
);
597 cell
->parameters
.at(ID::B_WIDTH
) = GetSize(new_sig_b
);
598 did_something
= true;
602 if (cell
->type
== ID($reduce_and
))
604 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
606 RTLIL::State new_a
= RTLIL::State::S1
;
607 for (auto &bit
: sig_a
.to_sigbit_vector())
608 if (bit
== RTLIL::State::Sx
) {
609 if (new_a
== RTLIL::State::S1
)
610 new_a
= RTLIL::State::Sx
;
611 } else if (bit
== RTLIL::State::S0
) {
612 new_a
= RTLIL::State::S0
;
614 } else if (bit
.wire
!= NULL
) {
615 new_a
= RTLIL::State::Sm
;
618 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
619 cover("opt.opt_expr.fine.$reduce_and");
620 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
621 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
622 cell
->setPort(ID::A
, sig_a
= new_a
);
623 cell
->parameters
.at(ID::A_WIDTH
) = 1;
624 did_something
= true;
628 if (cell
->type
.in(ID($logic_not
), ID($logic_and
), ID($logic_or
), ID($reduce_or
), ID($reduce_bool
)))
630 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
632 RTLIL::State new_a
= RTLIL::State::S0
;
633 for (auto &bit
: sig_a
.to_sigbit_vector())
634 if (bit
== RTLIL::State::Sx
) {
635 if (new_a
== RTLIL::State::S0
)
636 new_a
= RTLIL::State::Sx
;
637 } else if (bit
== RTLIL::State::S1
) {
638 new_a
= RTLIL::State::S1
;
640 } else if (bit
.wire
!= NULL
) {
641 new_a
= RTLIL::State::Sm
;
644 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
645 cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell
->type
.str());
646 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
647 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
648 cell
->setPort(ID::A
, sig_a
= new_a
);
649 cell
->parameters
.at(ID::A_WIDTH
) = 1;
650 did_something
= true;
654 if (cell
->type
.in(ID($logic_and
), ID($logic_or
)))
656 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
658 RTLIL::State new_b
= RTLIL::State::S0
;
659 for (auto &bit
: sig_b
.to_sigbit_vector())
660 if (bit
== RTLIL::State::Sx
) {
661 if (new_b
== RTLIL::State::S0
)
662 new_b
= RTLIL::State::Sx
;
663 } else if (bit
== RTLIL::State::S1
) {
664 new_b
= RTLIL::State::S1
;
666 } else if (bit
.wire
!= NULL
) {
667 new_b
= RTLIL::State::Sm
;
670 if (new_b
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_b
) != sig_b
) {
671 cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell
->type
.str());
672 log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
673 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_b
));
674 cell
->setPort(ID::B
, sig_b
= new_b
);
675 cell
->parameters
.at(ID::B_WIDTH
) = 1;
676 did_something
= true;
680 if (cell
->type
.in(ID($add
), ID($sub
)))
682 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
683 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
684 RTLIL::SigSpec sig_y
= cell
->getPort(ID::Y
);
685 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
686 bool sub
= cell
->type
== ID($sub
);
688 int minsz
= GetSize(sig_y
);
689 minsz
= std::min(minsz
, GetSize(sig_a
));
690 minsz
= std::min(minsz
, GetSize(sig_b
));
693 for (i
= 0; i
< minsz
; i
++) {
694 RTLIL::SigBit b
= sig_b
[i
];
695 RTLIL::SigBit a
= sig_a
[i
];
697 module
->connect(sig_y
[i
], a
);
698 else if (sub
&& b
== State::S1
&& a
== State::S1
)
699 module
->connect(sig_y
[i
], State::S0
);
700 else if (!sub
&& a
== State::S0
)
701 module
->connect(sig_y
[i
], b
);
706 cover_list("opt.opt_expr.fine", "$add", "$sub", cell
->type
.str());
707 log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i
, log_id(cell
->type
), log_id(cell
), log_id(module
));
708 SigSpec new_a
= sig_a
.extract_end(i
);
709 SigSpec new_b
= sig_b
.extract_end(i
);
710 if (new_a
.empty() && is_signed
)
712 if (new_b
.empty() && is_signed
)
714 cell
->setPort(ID::A
, new_a
);
715 cell
->setPort(ID::B
, new_b
);
716 cell
->setPort(ID::Y
, sig_y
.extract_end(i
));
717 cell
->fixup_parameters();
718 did_something
= true;
722 if (cell
->type
== ID($alu
))
724 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
725 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
726 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
727 RTLIL::SigBit sig_bi
= assign_map(cell
->getPort(ID::BI
));
728 RTLIL::SigSpec sig_x
= cell
->getPort(ID::X
);
729 RTLIL::SigSpec sig_y
= cell
->getPort(ID::Y
);
730 RTLIL::SigSpec sig_co
= cell
->getPort(ID::CO
);
731 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
733 if (sig_bi
!= State::S0
&& sig_bi
!= State::S1
)
735 if (sig_ci
!= State::S0
&& sig_ci
!= State::S1
)
738 bool bi
= sig_bi
== State::S1
;
739 bool ci
= sig_ci
== State::S1
;
741 int minsz
= GetSize(sig_y
);
742 minsz
= std::min(minsz
, GetSize(sig_a
));
743 minsz
= std::min(minsz
, GetSize(sig_b
));
746 for (i
= 0; i
< minsz
; i
++) {
747 RTLIL::SigBit b
= sig_b
[i
];
748 RTLIL::SigBit a
= sig_a
[i
];
749 if (b
== ((bi
^ ci
) ? State::S1
: State::S0
)) {
750 module
->connect(sig_y
[i
], a
);
751 module
->connect(sig_x
[i
], ci
? module
->Not(NEW_ID
, a
).as_bit() : a
);
752 module
->connect(sig_co
[i
], ci
? State::S1
: State::S0
);
754 else if (a
== (ci
? State::S1
: State::S0
)) {
755 module
->connect(sig_y
[i
], bi
? module
->Not(NEW_ID
, b
).as_bit() : b
);
756 module
->connect(sig_x
[i
], (bi
^ ci
) ? module
->Not(NEW_ID
, b
).as_bit() : b
);
757 module
->connect(sig_co
[i
], ci
? State::S1
: State::S0
);
763 cover("opt.opt_expr.fine.$alu");
764 log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i
, log_id(cell
->type
), log_id(cell
), log_id(module
));
765 SigSpec new_a
= sig_a
.extract_end(i
);
766 SigSpec new_b
= sig_b
.extract_end(i
);
767 if (new_a
.empty() && is_signed
)
769 if (new_b
.empty() && is_signed
)
771 cell
->setPort(ID::A
, new_a
);
772 cell
->setPort(ID::B
, new_b
);
773 cell
->setPort(ID::X
, sig_x
.extract_end(i
));
774 cell
->setPort(ID::Y
, sig_y
.extract_end(i
));
775 cell
->setPort(ID::CO
, sig_co
.extract_end(i
));
776 cell
->fixup_parameters();
777 did_something
= true;
783 if (cell
->type
.in(ID($reduce_xor
), ID($reduce_xnor
), ID($shift
), ID($shiftx
), ID($shl
), ID($shr
), ID($sshl
), ID($sshr
),
784 ID($lt
), ID($le
), ID($ge
), ID($gt
), ID($neg
), ID($add
), ID($sub
), ID($mul
), ID($div
), ID($mod
), ID($pow
)))
786 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
787 RTLIL::SigSpec sig_b
= cell
->hasPort(ID::B
) ? assign_map(cell
->getPort(ID::B
)) : RTLIL::SigSpec();
789 if (cell
->type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
), ID($shift
), ID($shiftx
)))
790 sig_a
= RTLIL::SigSpec();
792 for (auto &bit
: sig_a
.to_sigbit_vector())
793 if (bit
== RTLIL::State::Sx
)
794 goto found_the_x_bit
;
796 for (auto &bit
: sig_b
.to_sigbit_vector())
797 if (bit
== RTLIL::State::Sx
)
798 goto found_the_x_bit
;
802 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
803 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell
->type
.str());
804 if (cell
->type
.in(ID($reduce_xor
), ID($reduce_xnor
), ID($lt
), ID($le
), ID($ge
), ID($gt
)))
805 replace_cell(assign_map
, module
, cell
, "x-bit in input", ID::Y
, RTLIL::State::Sx
);
807 replace_cell(assign_map
, module
, cell
, "x-bit in input", ID::Y
, RTLIL::SigSpec(RTLIL::State::Sx
, GetSize(cell
->getPort(ID::Y
))));
812 if (cell
->type
.in(ID($shiftx
), ID($shift
))) {
813 SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
815 bool trim_x
= cell
->type
== ID($shiftx
) || !keepdc
;
816 bool trim_0
= cell
->type
== ID($shift
);
817 for (width
= GetSize(sig_a
); width
> 1; width
--) {
818 if ((trim_x
&& sig_a
[width
-1] == State::Sx
) ||
819 (trim_0
&& sig_a
[width
-1] == State::S0
))
824 if (width
< GetSize(sig_a
)) {
825 cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell
->type
.str());
826 sig_a
.remove(width
, GetSize(sig_a
)-width
);
827 cell
->setPort(ID::A
, sig_a
);
828 cell
->setParam(ID::A_WIDTH
, width
);
829 did_something
= true;
834 if (cell
->type
.in(ID($_NOT_
), ID($
not), ID($logic_not
)) && GetSize(cell
->getPort(ID::Y
)) == 1 &&
835 invert_map
.count(assign_map(cell
->getPort(ID::A
))) != 0) {
836 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell
->type
.str());
837 replace_cell(assign_map
, module
, cell
, "double_invert", ID::Y
, invert_map
.at(assign_map(cell
->getPort(ID::A
))));
841 if (cell
->type
.in(ID($_MUX_
), ID($mux
)) && invert_map
.count(assign_map(cell
->getPort(ID::S
))) != 0) {
842 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell
->type
.str());
843 log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
844 RTLIL::SigSpec tmp
= cell
->getPort(ID::A
);
845 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
846 cell
->setPort(ID::B
, tmp
);
847 cell
->setPort(ID::S
, invert_map
.at(assign_map(cell
->getPort(ID::S
))));
848 did_something
= true;
852 if (cell
->type
== ID($_NOT_
)) {
853 RTLIL::SigSpec input
= cell
->getPort(ID::A
);
854 assign_map
.apply(input
);
855 if (input
.match("1")) ACTION_DO_Y(0);
856 if (input
.match("0")) ACTION_DO_Y(1);
857 if (input
.match("*")) ACTION_DO_Y(x
);
860 if (cell
->type
== ID($_AND_
)) {
861 RTLIL::SigSpec input
;
862 input
.append(cell
->getPort(ID::B
));
863 input
.append(cell
->getPort(ID::A
));
864 assign_map
.apply(input
);
865 if (input
.match(" 0")) ACTION_DO_Y(0);
866 if (input
.match("0 ")) ACTION_DO_Y(0);
867 if (input
.match("11")) ACTION_DO_Y(1);
868 if (input
.match("**")) ACTION_DO_Y(x
);
869 if (input
.match("1*")) ACTION_DO_Y(x
);
870 if (input
.match("*1")) ACTION_DO_Y(x
);
872 if (input
.match(" *")) ACTION_DO_Y(0);
873 if (input
.match("* ")) ACTION_DO_Y(0);
875 if (input
.match(" 1")) ACTION_DO(ID::Y
, input
.extract(1, 1));
876 if (input
.match("1 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
879 if (cell
->type
== ID($_OR_
)) {
880 RTLIL::SigSpec input
;
881 input
.append(cell
->getPort(ID::B
));
882 input
.append(cell
->getPort(ID::A
));
883 assign_map
.apply(input
);
884 if (input
.match(" 1")) ACTION_DO_Y(1);
885 if (input
.match("1 ")) ACTION_DO_Y(1);
886 if (input
.match("00")) ACTION_DO_Y(0);
887 if (input
.match("**")) ACTION_DO_Y(x
);
888 if (input
.match("0*")) ACTION_DO_Y(x
);
889 if (input
.match("*0")) ACTION_DO_Y(x
);
891 if (input
.match(" *")) ACTION_DO_Y(1);
892 if (input
.match("* ")) ACTION_DO_Y(1);
894 if (input
.match(" 0")) ACTION_DO(ID::Y
, input
.extract(1, 1));
895 if (input
.match("0 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
898 if (cell
->type
== ID($_XOR_
)) {
899 RTLIL::SigSpec input
;
900 input
.append(cell
->getPort(ID::B
));
901 input
.append(cell
->getPort(ID::A
));
902 assign_map
.apply(input
);
903 if (input
.match("00")) ACTION_DO_Y(0);
904 if (input
.match("01")) ACTION_DO_Y(1);
905 if (input
.match("10")) ACTION_DO_Y(1);
906 if (input
.match("11")) ACTION_DO_Y(0);
907 if (input
.match(" *")) ACTION_DO_Y(x
);
908 if (input
.match("* ")) ACTION_DO_Y(x
);
911 if (cell
->type
== ID($_MUX_
)) {
912 RTLIL::SigSpec input
;
913 input
.append(cell
->getPort(ID::S
));
914 input
.append(cell
->getPort(ID::B
));
915 input
.append(cell
->getPort(ID::A
));
916 assign_map
.apply(input
);
917 if (input
.extract(2, 1) == input
.extract(1, 1))
918 ACTION_DO(ID::Y
, input
.extract(2, 1));
919 if (input
.match(" 0")) ACTION_DO(ID::Y
, input
.extract(2, 1));
920 if (input
.match(" 1")) ACTION_DO(ID::Y
, input
.extract(1, 1));
921 if (input
.match("01 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
922 if (input
.match("10 ")) {
923 cover("opt.opt_expr.mux_to_inv");
924 cell
->type
= ID($_NOT_
);
925 cell
->setPort(ID::A
, input
.extract(0, 1));
926 cell
->unsetPort(ID::B
);
927 cell
->unsetPort(ID::S
);
930 if (input
.match("11 ")) ACTION_DO_Y(1);
931 if (input
.match("00 ")) ACTION_DO_Y(0);
932 if (input
.match("** ")) ACTION_DO_Y(x
);
933 if (input
.match("01*")) ACTION_DO_Y(x
);
934 if (input
.match("10*")) ACTION_DO_Y(x
);
936 if (input
.match("* ")) ACTION_DO(ID::Y
, input
.extract(1, 1));
937 if (input
.match(" * ")) ACTION_DO(ID::Y
, input
.extract(2, 1));
938 if (input
.match(" *")) ACTION_DO(ID::Y
, input
.extract(2, 1));
942 if (cell
->type
.in(ID($_TBUF_
), ID($tribuf
))) {
943 RTLIL::SigSpec input
= cell
->getPort(cell
->type
== ID($_TBUF_
) ? ID::E
: ID::EN
);
944 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
945 assign_map
.apply(input
);
947 if (input
== State::S1
)
948 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
949 if (input
== State::S0
&& !a
.is_fully_undef()) {
950 cover("opt.opt_expr.action_" S__LINE__
);
951 log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
952 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str());
953 cell
->setPort(ID::A
, SigSpec(State::Sx
, GetSize(a
)));
954 did_something
= true;
959 if (cell
->type
.in(ID($eq
), ID($ne
), ID($eqx
), ID($nex
)))
961 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
962 RTLIL::SigSpec b
= cell
->getPort(ID::B
);
964 if (cell
->parameters
[ID::A_WIDTH
].as_int() != cell
->parameters
[ID::B_WIDTH
].as_int()) {
965 int width
= max(cell
->parameters
[ID::A_WIDTH
].as_int(), cell
->parameters
[ID::B_WIDTH
].as_int());
966 a
.extend_u0(width
, cell
->parameters
[ID::A_SIGNED
].as_bool() && cell
->parameters
[ID::B_SIGNED
].as_bool());
967 b
.extend_u0(width
, cell
->parameters
[ID::A_SIGNED
].as_bool() && cell
->parameters
[ID::B_SIGNED
].as_bool());
970 RTLIL::SigSpec new_a
, new_b
;
972 log_assert(GetSize(a
) == GetSize(b
));
973 for (int i
= 0; i
< GetSize(a
); i
++) {
974 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
) {
975 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
976 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in(ID($eq
), ID($eqx
)) ? RTLIL::State::S0
: RTLIL::State::S1
);
977 new_y
.extend_u0(cell
->parameters
[ID::Y_WIDTH
].as_int(), false);
978 replace_cell(assign_map
, module
, cell
, "isneq", ID::Y
, new_y
);
987 if (new_a
.size() == 0) {
988 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
989 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in(ID($eq
), ID($eqx
)) ? RTLIL::State::S1
: RTLIL::State::S0
);
990 new_y
.extend_u0(cell
->parameters
[ID::Y_WIDTH
].as_int(), false);
991 replace_cell(assign_map
, module
, cell
, "empty", ID::Y
, new_y
);
995 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
996 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
997 cell
->setPort(ID::A
, new_a
);
998 cell
->setPort(ID::B
, new_b
);
999 cell
->parameters
[ID::A_WIDTH
] = new_a
.size();
1000 cell
->parameters
[ID::B_WIDTH
] = new_b
.size();
1004 if (cell
->type
.in(ID($eq
), ID($ne
)) && cell
->parameters
[ID::Y_WIDTH
].as_int() == 1 &&
1005 cell
->parameters
[ID::A_WIDTH
].as_int() == 1 && cell
->parameters
[ID::B_WIDTH
].as_int() == 1)
1007 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1008 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1010 if (a
.is_fully_const() && !b
.is_fully_const()) {
1011 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell
->type
.str());
1012 cell
->setPort(ID::A
, b
);
1013 cell
->setPort(ID::B
, a
);
1017 if (b
.is_fully_const()) {
1018 if (b
.is_fully_undef()) {
1019 RTLIL::SigSpec input
= b
;
1020 ACTION_DO(ID::Y
, Const(State::Sx
, GetSize(cell
->getPort(ID::Y
))));
1022 if (b
.as_bool() == (cell
->type
== ID($eq
))) {
1023 RTLIL::SigSpec input
= b
;
1024 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
1026 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell
->type
.str());
1027 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1028 cell
->type
= ID($
not);
1029 cell
->parameters
.erase(ID::B_WIDTH
);
1030 cell
->parameters
.erase(ID::B_SIGNED
);
1031 cell
->unsetPort(ID::B
);
1032 did_something
= true;
1038 if (cell
->type
.in(ID($eq
), ID($ne
)) &&
1039 (assign_map(cell
->getPort(ID::A
)).is_fully_zero() || assign_map(cell
->getPort(ID::B
)).is_fully_zero()))
1041 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell
->type
.str());
1042 log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell
->type
), log_id(cell
),
1043 log_id(module
), cell
->type
== ID($eq
) ? "$logic_not" : "$reduce_bool");
1044 cell
->type
= cell
->type
== ID($eq
) ? ID($logic_not
) : ID($reduce_bool
);
1045 if (assign_map(cell
->getPort(ID::A
)).is_fully_zero()) {
1046 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1047 cell
->setParam(ID::A_SIGNED
, cell
->getParam(ID::B_SIGNED
));
1048 cell
->setParam(ID::A_WIDTH
, cell
->getParam(ID::B_WIDTH
));
1050 cell
->unsetPort(ID::B
);
1051 cell
->unsetParam(ID::B_SIGNED
);
1052 cell
->unsetParam(ID::B_WIDTH
);
1053 did_something
= true;
1057 if (cell
->type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
), ID($shift
), ID($shiftx
)) && assign_map(cell
->getPort(ID::B
)).is_fully_const())
1059 bool sign_ext
= cell
->type
== ID($sshr
) && cell
->getParam(ID::A_SIGNED
).as_bool();
1060 int shift_bits
= assign_map(cell
->getPort(ID::B
)).as_int(cell
->type
.in(ID($shift
), ID($shiftx
)) && cell
->getParam(ID::B_SIGNED
).as_bool());
1062 if (cell
->type
.in(ID($shl
), ID($sshl
)))
1065 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1066 RTLIL::SigSpec
sig_y(cell
->type
== ID($shiftx
) ? RTLIL::State::Sx
: RTLIL::State::S0
, cell
->getParam(ID::Y_WIDTH
).as_int());
1068 if (GetSize(sig_a
) < GetSize(sig_y
))
1069 sig_a
.extend_u0(GetSize(sig_y
), cell
->getParam(ID::A_SIGNED
).as_bool());
1071 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
1072 int idx
= i
+ shift_bits
;
1073 if (0 <= idx
&& idx
< GetSize(sig_a
))
1074 sig_y
[i
] = sig_a
[idx
];
1075 else if (GetSize(sig_a
) <= idx
&& sign_ext
)
1076 sig_y
[i
] = sig_a
[GetSize(sig_a
)-1];
1079 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell
->type
.str());
1081 log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
1082 log_id(cell
->type
), log_id(cell
), log_signal(assign_map(cell
->getPort(ID::B
))), shift_bits
, log_id(module
), log_signal(sig_y
));
1084 module
->connect(cell
->getPort(ID::Y
), sig_y
);
1085 module
->remove(cell
);
1087 did_something
= true;
1093 bool identity_wrt_a
= false;
1094 bool identity_wrt_b
= false;
1095 bool arith_inverse
= false;
1097 if (cell
->type
.in(ID($add
), ID($sub
), ID($alu
), ID($
or), ID($
xor)))
1099 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1100 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1102 bool sub
= cell
->type
== ID($sub
);
1104 if (cell
->type
== ID($alu
)) {
1105 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
1106 RTLIL::SigBit sig_bi
= assign_map(cell
->getPort(ID::BI
));
1108 sub
= (sig_ci
== State::S1
&& sig_bi
== State::S1
);
1110 // If not a subtraction, yet there is a carry or B is inverted
1111 // then no optimisation is possible as carry will not be constant
1112 if (!sub
&& (sig_ci
!= State::S0
|| sig_bi
!= State::S0
))
1116 if (!sub
&& a
.is_fully_const() && a
.as_bool() == false)
1117 identity_wrt_b
= true;
1119 if (b
.is_fully_const() && b
.as_bool() == false)
1120 identity_wrt_a
= true;
1123 if (cell
->type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
), ID($shift
), ID($shiftx
)))
1125 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1127 if (b
.is_fully_const() && b
.as_bool() == false)
1128 identity_wrt_a
= true;
1131 if (cell
->type
== ID($mul
))
1133 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1134 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1136 if (a
.is_fully_const() && is_one_or_minus_one(a
.as_const(), cell
->getParam(ID::A_SIGNED
).as_bool(), arith_inverse
))
1137 identity_wrt_b
= true;
1139 if (b
.is_fully_const() && is_one_or_minus_one(b
.as_const(), cell
->getParam(ID::B_SIGNED
).as_bool(), arith_inverse
))
1140 identity_wrt_a
= true;
1143 if (cell
->type
== ID($div
))
1145 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1147 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
1148 identity_wrt_a
= true;
1151 if (identity_wrt_a
|| identity_wrt_b
)
1154 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1156 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1158 log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
1159 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
1161 if (cell
->type
== ID($alu
)) {
1162 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1163 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1164 bool is_signed
= a_signed
&& b_signed
;
1165 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
1166 int y_width
= GetSize(cell
->getPort(ID::Y
));
1167 if (sig_ci
== State::S1
) {
1169 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
1170 a
.extend_u0(y_width
, is_signed
);
1171 module
->connect(cell
->getPort(ID::X
), module
->Not(NEW_ID
, a
));
1172 module
->connect(cell
->getPort(ID::CO
), RTLIL::Const(State::S1
, y_width
));
1175 RTLIL::SigSpec ab
= cell
->getPort(identity_wrt_a
? ID::A
: ID::B
);
1176 ab
.extend_u0(y_width
, is_signed
);
1177 module
->connect(cell
->getPort(ID::X
), ab
);
1178 module
->connect(cell
->getPort(ID::CO
), RTLIL::Const(State::S0
, y_width
));
1180 cell
->unsetPort(ID::BI
);
1181 cell
->unsetPort(ID::CI
);
1182 cell
->unsetPort(ID::X
);
1183 cell
->unsetPort(ID::CO
);
1186 if (!identity_wrt_a
) {
1187 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1188 cell
->setParam(ID::A_WIDTH
, cell
->getParam(ID::B_WIDTH
));
1189 cell
->setParam(ID::A_SIGNED
, cell
->getParam(ID::B_SIGNED
));
1192 cell
->type
= arith_inverse
? ID($neg
) : ID($pos
);
1193 cell
->unsetPort(ID::B
);
1194 cell
->parameters
.erase(ID::B_WIDTH
);
1195 cell
->parameters
.erase(ID::B_SIGNED
);
1198 did_something
= true;
1204 if (mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
1205 cell
->getPort(ID::A
) == State::S0
&& cell
->getPort(ID::B
) == State::S1
) {
1206 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell
->type
.str());
1207 replace_cell(assign_map
, module
, cell
, "mux_bool", ID::Y
, cell
->getPort(ID::S
));
1211 if (mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
1212 cell
->getPort(ID::A
) == State::S1
&& cell
->getPort(ID::B
) == State::S0
) {
1213 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell
->type
.str());
1214 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1215 cell
->setPort(ID::A
, cell
->getPort(ID::S
));
1216 cell
->unsetPort(ID::B
);
1217 cell
->unsetPort(ID::S
);
1218 if (cell
->type
== ID($mux
)) {
1219 Const width
= cell
->parameters
[ID::WIDTH
];
1220 cell
->parameters
[ID::A_WIDTH
] = width
;
1221 cell
->parameters
[ID::Y_WIDTH
] = width
;
1222 cell
->parameters
[ID::A_SIGNED
] = 0;
1223 cell
->parameters
.erase(ID::WIDTH
);
1224 cell
->type
= ID($
not);
1226 cell
->type
= ID($_NOT_
);
1227 did_something
= true;
1231 if (consume_x
&& mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) && cell
->getPort(ID::A
) == State::S0
) {
1232 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell
->type
.str());
1233 log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1234 cell
->setPort(ID::A
, cell
->getPort(ID::S
));
1235 cell
->unsetPort(ID::S
);
1236 if (cell
->type
== ID($mux
)) {
1237 Const width
= cell
->parameters
[ID::WIDTH
];
1238 cell
->parameters
[ID::A_WIDTH
] = width
;
1239 cell
->parameters
[ID::B_WIDTH
] = width
;
1240 cell
->parameters
[ID::Y_WIDTH
] = width
;
1241 cell
->parameters
[ID::A_SIGNED
] = 0;
1242 cell
->parameters
[ID::B_SIGNED
] = 0;
1243 cell
->parameters
.erase(ID::WIDTH
);
1244 cell
->type
= ID($
and);
1246 cell
->type
= ID($_AND_
);
1247 did_something
= true;
1251 if (consume_x
&& mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) && cell
->getPort(ID::B
) == State::S1
) {
1252 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell
->type
.str());
1253 log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1254 cell
->setPort(ID::B
, cell
->getPort(ID::S
));
1255 cell
->unsetPort(ID::S
);
1256 if (cell
->type
== ID($mux
)) {
1257 Const width
= cell
->parameters
[ID::WIDTH
];
1258 cell
->parameters
[ID::A_WIDTH
] = width
;
1259 cell
->parameters
[ID::B_WIDTH
] = width
;
1260 cell
->parameters
[ID::Y_WIDTH
] = width
;
1261 cell
->parameters
[ID::A_SIGNED
] = 0;
1262 cell
->parameters
[ID::B_SIGNED
] = 0;
1263 cell
->parameters
.erase(ID::WIDTH
);
1264 cell
->type
= ID($
or);
1266 cell
->type
= ID($_OR_
);
1267 did_something
= true;
1271 if (mux_undef
&& cell
->type
.in(ID($mux
), ID($pmux
))) {
1272 RTLIL::SigSpec new_a
, new_b
, new_s
;
1273 int width
= GetSize(cell
->getPort(ID::A
));
1274 if ((cell
->getPort(ID::A
).is_fully_undef() && cell
->getPort(ID::B
).is_fully_undef()) ||
1275 cell
->getPort(ID::S
).is_fully_undef()) {
1276 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell
->type
.str());
1277 replace_cell(assign_map
, module
, cell
, "mux_undef", ID::Y
, cell
->getPort(ID::A
));
1280 for (int i
= 0; i
< cell
->getPort(ID::S
).size(); i
++) {
1281 RTLIL::SigSpec old_b
= cell
->getPort(ID::B
).extract(i
*width
, width
);
1282 RTLIL::SigSpec old_s
= cell
->getPort(ID::S
).extract(i
, 1);
1283 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
1285 new_b
.append(old_b
);
1286 new_s
.append(old_s
);
1288 new_a
= cell
->getPort(ID::A
);
1289 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
1290 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
1291 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
1292 new_s
= new_s
.extract(0, new_s
.size()-1);
1294 if (new_s
.size() == 0) {
1295 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell
->type
.str());
1296 replace_cell(assign_map
, module
, cell
, "mux_empty", ID::Y
, new_a
);
1299 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
1300 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell
->type
.str());
1301 replace_cell(assign_map
, module
, cell
, "mux_sel01", ID::Y
, new_s
);
1304 if (cell
->getPort(ID::S
).size() != new_s
.size()) {
1305 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell
->type
.str());
1306 log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1307 GetSize(cell
->getPort(ID::S
)) - GetSize(new_s
), log_id(cell
->type
), log_id(cell
), log_id(module
));
1308 cell
->setPort(ID::A
, new_a
);
1309 cell
->setPort(ID::B
, new_b
);
1310 cell
->setPort(ID::S
, new_s
);
1311 if (new_s
.size() > 1) {
1312 cell
->type
= ID($pmux
);
1313 cell
->parameters
[ID::S_WIDTH
] = new_s
.size();
1315 cell
->type
= ID($mux
);
1316 cell
->parameters
.erase(ID::S_WIDTH
);
1318 did_something
= true;
1322 #define FOLD_1ARG_CELL(_t) \
1323 if (cell->type == ID($##_t)) { \
1324 RTLIL::SigSpec a = cell->getPort(ID::A); \
1325 assign_map.apply(a); \
1326 if (a.is_fully_const()) { \
1327 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1328 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1329 cell->parameters[ID::A_SIGNED].as_bool(), false, \
1330 cell->parameters[ID::Y_WIDTH].as_int())); \
1331 cover("opt.opt_expr.const.$" #_t); \
1332 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \
1336 #define FOLD_2ARG_CELL(_t) \
1337 if (cell->type == ID($##_t)) { \
1338 RTLIL::SigSpec a = cell->getPort(ID::A); \
1339 RTLIL::SigSpec b = cell->getPort(ID::B); \
1340 assign_map.apply(a), assign_map.apply(b); \
1341 if (a.is_fully_const() && b.is_fully_const()) { \
1342 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1343 cell->parameters[ID::A_SIGNED].as_bool(), \
1344 cell->parameters[ID::B_SIGNED].as_bool(), \
1345 cell->parameters[ID::Y_WIDTH].as_int())); \
1346 cover("opt.opt_expr.const.$" #_t); \
1347 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
1356 FOLD_2ARG_CELL(xnor
)
1358 FOLD_1ARG_CELL(reduce_and
)
1359 FOLD_1ARG_CELL(reduce_or
)
1360 FOLD_1ARG_CELL(reduce_xor
)
1361 FOLD_1ARG_CELL(reduce_xnor
)
1362 FOLD_1ARG_CELL(reduce_bool
)
1364 FOLD_1ARG_CELL(logic_not
)
1365 FOLD_2ARG_CELL(logic_and
)
1366 FOLD_2ARG_CELL(logic_or
)
1370 FOLD_2ARG_CELL(sshl
)
1371 FOLD_2ARG_CELL(sshr
)
1372 FOLD_2ARG_CELL(shift
)
1373 FOLD_2ARG_CELL(shiftx
)
1392 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1393 if (cell
->type
== ID($mux
)) {
1394 RTLIL::SigSpec input
= assign_map(cell
->getPort(ID::S
));
1395 RTLIL::SigSpec inA
= assign_map(cell
->getPort(ID::A
));
1396 RTLIL::SigSpec inB
= assign_map(cell
->getPort(ID::B
));
1397 if (input
.is_fully_const())
1398 ACTION_DO(ID::Y
, input
.as_bool() ? cell
->getPort(ID::B
) : cell
->getPort(ID::A
));
1399 else if (inA
== inB
)
1400 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
1403 if (!keepdc
&& cell
->type
== ID($mul
))
1405 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1406 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1407 bool swapped_ab
= false;
1409 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1410 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1411 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1413 if (sig_b
.is_fully_const() && sig_b
.size() <= 32)
1414 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
1416 if (sig_a
.is_fully_def() && sig_a
.size() <= 32)
1418 int a_val
= sig_a
.as_int();
1422 cover("opt.opt_expr.mul_shift.zero");
1424 log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1425 cell
->name
.c_str(), module
->name
.c_str());
1427 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
1428 module
->remove(cell
);
1430 did_something
= true;
1434 for (int i
= 1; i
< (a_signed
? sig_a
.size()-1 : sig_a
.size()); i
++)
1435 if (a_val
== (1 << i
))
1438 cover("opt.opt_expr.mul_shift.swapped");
1440 cover("opt.opt_expr.mul_shift.unswapped");
1442 log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1443 a_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1446 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1447 cell
->parameters
.at(ID::A_WIDTH
) = cell
->parameters
.at(ID::B_WIDTH
);
1448 cell
->parameters
.at(ID::A_SIGNED
) = cell
->parameters
.at(ID::B_SIGNED
);
1451 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1453 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1456 cell
->type
= ID($shl
);
1457 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1458 cell
->parameters
[ID::B_SIGNED
] = false;
1459 cell
->setPort(ID::B
, new_b
);
1462 did_something
= true;
1467 sig_a
= assign_map(cell
->getPort(ID::A
));
1468 sig_b
= assign_map(cell
->getPort(ID::B
));
1469 int a_zeros
, b_zeros
;
1470 for (a_zeros
= 0; a_zeros
< GetSize(sig_a
); a_zeros
++)
1471 if (sig_a
[a_zeros
] != RTLIL::State::S0
)
1473 for (b_zeros
= 0; b_zeros
< GetSize(sig_b
); b_zeros
++)
1474 if (sig_b
[b_zeros
] != RTLIL::State::S0
)
1476 if (a_zeros
|| b_zeros
) {
1477 int y_zeros
= a_zeros
+ b_zeros
;
1478 cover("opt.opt_expr.mul_low_zeros");
1480 log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n",
1481 a_zeros
, b_zeros
, cell
->name
.c_str(), module
->name
.c_str());
1484 cell
->setPort(ID::A
, sig_a
.extract_end(a_zeros
));
1485 cell
->parameters
[ID::A_WIDTH
] = GetSize(sig_a
) - a_zeros
;
1488 cell
->setPort(ID::B
, sig_b
.extract_end(b_zeros
));
1489 cell
->parameters
[ID::B_WIDTH
] = GetSize(sig_b
) - b_zeros
;
1491 cell
->setPort(ID::Y
, sig_y
.extract_end(y_zeros
));
1492 cell
->parameters
[ID::Y_WIDTH
] = GetSize(sig_y
) - y_zeros
;
1493 module
->connect(RTLIL::SigSig(sig_y
.extract(0, y_zeros
), RTLIL::SigSpec(0, y_zeros
)));
1496 did_something
= true;
1501 if (!keepdc
&& cell
->type
.in(ID($div
), ID($mod
)))
1503 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1504 SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1505 SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1507 if (sig_b
.is_fully_def() && sig_b
.size() <= 32)
1509 int b_val
= sig_b
.as_int();
1513 cover("opt.opt_expr.divmod_zero");
1515 log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1516 cell
->name
.c_str(), module
->name
.c_str());
1518 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(State::Sx
, sig_y
.size())));
1519 module
->remove(cell
);
1521 did_something
= true;
1525 for (int i
= 1; i
< (b_signed
? sig_b
.size()-1 : sig_b
.size()); i
++)
1526 if (b_val
== (1 << i
))
1528 if (cell
->type
== ID($div
))
1530 cover("opt.opt_expr.div_shift");
1532 log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1533 b_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
1535 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
1537 while (GetSize(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
1540 cell
->type
= ID($shr
);
1541 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1542 cell
->parameters
[ID::B_SIGNED
] = false;
1543 cell
->setPort(ID::B
, new_b
);
1548 cover("opt.opt_expr.mod_mask");
1550 log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
1551 b_val
, cell
->name
.c_str(), module
->name
.c_str());
1553 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(State::S1
, i
);
1556 new_b
.push_back(State::S0
);
1558 cell
->type
= ID($
and);
1559 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1560 cell
->setPort(ID::B
, new_b
);
1564 did_something
= true;
1570 // Find places in $alu cell where the carry is constant, and split it at these points.
1571 if (do_fine
&& !keepdc
&& cell
->type
== ID($alu
))
1573 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1574 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1575 bool is_signed
= a_signed
&& b_signed
;
1577 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1578 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1579 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1580 RTLIL::SigSpec sig_bi
= assign_map(cell
->getPort(ID::BI
));
1581 if (GetSize(sig_a
) == 0)
1583 if (GetSize(sig_b
) == 0)
1585 sig_a
.extend_u0(GetSize(sig_y
), is_signed
);
1586 sig_b
.extend_u0(GetSize(sig_y
), is_signed
);
1588 if (sig_bi
!= State::S0
&& sig_bi
!= State::S1
)
1589 goto skip_alu_split
;
1591 std::vector
<std::pair
<int, State
>> split_points
;
1593 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
1594 SigBit bit_a
= sig_a
[i
];
1595 SigBit bit_b
= sig_b
[i
];
1596 if (bit_a
!= State::S0
&& bit_a
!= State::S1
)
1598 if (bit_b
!= State::S0
&& bit_b
!= State::S1
)
1600 if (sig_bi
== State::S1
) {
1601 if (bit_b
== State::S0
)
1608 split_points
.push_back(std::make_pair(i
+ 1, bit_a
.data
));
1611 if (split_points
.empty() || split_points
[0].first
== GetSize(sig_y
))
1612 goto skip_alu_split
;
1614 for (auto &p
: split_points
)
1615 log_debug("Splitting $alu cell `%s' in module `%s' at const-carry point %d.\n",
1616 cell
->name
.c_str(), module
->name
.c_str(), p
.first
);
1618 if (split_points
.back().first
!= GetSize(sig_y
))
1619 split_points
.push_back(std::make_pair(GetSize(sig_y
), State::Sx
));
1621 RTLIL::SigSpec sig_ci
= assign_map(cell
->getPort(ID::CI
));
1623 RTLIL::SigSpec sig_x
= assign_map(cell
->getPort(ID::X
));
1624 RTLIL::SigSpec sig_co
= assign_map(cell
->getPort(ID::CO
));
1626 for (auto &p
: split_points
) {
1628 int sz
= cur
- prev
;
1629 bool last
= cur
== GetSize(sig_y
);
1631 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
1632 c
->setPort(ID::A
, sig_a
.extract(prev
, sz
));
1633 c
->setPort(ID::B
, sig_b
.extract(prev
, sz
));
1634 c
->setPort(ID::BI
, sig_bi
);
1635 c
->setPort(ID::CI
, sig_ci
);
1636 c
->setPort(ID::Y
, sig_y
.extract(prev
, sz
));
1637 c
->setPort(ID::X
, sig_x
.extract(prev
, sz
));
1638 RTLIL::SigSpec new_co
= sig_co
.extract(prev
, sz
);
1639 if (p
.second
!= State::Sx
) {
1640 module
->connect(new_co
[sz
-1], p
.second
);
1641 RTLIL::Wire
*dummy
= module
->addWire(NEW_ID
);
1642 new_co
[sz
-1] = dummy
;
1644 c
->setPort(ID::CO
, new_co
);
1645 c
->parameters
[ID::A_WIDTH
] = sz
;
1646 c
->parameters
[ID::B_WIDTH
] = sz
;
1647 c
->parameters
[ID::Y_WIDTH
] = sz
;
1648 c
->parameters
[ID::A_SIGNED
] = last
? a_signed
: false;
1649 c
->parameters
[ID::B_SIGNED
] = last
? b_signed
: false;
1655 cover("opt.opt_expr.alu_split");
1656 module
->remove(cell
);
1658 did_something
= true;
1663 // remove redundant pairs of bits in ==, ===, !=, and !==
1664 // replace cell with const driver if inputs can't be equal
1665 if (do_fine
&& cell
->type
.in(ID($eq
), ID($ne
), ID($eqx
), ID($nex
)))
1667 pool
<pair
<SigBit
, SigBit
>> redundant_cache
;
1668 mfp
<SigBit
> contradiction_cache
;
1670 contradiction_cache
.promote(State::S0
);
1671 contradiction_cache
.promote(State::S1
);
1673 int a_width
= cell
->getParam(ID::A_WIDTH
).as_int();
1674 int b_width
= cell
->getParam(ID::B_WIDTH
).as_int();
1676 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
1677 int width
= is_signed
? std::min(a_width
, b_width
) : std::max(a_width
, b_width
);
1679 SigSpec sig_a
= cell
->getPort(ID::A
);
1680 SigSpec sig_b
= cell
->getPort(ID::B
);
1682 int redundant_bits
= 0;
1684 for (int i
= width
-1; i
>= 0; i
--)
1686 SigBit bit_a
= i
< a_width
? assign_map(sig_a
[i
]) : State::S0
;
1687 SigBit bit_b
= i
< b_width
? assign_map(sig_b
[i
]) : State::S0
;
1689 if (bit_a
!= State::Sx
&& bit_a
!= State::Sz
&&
1690 bit_b
!= State::Sx
&& bit_b
!= State::Sz
)
1691 contradiction_cache
.merge(bit_a
, bit_b
);
1694 std::swap(bit_a
, bit_b
);
1696 pair
<SigBit
, SigBit
> key(bit_a
, bit_b
);
1698 if (redundant_cache
.count(key
)) {
1699 if (i
< a_width
) sig_a
.remove(i
);
1700 if (i
< b_width
) sig_b
.remove(i
);
1705 redundant_cache
.insert(key
);
1708 if (contradiction_cache
.find(State::S0
) == contradiction_cache
.find(State::S1
))
1710 SigSpec y_sig
= cell
->getPort(ID::Y
);
1711 Const
y_value(cell
->type
.in(ID($eq
), ID($eqx
)) ? 0 : 1, GetSize(y_sig
));
1713 log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
1714 log_id(cell
), log_id(module
), log_signal(y_value
));
1716 module
->connect(y_sig
, y_value
);
1717 module
->remove(cell
);
1719 did_something
= true;
1725 log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
1726 redundant_bits
, log_id(cell
->type
), log_id(cell
), log_id(module
));
1728 cell
->setPort(ID::A
, sig_a
);
1729 cell
->setPort(ID::B
, sig_b
);
1730 cell
->setParam(ID::A_WIDTH
, GetSize(sig_a
));
1731 cell
->setParam(ID::B_WIDTH
, GetSize(sig_b
));
1733 did_something
= true;
1738 // simplify comparisons
1739 if (do_fine
&& cell
->type
.in(ID($lt
), ID($ge
), ID($gt
), ID($le
)))
1741 IdString cmp_type
= cell
->type
;
1742 SigSpec var_sig
= cell
->getPort(ID::A
);
1743 SigSpec const_sig
= cell
->getPort(ID::B
);
1744 int var_width
= cell
->parameters
[ID::A_WIDTH
].as_int();
1745 int const_width
= cell
->parameters
[ID::B_WIDTH
].as_int();
1746 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
1748 if (!const_sig
.is_fully_const())
1750 std::swap(var_sig
, const_sig
);
1751 std::swap(var_width
, const_width
);
1752 if (cmp_type
== ID($gt
))
1754 else if (cmp_type
== ID($lt
))
1756 else if (cmp_type
== ID($ge
))
1758 else if (cmp_type
== ID($le
))
1762 if (const_sig
.is_fully_def() && const_sig
.is_fully_const())
1764 std::string condition
, replacement
;
1765 SigSpec
replace_sig(State::S0
, GetSize(cell
->getPort(ID::Y
)));
1766 bool replace
= false;
1767 bool remove
= false;
1771 if (const_sig
.is_fully_zero() && cmp_type
== ID($lt
)) {
1772 condition
= "unsigned X<0";
1773 replacement
= "constant 0";
1774 replace_sig
[0] = State::S0
;
1777 if (const_sig
.is_fully_zero() && cmp_type
== ID($ge
)) {
1778 condition
= "unsigned X>=0";
1779 replacement
= "constant 1";
1780 replace_sig
[0] = State::S1
;
1783 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== ID($gt
)) {
1784 condition
= "unsigned X>~0";
1785 replacement
= "constant 0";
1786 replace_sig
[0] = State::S0
;
1789 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== ID($le
)) {
1790 condition
= "unsigned X<=~0";
1791 replacement
= "constant 1";
1792 replace_sig
[0] = State::S1
;
1796 int const_bit_hot
= get_onehot_bit_index(const_sig
);
1797 if (const_bit_hot
>= 0 && const_bit_hot
< var_width
)
1799 RTLIL::SigSpec
var_high_sig(RTLIL::State::S0
, var_width
- const_bit_hot
);
1800 for (int i
= const_bit_hot
; i
< var_width
; i
++) {
1801 var_high_sig
[i
- const_bit_hot
] = var_sig
[i
];
1804 if (cmp_type
== ID($lt
))
1806 condition
= stringf("unsigned X<%s", log_signal(const_sig
));
1807 replacement
= stringf("!X[%d:%d]", var_width
- 1, const_bit_hot
);
1808 module
->addLogicNot(NEW_ID
, var_high_sig
, cell
->getPort(ID::Y
));
1811 if (cmp_type
== ID($ge
))
1813 condition
= stringf("unsigned X>=%s", log_signal(const_sig
));
1814 replacement
= stringf("|X[%d:%d]", var_width
- 1, const_bit_hot
);
1815 module
->addReduceOr(NEW_ID
, var_high_sig
, cell
->getPort(ID::Y
));
1820 int const_bit_set
= get_highest_hot_index(const_sig
);
1821 if (const_bit_set
>= var_width
)
1824 if (cmp_type
== ID($lt
) || cmp_type
== ID($le
))
1826 if (cmp_type
== ID($lt
)) cmp_name
= "<";
1827 if (cmp_type
== ID($le
)) cmp_name
= "<=";
1828 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1829 replacement
= "constant 1";
1830 replace_sig
[0] = State::S1
;
1833 if (cmp_type
== ID($gt
) || cmp_type
== ID($ge
))
1835 if (cmp_type
== ID($gt
)) cmp_name
= ">";
1836 if (cmp_type
== ID($ge
)) cmp_name
= ">=";
1837 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1838 replacement
= "constant 0";
1839 replace_sig
[0] = State::S0
;
1846 if (const_sig
.is_fully_zero() && cmp_type
== ID($lt
))
1848 condition
= "signed X<0";
1849 replacement
= stringf("X[%d]", var_width
- 1);
1850 replace_sig
[0] = var_sig
[var_width
- 1];
1853 if (const_sig
.is_fully_zero() && cmp_type
== ID($ge
))
1855 condition
= "signed X>=0";
1856 replacement
= stringf("X[%d]", var_width
- 1);
1857 module
->addNot(NEW_ID
, var_sig
[var_width
- 1], cell
->getPort(ID::Y
));
1862 if (replace
|| remove
)
1864 log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
1865 log_id(cell
->type
), log_id(cell
), condition
.c_str(), replacement
.c_str());
1867 module
->connect(cell
->getPort(ID::Y
), replace_sig
);
1868 module
->remove(cell
);
1869 did_something
= true;
1878 #undef FOLD_1ARG_CELL
1879 #undef FOLD_2ARG_CELL
1883 struct OptExprPass
: public Pass
{
1884 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
1885 void help() YS_OVERRIDE
1887 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1889 log(" opt_expr [options] [selection]\n");
1891 log("This pass performs const folding on internal cell types with constant inputs.\n");
1892 log("It also performs some simple expression rewriting.\n");
1894 log(" -mux_undef\n");
1895 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
1897 log(" -mux_bool\n");
1898 log(" replace $mux cells with inverters or buffers when possible\n");
1900 log(" -undriven\n");
1901 log(" replace undriven nets with undef (x) constants\n");
1904 log(" optimize clock inverters by changing FF types\n");
1907 log(" perform fine-grain optimizations\n");
1910 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
1913 log(" some optimizations change the behavior of the circuit with respect to\n");
1914 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
1915 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
1916 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
1919 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1921 bool mux_undef
= false;
1922 bool mux_bool
= false;
1923 bool undriven
= false;
1924 bool clkinv
= false;
1925 bool do_fine
= false;
1926 bool keepdc
= false;
1928 log_header(design
, "Executing OPT_EXPR pass (perform const folding).\n");
1932 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1933 if (args
[argidx
] == "-mux_undef") {
1937 if (args
[argidx
] == "-mux_bool") {
1941 if (args
[argidx
] == "-undriven") {
1945 if (args
[argidx
] == "-clkinv") {
1949 if (args
[argidx
] == "-fine") {
1953 if (args
[argidx
] == "-full") {
1960 if (args
[argidx
] == "-keepdc") {
1966 extra_args(args
, argidx
, design
);
1968 CellTypes
ct(design
);
1969 for (auto module
: design
->selected_modules())
1971 log("Optimizing module %s.\n", log_id(module
));
1974 did_something
= false;
1975 replace_undriven(module
, ct
);
1977 design
->scratchpad_set_bool("opt.did_something", true);
1982 did_something
= false;
1983 replace_const_cells(design
, module
, false, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1985 design
->scratchpad_set_bool("opt.did_something", true);
1986 } while (did_something
);
1987 replace_const_cells(design
, module
, true, mux_undef
, mux_bool
, do_fine
, keepdc
, clkinv
);
1989 design
->scratchpad_set_bool("opt.did_something", true);
1990 } while (did_something
);
1999 PRIVATE_NAMESPACE_END