2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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
, 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
, bool keepdc
)
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)) {
160 if (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
)
161 bit_a
= bit_b
= RTLIL::State::S1
;
163 else if (cell
->type
== ID($
and)) {
164 if (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
)
165 bit_a
= bit_b
= RTLIL::State::S0
;
168 if (cell
->type
== ID($
xor)) {
170 bit_a
= bit_b
= RTLIL::State::S0
;
172 else if (cell
->type
== ID($xnor
)) {
174 bit_a
= bit_b
= RTLIL::State::S1
; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_
178 bool def
= (bit_a
!= State::Sx
&& bit_a
!= State::Sz
&& bit_b
!= State::Sx
&& bit_b
!= State::Sz
);
179 if (def
|| !keepdc
) {
180 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
181 group_idx
= GRP_CONST_AB
;
182 else if (bit_a
.wire
== NULL
)
183 group_idx
= GRP_CONST_A
;
184 else if (bit_b
.wire
== NULL
&& commutative
)
185 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
186 else if (bit_b
.wire
== NULL
)
187 group_idx
= GRP_CONST_B
;
190 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
193 for (int i
= 0; i
< GRP_N
; i
++)
194 if (GetSize(grouped_bits
[i
]) == GetSize(bits_y
))
197 log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
198 log_id(cell
->type
), log_id(cell
), log_id(module
));
200 for (int i
= 0; i
< GRP_N
; i
++)
202 if (grouped_bits
[i
].empty())
205 RTLIL::SigSpec new_y
= module
->addWire(NEW_ID
, GetSize(grouped_bits
[i
]));
206 RTLIL::SigSpec new_a
, new_b
;
207 RTLIL::SigSig new_conn
;
209 for (auto &it
: grouped_bits
[i
]) {
210 for (auto &bit
: it
.second
) {
211 new_conn
.first
.append(bit
);
212 new_conn
.second
.append(new_y
[new_a
.size()]);
214 new_a
.append(it
.first
.first
);
215 new_b
.append(it
.first
.second
);
218 if (cell
->type
.in(ID($
and), ID($
or)) && i
== GRP_CONST_A
) {
220 if (cell
->type
== ID($
and))
221 new_a
.replace(dict
<SigBit
,SigBit
>{{State::Sx
, State::S0
}, {State::Sz
, State::S0
}}, &new_b
);
222 else if (cell
->type
== ID($
or))
223 new_a
.replace(dict
<SigBit
,SigBit
>{{State::Sx
, State::S1
}, {State::Sz
, State::S1
}}, &new_b
);
226 log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b
), log_id(cell
->type
), log_signal(new_a
));
227 module
->connect(new_y
, new_b
);
228 module
->connect(new_conn
);
232 if (cell
->type
.in(ID($
xor), ID($xnor
)) && i
== GRP_CONST_A
) {
233 SigSpec undef_a
, undef_y
, undef_b
;
234 SigSpec def_y
, def_a
, def_b
;
235 for (int i
= 0; i
< GetSize(new_y
); i
++) {
236 bool undef
= new_a
[i
] == State::Sx
|| new_a
[i
] == State::Sz
;
237 if (!keepdc
&& (undef
|| new_a
[i
] == new_b
[i
])) {
238 undef_a
.append(new_a
[i
]);
239 if (cell
->type
== ID($
xor))
240 undef_b
.append(State::S0
);
241 // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
242 else if (cell
->type
== ID($xnor
))
243 undef_b
.append(State::S1
);
245 undef_y
.append(new_y
[i
]);
247 else if (new_a
[i
] == State::S0
|| new_a
[i
] == State::S1
) {
248 undef_a
.append(new_a
[i
]);
249 if (cell
->type
== ID($
xor))
250 undef_b
.append(new_a
[i
] == State::S1
? module
->Not(NEW_ID
, new_b
[i
]).as_bit() : new_b
[i
]);
251 else if (cell
->type
== ID($xnor
))
252 undef_b
.append(new_a
[i
] == State::S1
? new_b
[i
] : module
->Not(NEW_ID
, new_b
[i
]).as_bit());
254 undef_y
.append(new_y
[i
]);
257 def_a
.append(new_a
[i
]);
258 def_b
.append(new_b
[i
]);
259 def_y
.append(new_y
[i
]);
262 if (!undef_y
.empty()) {
263 log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b
), log_id(cell
->type
), log_signal(undef_a
));
264 module
->connect(undef_y
, undef_b
);
266 module
->connect(new_conn
);
270 new_a
= std::move(def_a
);
271 new_b
= std::move(def_b
);
272 new_y
= std::move(def_y
);
276 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
278 c
->setPort(ID::A
, new_a
);
279 c
->parameters
[ID::A_WIDTH
] = new_a
.size();
280 c
->parameters
[ID::A_SIGNED
] = false;
282 if (b_name
== ID::B
) {
283 c
->setPort(ID::B
, new_b
);
284 c
->parameters
[ID::B_WIDTH
] = new_b
.size();
285 c
->parameters
[ID::B_SIGNED
] = false;
288 c
->setPort(ID::Y
, new_y
);
289 c
->parameters
[ID::Y_WIDTH
] = GetSize(new_y
);
292 module
->connect(new_conn
);
294 log_debug(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
296 log_debug(", B=%s", log_signal(new_b
));
300 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell
->type
.str());
302 module
->remove(cell
);
303 did_something
= true;
307 void handle_polarity_inv(Cell
*cell
, IdString port
, IdString param
, const SigMap
&assign_map
, const dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> &invert_map
)
309 SigSpec sig
= assign_map(cell
->getPort(port
));
310 if (invert_map
.count(sig
)) {
311 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
312 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
313 log_signal(sig
), log_signal(invert_map
.at(sig
)));
314 cell
->setPort(port
, (invert_map
.at(sig
)));
315 cell
->setParam(param
, !cell
->getParam(param
).as_bool());
319 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
)
321 log_assert(GetSize(type1
) == GetSize(type2
));
322 string cell_type
= cell
->type
.str();
324 if (GetSize(type1
) != GetSize(cell_type
))
327 for (int i
= 0; i
< GetSize(type1
); i
++) {
328 log_assert((type1
[i
] == '?') == (type2
[i
] == '?'));
329 if (type1
[i
] == '?') {
330 if (cell_type
[i
] != '0' && cell_type
[i
] != '1' && cell_type
[i
] != 'N' && cell_type
[i
] != 'P')
332 type1
[i
] = cell_type
[i
];
333 type2
[i
] = cell_type
[i
];
337 if (cell
->type
.in(type1
, type2
)) {
338 SigSpec sig
= assign_map(cell
->getPort(port
));
339 if (invert_map
.count(sig
)) {
340 log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
341 log_id(port
), log_id(cell
->type
), log_id(cell
), log_id(cell
->module
),
342 log_signal(sig
), log_signal(invert_map
.at(sig
)));
343 cell
->setPort(port
, (invert_map
.at(sig
)));
344 cell
->type
= cell
->type
== type1
? type2
: type1
;
349 bool is_one_or_minus_one(const Const
&value
, bool is_signed
, bool &is_negative
)
351 bool all_bits_one
= true;
352 bool last_bit_one
= true;
354 if (GetSize(value
.bits
) < 1)
357 if (GetSize(value
.bits
) == 1) {
358 if (value
.bits
[0] != State::S1
)
365 for (int i
= 0; i
< GetSize(value
.bits
); i
++) {
366 if (value
.bits
[i
] != State::S1
)
367 all_bits_one
= false;
368 if (value
.bits
[i
] != (i
? State::S0
: State::S1
))
369 last_bit_one
= false;
372 if (all_bits_one
&& is_signed
) {
380 int get_highest_hot_index(RTLIL::SigSpec signal
)
382 for (int i
= GetSize(signal
) - 1; i
>= 0; i
--)
384 if (signal
[i
] == RTLIL::State::S0
)
387 if (signal
[i
] == RTLIL::State::S1
)
396 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 noclkinv
)
398 CellTypes ct_combinational
;
399 ct_combinational
.setup_internals();
400 ct_combinational
.setup_stdcells();
402 SigMap
assign_map(module
);
403 dict
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
405 TopoSort
<RTLIL::Cell
*, RTLIL::IdString::compare_ptr_by_name
<RTLIL::Cell
>> cells
;
406 dict
<RTLIL::Cell
*, std::set
<RTLIL::SigBit
>> cell_to_inbit
;
407 dict
<RTLIL::SigBit
, std::set
<RTLIL::Cell
*>> outbit_to_cell
;
409 for (auto cell
: module
->cells())
410 if (design
->selected(module
, cell
) && cell
->type
[0] == '$') {
411 if (cell
->type
.in(ID($_NOT_
), ID($
not), ID($logic_not
)) &&
412 GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::Y
)) == 1)
413 invert_map
[assign_map(cell
->getPort(ID::Y
))] = assign_map(cell
->getPort(ID::A
));
414 if (cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
415 cell
->getPort(ID::A
) == SigSpec(State::S1
) && cell
->getPort(ID::B
) == SigSpec(State::S0
))
416 invert_map
[assign_map(cell
->getPort(ID::Y
))] = assign_map(cell
->getPort(ID::S
));
417 if (ct_combinational
.cell_known(cell
->type
))
418 for (auto &conn
: cell
->connections()) {
419 RTLIL::SigSpec sig
= assign_map(conn
.second
);
421 if (ct_combinational
.cell_input(cell
->type
, conn
.first
))
422 cell_to_inbit
[cell
].insert(sig
.begin(), sig
.end());
423 if (ct_combinational
.cell_output(cell
->type
, conn
.first
))
424 for (auto &bit
: sig
)
425 outbit_to_cell
[bit
].insert(cell
);
430 for (auto &it_right
: cell_to_inbit
)
431 for (auto &it_sigbit
: it_right
.second
)
432 for (auto &it_left
: outbit_to_cell
[it_sigbit
])
433 cells
.edge(it_left
, it_right
.first
);
437 for (auto cell
: cells
.sorted
)
439 #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)
440 #define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
444 if (cell
->type
.in(ID($dff
), ID($dffe
), ID($dffsr
), ID($dffsre
), ID($adff
), ID($adffe
), ID($aldff
), ID($aldffe
), ID($sdff
), ID($sdffe
), ID($sdffce
), ID($fsm
), ID($memrd
), ID($memrd_v2
), ID($memwr
), ID($memwr_v2
)))
445 handle_polarity_inv(cell
, ID::CLK
, ID::CLK_POLARITY
, assign_map
, invert_map
);
447 if (cell
->type
.in(ID($sr
), ID($dffsr
), ID($dffsre
), ID($dlatchsr
))) {
448 handle_polarity_inv(cell
, ID::SET
, ID::SET_POLARITY
, assign_map
, invert_map
);
449 handle_polarity_inv(cell
, ID::CLR
, ID::CLR_POLARITY
, assign_map
, invert_map
);
452 if (cell
->type
.in(ID($adff
), ID($adffe
), ID($adlatch
)))
453 handle_polarity_inv(cell
, ID::ARST
, ID::ARST_POLARITY
, assign_map
, invert_map
);
455 if (cell
->type
.in(ID($aldff
), ID($aldffe
)))
456 handle_polarity_inv(cell
, ID::ALOAD
, ID::ALOAD_POLARITY
, assign_map
, invert_map
);
458 if (cell
->type
.in(ID($sdff
), ID($sdffe
), ID($sdffce
)))
459 handle_polarity_inv(cell
, ID::SRST
, ID::SRST_POLARITY
, assign_map
, invert_map
);
461 if (cell
->type
.in(ID($dffe
), ID($adffe
), ID($aldffe
), ID($sdffe
), ID($sdffce
), ID($dffsre
), ID($dlatch
), ID($adlatch
), ID($dlatchsr
)))
462 handle_polarity_inv(cell
, ID::EN
, ID::EN_POLARITY
, assign_map
, invert_map
);
464 handle_clkpol_celltype_swap(cell
, "$_SR_N?_", "$_SR_P?_", ID::S
, assign_map
, invert_map
);
465 handle_clkpol_celltype_swap(cell
, "$_SR_?N_", "$_SR_?P_", ID::R
, assign_map
, invert_map
);
467 handle_clkpol_celltype_swap(cell
, "$_DFF_N_", "$_DFF_P_", ID::C
, assign_map
, invert_map
);
469 handle_clkpol_celltype_swap(cell
, "$_DFFE_N?_", "$_DFFE_P?_", ID::C
, assign_map
, invert_map
);
470 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N_", "$_DFFE_?P_", ID::E
, assign_map
, invert_map
);
472 handle_clkpol_celltype_swap(cell
, "$_DFF_N??_", "$_DFF_P??_", ID::C
, assign_map
, invert_map
);
473 handle_clkpol_celltype_swap(cell
, "$_DFF_?N?_", "$_DFF_?P?_", ID::R
, assign_map
, invert_map
);
475 handle_clkpol_celltype_swap(cell
, "$_DFFE_N???_", "$_DFFE_P???_", ID::C
, assign_map
, invert_map
);
476 handle_clkpol_celltype_swap(cell
, "$_DFFE_?N??_", "$_DFFE_?P??_", ID::R
, assign_map
, invert_map
);
477 handle_clkpol_celltype_swap(cell
, "$_DFFE_???N_", "$_DFFE_???P_", ID::E
, assign_map
, invert_map
);
479 handle_clkpol_celltype_swap(cell
, "$_SDFF_N??_", "$_SDFF_P??_", ID::C
, assign_map
, invert_map
);
480 handle_clkpol_celltype_swap(cell
, "$_SDFF_?N?_", "$_SDFF_?P?_", ID::R
, assign_map
, invert_map
);
482 handle_clkpol_celltype_swap(cell
, "$_SDFFE_N???_", "$_SDFFE_P???_", ID::C
, assign_map
, invert_map
);
483 handle_clkpol_celltype_swap(cell
, "$_SDFFE_?N??_", "$_SDFFE_?P??_", ID::R
, assign_map
, invert_map
);
484 handle_clkpol_celltype_swap(cell
, "$_SDFFE_???N_", "$_SDFFE_???P_", ID::E
, assign_map
, invert_map
);
486 handle_clkpol_celltype_swap(cell
, "$_SDFFCE_N???_", "$_SDFFCE_P???_", ID::C
, assign_map
, invert_map
);
487 handle_clkpol_celltype_swap(cell
, "$_SDFFCE_?N??_", "$_SDFFCE_?P??_", ID::R
, assign_map
, invert_map
);
488 handle_clkpol_celltype_swap(cell
, "$_SDFFCE_???N_", "$_SDFFCE_???P_", ID::E
, assign_map
, invert_map
);
490 handle_clkpol_celltype_swap(cell
, "$_ALDFF_N?_", "$_ALDFF_P?_", ID::C
, assign_map
, invert_map
);
491 handle_clkpol_celltype_swap(cell
, "$_ALDFF_?N_", "$_ALDFF_?P_", ID::L
, assign_map
, invert_map
);
493 handle_clkpol_celltype_swap(cell
, "$_ALDFFE_N??_", "$_ALDFFE_P??_", ID::C
, assign_map
, invert_map
);
494 handle_clkpol_celltype_swap(cell
, "$_ALDFFE_?N?_", "$_ALDFFE_?P?_", ID::L
, assign_map
, invert_map
);
495 handle_clkpol_celltype_swap(cell
, "$_ALDFFE_??N_", "$_ALDFFE_??P_", ID::E
, assign_map
, invert_map
);
497 handle_clkpol_celltype_swap(cell
, "$_DFFSR_N??_", "$_DFFSR_P??_", ID::C
, assign_map
, invert_map
);
498 handle_clkpol_celltype_swap(cell
, "$_DFFSR_?N?_", "$_DFFSR_?P?_", ID::S
, assign_map
, invert_map
);
499 handle_clkpol_celltype_swap(cell
, "$_DFFSR_??N_", "$_DFFSR_??P_", ID::R
, assign_map
, invert_map
);
501 handle_clkpol_celltype_swap(cell
, "$_DFFSRE_N???_", "$_DFFSRE_P???_", ID::C
, assign_map
, invert_map
);
502 handle_clkpol_celltype_swap(cell
, "$_DFFSRE_?N??_", "$_DFFSRE_?P??_", ID::S
, assign_map
, invert_map
);
503 handle_clkpol_celltype_swap(cell
, "$_DFFSRE_??N?_", "$_DFFSRE_??P?_", ID::R
, assign_map
, invert_map
);
504 handle_clkpol_celltype_swap(cell
, "$_DFFSRE_???N_", "$_DFFSRE_???P_", ID::E
, assign_map
, invert_map
);
506 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N_", "$_DLATCH_P_", ID::E
, assign_map
, invert_map
);
508 handle_clkpol_celltype_swap(cell
, "$_DLATCH_N??_", "$_DLATCH_P??_", ID::E
, assign_map
, invert_map
);
509 handle_clkpol_celltype_swap(cell
, "$_DLATCH_?N?_", "$_DLATCH_?P?_", ID::R
, assign_map
, invert_map
);
511 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID::E
, assign_map
, invert_map
);
512 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID::S
, assign_map
, invert_map
);
513 handle_clkpol_celltype_swap(cell
, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R
, assign_map
, invert_map
);
516 bool detect_const_and
= false;
517 bool detect_const_or
= false;
519 if (cell
->type
.in(ID($reduce_and
), ID($_AND_
)))
520 detect_const_and
= true;
522 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())
523 detect_const_and
= true;
525 if (cell
->type
.in(ID($reduce_or
), ID($reduce_bool
), ID($_OR_
)))
526 detect_const_or
= true;
528 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())
529 detect_const_or
= true;
531 if (detect_const_and
|| detect_const_or
)
533 pool
<SigBit
> input_bits
= assign_map(cell
->getPort(ID::A
)).to_sigbit_pool();
534 bool found_zero
= false, found_one
= false, found_undef
= false, found_inv
= false, many_conconst
= false;
535 SigBit non_const_input
= State::Sm
;
537 if (cell
->hasPort(ID::B
)) {
538 vector
<SigBit
> more_bits
= assign_map(cell
->getPort(ID::B
)).to_sigbit_vector();
539 input_bits
.insert(more_bits
.begin(), more_bits
.end());
542 for (auto bit
: input_bits
) {
544 if (invert_map
.count(bit
) && input_bits
.count(invert_map
.at(bit
)))
546 if (non_const_input
!= State::Sm
)
547 many_conconst
= true;
548 non_const_input
= many_conconst
? State::Sm
: bit
;
550 if (bit
== State::S0
)
552 else if (bit
== State::S1
)
559 if (detect_const_and
&& (found_zero
|| found_inv
|| (found_undef
&& consume_x
))) {
560 cover("opt.opt_expr.const_and");
561 replace_cell(assign_map
, module
, cell
, "const_and", ID::Y
, RTLIL::State::S0
);
565 if (detect_const_or
&& (found_one
|| found_inv
|| (found_undef
&& consume_x
))) {
566 cover("opt.opt_expr.const_or");
567 replace_cell(assign_map
, module
, cell
, "const_or", ID::Y
, RTLIL::State::S1
);
571 if (non_const_input
!= State::Sm
&& !found_undef
) {
572 cover("opt.opt_expr.and_or_buffer");
573 replace_cell(assign_map
, module
, cell
, "and_or_buffer", ID::Y
, non_const_input
);
578 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()))
580 SigBit sig_a
= assign_map(cell
->getPort(ID::A
));
581 SigBit sig_b
= assign_map(cell
->getPort(ID::B
));
582 if (!keepdc
&& (sig_a
== sig_b
|| sig_a
== State::Sx
|| sig_a
== State::Sz
|| sig_b
== State::Sx
|| sig_b
== State::Sz
)) {
583 if (cell
->type
.in(ID($
xor), ID($_XOR_
))) {
584 cover("opt.opt_expr.const_xor");
585 replace_cell(assign_map
, module
, cell
, "const_xor", ID::Y
, RTLIL::State::S0
);
588 if (cell
->type
.in(ID($xnor
), ID($_XNOR_
))) {
589 cover("opt.opt_expr.const_xnor");
590 // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
591 int width
= GetSize(cell
->getPort(ID::Y
));
592 replace_cell(assign_map
, module
, cell
, "const_xnor", ID::Y
, SigSpec(RTLIL::State::S1
, width
));
599 std::swap(sig_a
, sig_b
);
600 if (sig_b
== State::S0
|| sig_b
== State::S1
) {
601 if (cell
->type
.in(ID($
xor), ID($_XOR_
))) {
602 cover("opt.opt_expr.xor_buffer");
604 if (cell
->type
== ID($
xor))
605 sig_y
= (sig_b
== State::S1
? module
->Not(NEW_ID
, sig_a
).as_bit() : sig_a
);
606 else if (cell
->type
== ID($_XOR_
))
607 sig_y
= (sig_b
== State::S1
? module
->NotGate(NEW_ID
, sig_a
) : sig_a
);
609 replace_cell(assign_map
, module
, cell
, "xor_buffer", ID::Y
, sig_y
);
612 if (cell
->type
.in(ID($xnor
), ID($_XNOR_
))) {
613 cover("opt.opt_expr.xnor_buffer");
615 if (cell
->type
== ID($xnor
)) {
616 sig_y
= (sig_b
== State::S1
? sig_a
: module
->Not(NEW_ID
, sig_a
).as_bit());
617 int width
= cell
->getParam(ID::Y_WIDTH
).as_int();
618 sig_y
.append(RTLIL::Const(State::S1
, width
-1));
620 else if (cell
->type
== ID($_XNOR_
))
621 sig_y
= (sig_b
== State::S1
? sig_a
: module
->NotGate(NEW_ID
, sig_a
));
623 replace_cell(assign_map
, module
, cell
, "xnor_buffer", ID::Y
, sig_y
);
630 if (cell
->type
.in(ID($reduce_and
), ID($reduce_or
), ID($reduce_bool
), ID($reduce_xor
), ID($reduce_xnor
), ID($neg
)) &&
631 GetSize(cell
->getPort(ID::A
)) == 1 && GetSize(cell
->getPort(ID::Y
)) == 1)
633 if (cell
->type
== ID($reduce_xnor
)) {
634 cover("opt.opt_expr.reduce_xnor_not");
635 log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
636 log_id(cell
->type
), log_id(cell
->name
), log_id(module
));
637 cell
->type
= ID($
not);
638 did_something
= true;
640 cover("opt.opt_expr.unary_buffer");
641 replace_cell(assign_map
, module
, cell
, "unary_buffer", ID::Y
, cell
->getPort(ID::A
));
648 if (cell
->type
.in(ID($
not), ID($pos
), ID($
and), ID($
or), ID($
xor), ID($xnor
)))
649 if (group_cell_inputs(module
, cell
, true, assign_map
, keepdc
))
652 if (cell
->type
.in(ID($logic_not
), ID($logic_and
), ID($logic_or
), ID($reduce_or
), ID($reduce_and
), ID($reduce_bool
)))
654 SigBit neutral_bit
= cell
->type
== ID($reduce_and
) ? State::S1
: State::S0
;
656 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
657 RTLIL::SigSpec new_sig_a
;
659 for (auto bit
: sig_a
)
660 if (bit
!= neutral_bit
) new_sig_a
.append(bit
);
662 if (GetSize(new_sig_a
) == 0)
663 new_sig_a
.append(neutral_bit
);
665 if (GetSize(new_sig_a
) < GetSize(sig_a
)) {
666 cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell
->type
.str());
667 log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
668 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_sig_a
));
669 cell
->setPort(ID::A
, new_sig_a
);
670 cell
->parameters
.at(ID::A_WIDTH
) = GetSize(new_sig_a
);
671 did_something
= true;
675 if (cell
->type
.in(ID($logic_and
), ID($logic_or
)))
677 SigBit neutral_bit
= State::S0
;
679 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
680 RTLIL::SigSpec new_sig_b
;
682 for (auto bit
: sig_b
)
683 if (bit
!= neutral_bit
) new_sig_b
.append(bit
);
685 if (GetSize(new_sig_b
) == 0)
686 new_sig_b
.append(neutral_bit
);
688 if (GetSize(new_sig_b
) < GetSize(sig_b
)) {
689 cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell
->type
.str());
690 log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
691 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_sig_b
));
692 cell
->setPort(ID::B
, new_sig_b
);
693 cell
->parameters
.at(ID::B_WIDTH
) = GetSize(new_sig_b
);
694 did_something
= true;
698 if (cell
->type
== ID($reduce_and
))
700 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
702 RTLIL::State new_a
= RTLIL::State::S1
;
703 for (auto &bit
: sig_a
.to_sigbit_vector())
704 if (bit
== RTLIL::State::Sx
) {
705 if (new_a
== RTLIL::State::S1
)
706 new_a
= RTLIL::State::Sx
;
707 } else if (bit
== RTLIL::State::S0
) {
708 new_a
= RTLIL::State::S0
;
710 } else if (bit
.wire
!= NULL
) {
711 new_a
= RTLIL::State::Sm
;
714 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
715 cover("opt.opt_expr.fine.$reduce_and");
716 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
717 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
718 cell
->setPort(ID::A
, sig_a
= new_a
);
719 cell
->parameters
.at(ID::A_WIDTH
) = 1;
720 did_something
= true;
724 if (cell
->type
.in(ID($logic_not
), ID($logic_and
), ID($logic_or
), ID($reduce_or
), ID($reduce_bool
)))
726 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
728 RTLIL::State new_a
= RTLIL::State::S0
;
729 for (auto &bit
: sig_a
.to_sigbit_vector())
730 if (bit
== RTLIL::State::Sx
) {
731 if (new_a
== RTLIL::State::S0
)
732 new_a
= RTLIL::State::Sx
;
733 } else if (bit
== RTLIL::State::S1
) {
734 new_a
= RTLIL::State::S1
;
736 } else if (bit
.wire
!= NULL
) {
737 new_a
= RTLIL::State::Sm
;
740 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
741 cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell
->type
.str());
742 log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
743 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
744 cell
->setPort(ID::A
, sig_a
= new_a
);
745 cell
->parameters
.at(ID::A_WIDTH
) = 1;
746 did_something
= true;
750 if (cell
->type
.in(ID($logic_and
), ID($logic_or
)))
752 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
754 RTLIL::State new_b
= RTLIL::State::S0
;
755 for (auto &bit
: sig_b
.to_sigbit_vector())
756 if (bit
== RTLIL::State::Sx
) {
757 if (new_b
== RTLIL::State::S0
)
758 new_b
= RTLIL::State::Sx
;
759 } else if (bit
== RTLIL::State::S1
) {
760 new_b
= RTLIL::State::S1
;
762 } else if (bit
.wire
!= NULL
) {
763 new_b
= RTLIL::State::Sm
;
766 if (new_b
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_b
) != sig_b
) {
767 cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell
->type
.str());
768 log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
769 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_b
));
770 cell
->setPort(ID::B
, sig_b
= new_b
);
771 cell
->parameters
.at(ID::B_WIDTH
) = 1;
772 did_something
= true;
776 if (cell
->type
.in(ID($add
), ID($sub
)))
778 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
779 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
780 RTLIL::SigSpec sig_y
= cell
->getPort(ID::Y
);
781 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
782 bool sub
= cell
->type
== ID($sub
);
784 int minsz
= GetSize(sig_y
);
785 minsz
= std::min(minsz
, GetSize(sig_a
));
786 minsz
= std::min(minsz
, GetSize(sig_b
));
789 for (i
= 0; i
< minsz
; i
++) {
790 RTLIL::SigBit b
= sig_b
[i
];
791 RTLIL::SigBit a
= sig_a
[i
];
793 module
->connect(sig_y
[i
], a
);
794 else if (sub
&& b
== State::S1
&& a
== State::S1
)
795 module
->connect(sig_y
[i
], State::S0
);
796 else if (!sub
&& a
== State::S0
)
797 module
->connect(sig_y
[i
], b
);
802 cover_list("opt.opt_expr.fine", "$add", "$sub", cell
->type
.str());
803 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
));
804 SigSpec new_a
= sig_a
.extract_end(i
);
805 SigSpec new_b
= sig_b
.extract_end(i
);
806 if (new_a
.empty() && is_signed
)
808 if (new_b
.empty() && is_signed
)
810 cell
->setPort(ID::A
, new_a
);
811 cell
->setPort(ID::B
, new_b
);
812 cell
->setPort(ID::Y
, sig_y
.extract_end(i
));
813 cell
->fixup_parameters();
814 did_something
= true;
818 if (cell
->type
== ID($alu
))
820 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
821 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
822 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
823 RTLIL::SigBit sig_bi
= assign_map(cell
->getPort(ID::BI
));
824 RTLIL::SigSpec sig_x
= cell
->getPort(ID::X
);
825 RTLIL::SigSpec sig_y
= cell
->getPort(ID::Y
);
826 RTLIL::SigSpec sig_co
= cell
->getPort(ID::CO
);
827 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
829 if (sig_bi
!= State::S0
&& sig_bi
!= State::S1
)
831 if (sig_ci
!= State::S0
&& sig_ci
!= State::S1
)
834 bool bi
= sig_bi
== State::S1
;
835 bool ci
= sig_ci
== State::S1
;
837 int minsz
= GetSize(sig_y
);
838 minsz
= std::min(minsz
, GetSize(sig_a
));
839 minsz
= std::min(minsz
, GetSize(sig_b
));
842 for (i
= 0; i
< minsz
; i
++) {
843 RTLIL::SigBit b
= sig_b
[i
];
844 RTLIL::SigBit a
= sig_a
[i
];
845 if (b
== ((bi
^ ci
) ? State::S1
: State::S0
)) {
846 module
->connect(sig_y
[i
], a
);
847 module
->connect(sig_x
[i
], ci
? module
->Not(NEW_ID
, a
).as_bit() : a
);
848 module
->connect(sig_co
[i
], ci
? State::S1
: State::S0
);
850 else if (a
== (ci
? State::S1
: State::S0
)) {
851 module
->connect(sig_y
[i
], bi
? module
->Not(NEW_ID
, b
).as_bit() : b
);
852 module
->connect(sig_x
[i
], (bi
^ ci
) ? module
->Not(NEW_ID
, b
).as_bit() : b
);
853 module
->connect(sig_co
[i
], ci
? State::S1
: State::S0
);
859 cover("opt.opt_expr.fine.$alu");
860 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
));
861 SigSpec new_a
= sig_a
.extract_end(i
);
862 SigSpec new_b
= sig_b
.extract_end(i
);
863 if (new_a
.empty() && is_signed
)
865 if (new_b
.empty() && is_signed
)
867 cell
->setPort(ID::A
, new_a
);
868 cell
->setPort(ID::B
, new_b
);
869 cell
->setPort(ID::X
, sig_x
.extract_end(i
));
870 cell
->setPort(ID::Y
, sig_y
.extract_end(i
));
871 cell
->setPort(ID::CO
, sig_co
.extract_end(i
));
872 cell
->fixup_parameters();
873 did_something
= true;
879 if (cell
->type
.in(ID($reduce_xor
), ID($reduce_xnor
), ID($shift
), ID($shiftx
), ID($shl
), ID($shr
), ID($sshl
), ID($sshr
),
880 ID($lt
), ID($le
), ID($ge
), ID($gt
), ID($neg
), ID($add
), ID($sub
), ID($mul
), ID($div
), ID($mod
), ID($divfloor
), ID($modfloor
), ID($pow
)))
882 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
883 RTLIL::SigSpec sig_b
= cell
->hasPort(ID::B
) ? assign_map(cell
->getPort(ID::B
)) : RTLIL::SigSpec();
885 if (cell
->type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
), ID($shift
), ID($shiftx
)))
886 sig_a
= RTLIL::SigSpec();
888 for (auto &bit
: sig_a
.to_sigbit_vector())
889 if (bit
== RTLIL::State::Sx
)
890 goto found_the_x_bit
;
892 for (auto &bit
: sig_b
.to_sigbit_vector())
893 if (bit
== RTLIL::State::Sx
)
894 goto found_the_x_bit
;
898 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
899 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell
->type
.str());
900 if (cell
->type
.in(ID($reduce_xor
), ID($reduce_xnor
), ID($lt
), ID($le
), ID($ge
), ID($gt
)))
901 replace_cell(assign_map
, module
, cell
, "x-bit in input", ID::Y
, RTLIL::State::Sx
);
903 replace_cell(assign_map
, module
, cell
, "x-bit in input", ID::Y
, RTLIL::SigSpec(RTLIL::State::Sx
, GetSize(cell
->getPort(ID::Y
))));
908 if (cell
->type
.in(ID($shiftx
), ID($shift
))) {
909 SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
911 bool trim_x
= cell
->type
== ID($shiftx
) || !keepdc
;
912 bool trim_0
= cell
->type
== ID($shift
);
913 for (width
= GetSize(sig_a
); width
> 1; width
--) {
914 if ((trim_x
&& sig_a
[width
-1] == State::Sx
) ||
915 (trim_0
&& sig_a
[width
-1] == State::S0
))
920 if (width
< GetSize(sig_a
)) {
921 cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell
->type
.str());
922 sig_a
.remove(width
, GetSize(sig_a
)-width
);
923 cell
->setPort(ID::A
, sig_a
);
924 cell
->setParam(ID::A_WIDTH
, width
);
925 did_something
= true;
930 if (cell
->type
.in(ID($_NOT_
), ID($
not), ID($logic_not
)) && GetSize(cell
->getPort(ID::Y
)) == 1 &&
931 invert_map
.count(assign_map(cell
->getPort(ID::A
))) != 0) {
932 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell
->type
.str());
933 replace_cell(assign_map
, module
, cell
, "double_invert", ID::Y
, invert_map
.at(assign_map(cell
->getPort(ID::A
))));
937 if (cell
->type
.in(ID($_MUX_
), ID($mux
)) && invert_map
.count(assign_map(cell
->getPort(ID::S
))) != 0) {
938 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell
->type
.str());
939 log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
940 RTLIL::SigSpec tmp
= cell
->getPort(ID::A
);
941 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
942 cell
->setPort(ID::B
, tmp
);
943 cell
->setPort(ID::S
, invert_map
.at(assign_map(cell
->getPort(ID::S
))));
944 did_something
= true;
948 if (cell
->type
== ID($_NOT_
)) {
949 RTLIL::SigSpec input
= cell
->getPort(ID::A
);
950 assign_map
.apply(input
);
951 if (input
.match("1")) ACTION_DO_Y(0);
952 if (input
.match("0")) ACTION_DO_Y(1);
953 if (input
.match("*")) ACTION_DO_Y(x
);
956 if (cell
->type
== ID($_AND_
)) {
957 RTLIL::SigSpec input
;
958 input
.append(cell
->getPort(ID::B
));
959 input
.append(cell
->getPort(ID::A
));
960 assign_map
.apply(input
);
961 if (input
.match(" 0")) ACTION_DO_Y(0);
962 if (input
.match("0 ")) ACTION_DO_Y(0);
963 if (input
.match("11")) ACTION_DO_Y(1);
964 if (input
.match("**")) ACTION_DO_Y(x
);
965 if (input
.match("1*")) ACTION_DO_Y(x
);
966 if (input
.match("*1")) ACTION_DO_Y(x
);
968 if (input
.match(" *")) ACTION_DO_Y(0);
969 if (input
.match("* ")) ACTION_DO_Y(0);
971 if (input
.match(" 1")) ACTION_DO(ID::Y
, input
.extract(1, 1));
972 if (input
.match("1 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
975 if (cell
->type
== ID($_OR_
)) {
976 RTLIL::SigSpec input
;
977 input
.append(cell
->getPort(ID::B
));
978 input
.append(cell
->getPort(ID::A
));
979 assign_map
.apply(input
);
980 if (input
.match(" 1")) ACTION_DO_Y(1);
981 if (input
.match("1 ")) ACTION_DO_Y(1);
982 if (input
.match("00")) ACTION_DO_Y(0);
983 if (input
.match("**")) ACTION_DO_Y(x
);
984 if (input
.match("0*")) ACTION_DO_Y(x
);
985 if (input
.match("*0")) ACTION_DO_Y(x
);
987 if (input
.match(" *")) ACTION_DO_Y(1);
988 if (input
.match("* ")) ACTION_DO_Y(1);
990 if (input
.match(" 0")) ACTION_DO(ID::Y
, input
.extract(1, 1));
991 if (input
.match("0 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
994 if (cell
->type
== ID($_XOR_
)) {
995 RTLIL::SigSpec input
;
996 input
.append(cell
->getPort(ID::B
));
997 input
.append(cell
->getPort(ID::A
));
998 assign_map
.apply(input
);
999 if (input
.match("00")) ACTION_DO_Y(0);
1000 if (input
.match("01")) ACTION_DO_Y(1);
1001 if (input
.match("10")) ACTION_DO_Y(1);
1002 if (input
.match("11")) ACTION_DO_Y(0);
1004 if (input
.match(" *")) ACTION_DO_Y(0);
1005 if (input
.match("* ")) ACTION_DO_Y(0);
1009 if (cell
->type
== ID($_MUX_
)) {
1010 RTLIL::SigSpec input
;
1011 input
.append(cell
->getPort(ID::S
));
1012 input
.append(cell
->getPort(ID::B
));
1013 input
.append(cell
->getPort(ID::A
));
1014 assign_map
.apply(input
);
1015 if (input
.extract(2, 1) == input
.extract(1, 1))
1016 ACTION_DO(ID::Y
, input
.extract(2, 1));
1017 if (input
.match(" 0")) ACTION_DO(ID::Y
, input
.extract(2, 1));
1018 if (input
.match(" 1")) ACTION_DO(ID::Y
, input
.extract(1, 1));
1019 if (input
.match("01 ")) ACTION_DO(ID::Y
, input
.extract(0, 1));
1020 if (input
.match("10 ")) {
1021 cover("opt.opt_expr.mux_to_inv");
1022 cell
->type
= ID($_NOT_
);
1023 cell
->setPort(ID::A
, input
.extract(0, 1));
1024 cell
->unsetPort(ID::B
);
1025 cell
->unsetPort(ID::S
);
1028 if (input
.match("11 ")) ACTION_DO_Y(1);
1029 if (input
.match("00 ")) ACTION_DO_Y(0);
1030 if (input
.match("** ")) ACTION_DO_Y(x
);
1031 if (input
.match("01*")) ACTION_DO_Y(x
);
1032 if (input
.match("10*")) ACTION_DO_Y(x
);
1034 if (input
.match("* ")) ACTION_DO(ID::Y
, input
.extract(1, 1));
1035 if (input
.match(" * ")) ACTION_DO(ID::Y
, input
.extract(2, 1));
1036 if (input
.match(" *")) ACTION_DO(ID::Y
, input
.extract(2, 1));
1040 if (cell
->type
.in(ID($_TBUF_
), ID($tribuf
))) {
1041 RTLIL::SigSpec input
= cell
->getPort(cell
->type
== ID($_TBUF_
) ? ID::E
: ID::EN
);
1042 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
1043 assign_map
.apply(input
);
1044 assign_map
.apply(a
);
1045 if (input
== State::S1
)
1046 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
1047 if (input
== State::S0
&& !a
.is_fully_undef()) {
1048 cover("opt.opt_expr.action_" S__LINE__
);
1049 log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
1050 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str());
1051 cell
->setPort(ID::A
, SigSpec(State::Sx
, GetSize(a
)));
1052 did_something
= true;
1057 if (cell
->type
.in(ID($eq
), ID($ne
), ID($eqx
), ID($nex
)))
1059 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
1060 RTLIL::SigSpec b
= cell
->getPort(ID::B
);
1062 if (cell
->parameters
[ID::A_WIDTH
].as_int() != cell
->parameters
[ID::B_WIDTH
].as_int()) {
1063 int width
= max(cell
->parameters
[ID::A_WIDTH
].as_int(), cell
->parameters
[ID::B_WIDTH
].as_int());
1064 a
.extend_u0(width
, cell
->parameters
[ID::A_SIGNED
].as_bool() && cell
->parameters
[ID::B_SIGNED
].as_bool());
1065 b
.extend_u0(width
, cell
->parameters
[ID::A_SIGNED
].as_bool() && cell
->parameters
[ID::B_SIGNED
].as_bool());
1068 RTLIL::SigSpec new_a
, new_b
;
1070 log_assert(GetSize(a
) == GetSize(b
));
1071 for (int i
= 0; i
< GetSize(a
); i
++) {
1072 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
) {
1073 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
1074 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in(ID($eq
), ID($eqx
)) ? RTLIL::State::S0
: RTLIL::State::S1
);
1075 new_y
.extend_u0(cell
->parameters
[ID::Y_WIDTH
].as_int(), false);
1076 replace_cell(assign_map
, module
, cell
, "isneq", ID::Y
, new_y
);
1085 if (new_a
.size() == 0) {
1086 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
1087 RTLIL::SigSpec new_y
= RTLIL::SigSpec(cell
->type
.in(ID($eq
), ID($eqx
)) ? RTLIL::State::S1
: RTLIL::State::S0
);
1088 new_y
.extend_u0(cell
->parameters
[ID::Y_WIDTH
].as_int(), false);
1089 replace_cell(assign_map
, module
, cell
, "empty", ID::Y
, new_y
);
1093 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
1094 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell
->type
.str());
1095 cell
->setPort(ID::A
, new_a
);
1096 cell
->setPort(ID::B
, new_b
);
1097 cell
->parameters
[ID::A_WIDTH
] = new_a
.size();
1098 cell
->parameters
[ID::B_WIDTH
] = new_b
.size();
1102 if (cell
->type
.in(ID($eq
), ID($ne
)) && cell
->parameters
[ID::Y_WIDTH
].as_int() == 1 &&
1103 cell
->parameters
[ID::A_WIDTH
].as_int() == 1 && cell
->parameters
[ID::B_WIDTH
].as_int() == 1)
1105 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1106 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1108 if (a
.is_fully_const() && !b
.is_fully_const()) {
1109 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell
->type
.str());
1110 cell
->setPort(ID::A
, b
);
1111 cell
->setPort(ID::B
, a
);
1115 if (b
.is_fully_const()) {
1116 if (b
.is_fully_undef()) {
1117 RTLIL::SigSpec input
= b
;
1118 ACTION_DO(ID::Y
, Const(State::Sx
, GetSize(cell
->getPort(ID::Y
))));
1120 if (b
.as_bool() == (cell
->type
== ID($eq
))) {
1121 RTLIL::SigSpec input
= b
;
1122 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
1124 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell
->type
.str());
1125 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1126 cell
->type
= ID($
not);
1127 cell
->parameters
.erase(ID::B_WIDTH
);
1128 cell
->parameters
.erase(ID::B_SIGNED
);
1129 cell
->unsetPort(ID::B
);
1130 did_something
= true;
1136 if (cell
->type
.in(ID($eq
), ID($ne
)) &&
1137 (assign_map(cell
->getPort(ID::A
)).is_fully_zero() || assign_map(cell
->getPort(ID::B
)).is_fully_zero()))
1139 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell
->type
.str());
1140 log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell
->type
), log_id(cell
),
1141 log_id(module
), cell
->type
== ID($eq
) ? "$logic_not" : "$reduce_bool");
1142 cell
->type
= cell
->type
== ID($eq
) ? ID($logic_not
) : ID($reduce_bool
);
1143 if (assign_map(cell
->getPort(ID::A
)).is_fully_zero()) {
1144 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1145 cell
->setParam(ID::A_SIGNED
, cell
->getParam(ID::B_SIGNED
));
1146 cell
->setParam(ID::A_WIDTH
, cell
->getParam(ID::B_WIDTH
));
1148 cell
->unsetPort(ID::B
);
1149 cell
->unsetParam(ID::B_SIGNED
);
1150 cell
->unsetParam(ID::B_WIDTH
);
1151 did_something
= true;
1155 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())
1157 bool sign_ext
= cell
->type
== ID($sshr
) && cell
->getParam(ID::A_SIGNED
).as_bool();
1158 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());
1160 if (cell
->type
.in(ID($shl
), ID($sshl
)))
1163 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1164 RTLIL::SigSpec
sig_y(cell
->type
== ID($shiftx
) ? RTLIL::State::Sx
: RTLIL::State::S0
, cell
->getParam(ID::Y_WIDTH
).as_int());
1166 if (GetSize(sig_a
) < GetSize(sig_y
))
1167 sig_a
.extend_u0(GetSize(sig_y
), cell
->getParam(ID::A_SIGNED
).as_bool());
1169 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
1170 int idx
= i
+ shift_bits
;
1171 if (0 <= idx
&& idx
< GetSize(sig_a
))
1172 sig_y
[i
] = sig_a
[idx
];
1173 else if (GetSize(sig_a
) <= idx
&& sign_ext
)
1174 sig_y
[i
] = sig_a
[GetSize(sig_a
)-1];
1177 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell
->type
.str());
1179 log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
1180 log_id(cell
->type
), log_id(cell
), log_signal(assign_map(cell
->getPort(ID::B
))), shift_bits
, log_id(module
), log_signal(sig_y
));
1182 module
->connect(cell
->getPort(ID::Y
), sig_y
);
1183 module
->remove(cell
);
1185 did_something
= true;
1191 bool identity_wrt_a
= false;
1192 bool identity_wrt_b
= false;
1193 bool arith_inverse
= false;
1195 if (cell
->type
.in(ID($add
), ID($sub
), ID($alu
), ID($
or), ID($
xor)))
1197 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1198 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1200 bool sub
= cell
->type
== ID($sub
);
1202 if (cell
->type
== ID($alu
)) {
1203 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
1204 RTLIL::SigBit sig_bi
= assign_map(cell
->getPort(ID::BI
));
1206 sub
= (sig_ci
== State::S1
&& sig_bi
== State::S1
);
1208 // If not a subtraction, yet there is a carry or B is inverted
1209 // then no optimisation is possible as carry will not be constant
1210 if (!sub
&& (sig_ci
!= State::S0
|| sig_bi
!= State::S0
))
1214 if (!sub
&& a
.is_fully_const() && a
.as_bool() == false)
1215 identity_wrt_b
= true;
1217 if (b
.is_fully_const() && b
.as_bool() == false)
1218 identity_wrt_a
= true;
1221 if (cell
->type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
), ID($shift
), ID($shiftx
)))
1223 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1225 if (b
.is_fully_const() && b
.as_bool() == false)
1226 identity_wrt_a
= true;
1229 if (cell
->type
== ID($mul
))
1231 RTLIL::SigSpec a
= assign_map(cell
->getPort(ID::A
));
1232 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1234 if (a
.is_fully_const() && is_one_or_minus_one(a
.as_const(), cell
->getParam(ID::A_SIGNED
).as_bool(), arith_inverse
))
1235 identity_wrt_b
= true;
1237 if (b
.is_fully_const() && is_one_or_minus_one(b
.as_const(), cell
->getParam(ID::B_SIGNED
).as_bool(), arith_inverse
))
1238 identity_wrt_a
= true;
1241 if (cell
->type
== ID($div
))
1243 RTLIL::SigSpec b
= assign_map(cell
->getPort(ID::B
));
1245 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
1246 identity_wrt_a
= true;
1249 if (identity_wrt_a
|| identity_wrt_b
)
1252 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1254 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell
->type
.str());
1256 log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
1257 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
1259 if (cell
->type
== ID($alu
)) {
1260 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1261 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1262 bool is_signed
= a_signed
&& b_signed
;
1263 RTLIL::SigBit sig_ci
= assign_map(cell
->getPort(ID::CI
));
1264 int y_width
= GetSize(cell
->getPort(ID::Y
));
1265 if (sig_ci
== State::S1
) {
1267 RTLIL::SigSpec a
= cell
->getPort(ID::A
);
1268 a
.extend_u0(y_width
, is_signed
);
1269 module
->connect(cell
->getPort(ID::X
), module
->Not(NEW_ID
, a
));
1270 module
->connect(cell
->getPort(ID::CO
), RTLIL::Const(State::S1
, y_width
));
1273 RTLIL::SigSpec ab
= cell
->getPort(identity_wrt_a
? ID::A
: ID::B
);
1274 ab
.extend_u0(y_width
, is_signed
);
1275 module
->connect(cell
->getPort(ID::X
), ab
);
1276 module
->connect(cell
->getPort(ID::CO
), RTLIL::Const(State::S0
, y_width
));
1278 cell
->unsetPort(ID::BI
);
1279 cell
->unsetPort(ID::CI
);
1280 cell
->unsetPort(ID::X
);
1281 cell
->unsetPort(ID::CO
);
1284 if (!identity_wrt_a
) {
1285 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1286 cell
->setParam(ID::A_WIDTH
, cell
->getParam(ID::B_WIDTH
));
1287 cell
->setParam(ID::A_SIGNED
, cell
->getParam(ID::B_SIGNED
));
1290 cell
->type
= arith_inverse
? ID($neg
) : ID($pos
);
1291 cell
->unsetPort(ID::B
);
1292 cell
->parameters
.erase(ID::B_WIDTH
);
1293 cell
->parameters
.erase(ID::B_SIGNED
);
1296 did_something
= true;
1302 if (mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
1303 cell
->getPort(ID::A
) == State::S0
&& cell
->getPort(ID::B
) == State::S1
) {
1304 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell
->type
.str());
1305 replace_cell(assign_map
, module
, cell
, "mux_bool", ID::Y
, cell
->getPort(ID::S
));
1309 if (mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) &&
1310 cell
->getPort(ID::A
) == State::S1
&& cell
->getPort(ID::B
) == State::S0
) {
1311 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell
->type
.str());
1312 log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1313 cell
->setPort(ID::A
, cell
->getPort(ID::S
));
1314 cell
->unsetPort(ID::B
);
1315 cell
->unsetPort(ID::S
);
1316 if (cell
->type
== ID($mux
)) {
1317 Const width
= cell
->parameters
[ID::WIDTH
];
1318 cell
->parameters
[ID::A_WIDTH
] = width
;
1319 cell
->parameters
[ID::Y_WIDTH
] = width
;
1320 cell
->parameters
[ID::A_SIGNED
] = 0;
1321 cell
->parameters
.erase(ID::WIDTH
);
1322 cell
->type
= ID($
not);
1324 cell
->type
= ID($_NOT_
);
1325 did_something
= true;
1329 if (consume_x
&& mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) && cell
->getPort(ID::A
) == State::S0
) {
1330 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell
->type
.str());
1331 log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1332 cell
->setPort(ID::A
, cell
->getPort(ID::S
));
1333 cell
->unsetPort(ID::S
);
1334 if (cell
->type
== ID($mux
)) {
1335 Const width
= cell
->parameters
[ID::WIDTH
];
1336 cell
->parameters
[ID::A_WIDTH
] = width
;
1337 cell
->parameters
[ID::B_WIDTH
] = width
;
1338 cell
->parameters
[ID::Y_WIDTH
] = width
;
1339 cell
->parameters
[ID::A_SIGNED
] = 0;
1340 cell
->parameters
[ID::B_SIGNED
] = 0;
1341 cell
->parameters
.erase(ID::WIDTH
);
1342 cell
->type
= ID($
and);
1344 cell
->type
= ID($_AND_
);
1345 did_something
= true;
1349 if (consume_x
&& mux_bool
&& cell
->type
.in(ID($mux
), ID($_MUX_
)) && cell
->getPort(ID::B
) == State::S1
) {
1350 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell
->type
.str());
1351 log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell
->type
), log_id(cell
), log_id(module
));
1352 cell
->setPort(ID::B
, cell
->getPort(ID::S
));
1353 cell
->unsetPort(ID::S
);
1354 if (cell
->type
== ID($mux
)) {
1355 Const width
= cell
->parameters
[ID::WIDTH
];
1356 cell
->parameters
[ID::A_WIDTH
] = width
;
1357 cell
->parameters
[ID::B_WIDTH
] = width
;
1358 cell
->parameters
[ID::Y_WIDTH
] = width
;
1359 cell
->parameters
[ID::A_SIGNED
] = 0;
1360 cell
->parameters
[ID::B_SIGNED
] = 0;
1361 cell
->parameters
.erase(ID::WIDTH
);
1362 cell
->type
= ID($
or);
1364 cell
->type
= ID($_OR_
);
1365 did_something
= true;
1369 if (mux_undef
&& cell
->type
.in(ID($mux
), ID($pmux
))) {
1370 RTLIL::SigSpec new_a
, new_b
, new_s
;
1371 int width
= GetSize(cell
->getPort(ID::A
));
1372 if ((cell
->getPort(ID::A
).is_fully_undef() && cell
->getPort(ID::B
).is_fully_undef()) ||
1373 cell
->getPort(ID::S
).is_fully_undef()) {
1374 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell
->type
.str());
1375 replace_cell(assign_map
, module
, cell
, "mux_undef", ID::Y
, cell
->getPort(ID::A
));
1378 for (int i
= 0; i
< cell
->getPort(ID::S
).size(); i
++) {
1379 RTLIL::SigSpec old_b
= cell
->getPort(ID::B
).extract(i
*width
, width
);
1380 RTLIL::SigSpec old_s
= cell
->getPort(ID::S
).extract(i
, 1);
1381 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
1383 new_b
.append(old_b
);
1384 new_s
.append(old_s
);
1386 new_a
= cell
->getPort(ID::A
);
1387 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
1388 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
1389 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
1390 new_s
= new_s
.extract(0, new_s
.size()-1);
1392 if (new_s
.size() == 0) {
1393 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell
->type
.str());
1394 replace_cell(assign_map
, module
, cell
, "mux_empty", ID::Y
, new_a
);
1397 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
1398 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell
->type
.str());
1399 replace_cell(assign_map
, module
, cell
, "mux_sel01", ID::Y
, new_s
);
1402 if (cell
->getPort(ID::S
).size() != new_s
.size()) {
1403 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell
->type
.str());
1404 log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1405 GetSize(cell
->getPort(ID::S
)) - GetSize(new_s
), log_id(cell
->type
), log_id(cell
), log_id(module
));
1406 cell
->setPort(ID::A
, new_a
);
1407 cell
->setPort(ID::B
, new_b
);
1408 cell
->setPort(ID::S
, new_s
);
1409 if (new_s
.size() > 1) {
1410 cell
->type
= ID($pmux
);
1411 cell
->parameters
[ID::S_WIDTH
] = new_s
.size();
1413 cell
->type
= ID($mux
);
1414 cell
->parameters
.erase(ID::S_WIDTH
);
1416 did_something
= true;
1420 #define FOLD_1ARG_CELL(_t) \
1421 if (cell->type == ID($##_t)) { \
1422 RTLIL::SigSpec a = cell->getPort(ID::A); \
1423 assign_map.apply(a); \
1424 if (a.is_fully_const()) { \
1425 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1426 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1427 cell->parameters[ID::A_SIGNED].as_bool(), false, \
1428 cell->parameters[ID::Y_WIDTH].as_int())); \
1429 cover("opt.opt_expr.const.$" #_t); \
1430 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \
1434 #define FOLD_2ARG_CELL(_t) \
1435 if (cell->type == ID($##_t)) { \
1436 RTLIL::SigSpec a = cell->getPort(ID::A); \
1437 RTLIL::SigSpec b = cell->getPort(ID::B); \
1438 assign_map.apply(a), assign_map.apply(b); \
1439 if (a.is_fully_const() && b.is_fully_const()) { \
1440 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1441 cell->parameters[ID::A_SIGNED].as_bool(), \
1442 cell->parameters[ID::B_SIGNED].as_bool(), \
1443 cell->parameters[ID::Y_WIDTH].as_int())); \
1444 cover("opt.opt_expr.const.$" #_t); \
1445 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
1454 FOLD_2ARG_CELL(xnor
)
1456 FOLD_1ARG_CELL(reduce_and
)
1457 FOLD_1ARG_CELL(reduce_or
)
1458 FOLD_1ARG_CELL(reduce_xor
)
1459 FOLD_1ARG_CELL(reduce_xnor
)
1460 FOLD_1ARG_CELL(reduce_bool
)
1462 FOLD_1ARG_CELL(logic_not
)
1463 FOLD_2ARG_CELL(logic_and
)
1464 FOLD_2ARG_CELL(logic_or
)
1468 FOLD_2ARG_CELL(sshl
)
1469 FOLD_2ARG_CELL(sshr
)
1470 FOLD_2ARG_CELL(shift
)
1471 FOLD_2ARG_CELL(shiftx
)
1485 FOLD_2ARG_CELL(divfloor
)
1486 FOLD_2ARG_CELL(modfloor
)
1492 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1493 if (cell
->type
== ID($mux
)) {
1494 RTLIL::SigSpec input
= assign_map(cell
->getPort(ID::S
));
1495 RTLIL::SigSpec inA
= assign_map(cell
->getPort(ID::A
));
1496 RTLIL::SigSpec inB
= assign_map(cell
->getPort(ID::B
));
1497 if (input
.is_fully_const())
1498 ACTION_DO(ID::Y
, input
.as_bool() ? cell
->getPort(ID::B
) : cell
->getPort(ID::A
));
1499 else if (inA
== inB
)
1500 ACTION_DO(ID::Y
, cell
->getPort(ID::A
));
1503 if (!keepdc
&& cell
->type
== ID($mul
))
1505 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1506 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1507 bool swapped_ab
= false;
1509 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1510 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1511 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1513 if (sig_b
.is_fully_const())
1514 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
1516 if (sig_a
.is_fully_def())
1518 if (sig_a
.is_fully_zero())
1520 cover("opt.opt_expr.mul_shift.zero");
1522 log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1523 cell
->name
.c_str(), module
->name
.c_str());
1525 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
1526 module
->remove(cell
);
1528 did_something
= true;
1533 if (sig_a
.is_onehot(&exp
) && !(a_signed
&& exp
== GetSize(sig_a
) - 1))
1536 cover("opt.opt_expr.mul_shift.swapped");
1538 cover("opt.opt_expr.mul_shift.unswapped");
1540 log_debug("Replacing multiply-by-%s cell `%s' in module `%s' with shift-by-%d.\n",
1541 log_signal(sig_a
), cell
->name
.c_str(), module
->name
.c_str(), exp
);
1544 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
1545 cell
->parameters
.at(ID::A_WIDTH
) = cell
->parameters
.at(ID::B_WIDTH
);
1546 cell
->parameters
.at(ID::A_SIGNED
) = cell
->parameters
.at(ID::B_SIGNED
);
1551 cell
->type
= ID($shl
);
1552 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1553 cell
->parameters
[ID::B_SIGNED
] = false;
1554 cell
->setPort(ID::B
, new_b
);
1557 did_something
= true;
1562 sig_a
= assign_map(cell
->getPort(ID::A
));
1563 sig_b
= assign_map(cell
->getPort(ID::B
));
1564 int a_zeros
, b_zeros
;
1565 for (a_zeros
= 0; a_zeros
< GetSize(sig_a
); a_zeros
++)
1566 if (sig_a
[a_zeros
] != RTLIL::State::S0
)
1568 for (b_zeros
= 0; b_zeros
< GetSize(sig_b
); b_zeros
++)
1569 if (sig_b
[b_zeros
] != RTLIL::State::S0
)
1571 if (a_zeros
|| b_zeros
) {
1572 int y_zeros
= a_zeros
+ b_zeros
;
1573 cover("opt.opt_expr.mul_low_zeros");
1575 log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n",
1576 a_zeros
, b_zeros
, cell
->name
.c_str(), module
->name
.c_str());
1578 if (y_zeros
>= GetSize(sig_y
)) {
1579 module
->connect(sig_y
, RTLIL::SigSpec(0, GetSize(sig_y
)));
1580 module
->remove(cell
);
1582 did_something
= true;
1587 cell
->setPort(ID::A
, sig_a
.extract_end(a_zeros
));
1588 cell
->parameters
[ID::A_WIDTH
] = GetSize(sig_a
) - a_zeros
;
1591 cell
->setPort(ID::B
, sig_b
.extract_end(b_zeros
));
1592 cell
->parameters
[ID::B_WIDTH
] = GetSize(sig_b
) - b_zeros
;
1594 cell
->setPort(ID::Y
, sig_y
.extract_end(y_zeros
));
1595 cell
->parameters
[ID::Y_WIDTH
] = GetSize(sig_y
) - y_zeros
;
1596 module
->connect(RTLIL::SigSig(sig_y
.extract(0, y_zeros
), RTLIL::SigSpec(0, y_zeros
)));
1599 did_something
= true;
1604 if (cell
->type
.in(ID($div
), ID($mod
), ID($divfloor
), ID($modfloor
)))
1606 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1607 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1608 SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1609 SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1610 SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1612 if (sig_b
.is_fully_def())
1614 if (sig_b
.is_fully_zero())
1616 cover("opt.opt_expr.divmod_zero");
1618 log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1619 cell
->name
.c_str(), module
->name
.c_str());
1621 module
->connect(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(State::Sx
, sig_y
.size())));
1622 module
->remove(cell
);
1624 did_something
= true;
1629 if (!keepdc
&& sig_b
.is_onehot(&exp
) && !(b_signed
&& exp
== GetSize(sig_b
) - 1))
1631 if (cell
->type
.in(ID($div
), ID($divfloor
)))
1633 cover("opt.opt_expr.div_shift");
1635 bool is_truncating
= cell
->type
== ID($div
);
1636 log_debug("Replacing %s-divide-by-%s cell `%s' in module `%s' with shift-by-%d.\n",
1637 is_truncating
? "truncating" : "flooring",
1638 log_signal(sig_b
), cell
->name
.c_str(), module
->name
.c_str(), exp
);
1642 cell
->type
= ID($sshr
);
1643 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1644 cell
->parameters
[ID::B_SIGNED
] = false;
1645 cell
->setPort(ID::B
, new_b
);
1647 // Truncating division is the same as flooring division, except when
1648 // the result is negative and there is a remainder - then trunc = floor + 1
1649 if (is_truncating
&& a_signed
&& GetSize(sig_a
) != 0 && exp
!= 0) {
1650 Wire
*flooring
= module
->addWire(NEW_ID
, sig_y
.size());
1651 cell
->setPort(ID::Y
, flooring
);
1653 SigSpec a_sign
= sig_a
[sig_a
.size()-1];
1654 SigSpec rem_nonzero
= module
->ReduceOr(NEW_ID
, sig_a
.extract(0, exp
));
1655 SigSpec should_add
= module
->And(NEW_ID
, a_sign
, rem_nonzero
);
1656 module
->addAdd(NEW_ID
, flooring
, should_add
, sig_y
);
1661 else if (cell
->type
.in(ID($mod
), ID($modfloor
)))
1663 cover("opt.opt_expr.mod_mask");
1665 bool is_truncating
= cell
->type
== ID($mod
);
1666 log_debug("Replacing %s-modulo-by-%s cell `%s' in module `%s' with bitmask.\n",
1667 is_truncating
? "truncating" : "flooring",
1668 log_signal(sig_b
), cell
->name
.c_str(), module
->name
.c_str());
1670 // truncating modulo has the same masked bits as flooring modulo, but
1671 // the sign bits are those of A (except when R=0)
1672 if (is_truncating
&& a_signed
&& GetSize(sig_a
) != 0 && exp
!= 0)
1674 module
->remove(cell
);
1675 SigSpec truncating
= sig_a
.extract(0, exp
);
1677 SigSpec a_sign
= sig_a
[sig_a
.size()-1];
1678 SigSpec rem_nonzero
= module
->ReduceOr(NEW_ID
, sig_a
.extract(0, exp
));
1679 SigSpec extend_bit
= module
->And(NEW_ID
, a_sign
, rem_nonzero
);
1681 truncating
.append(extend_bit
);
1682 module
->addPos(NEW_ID
, truncating
, sig_y
, true);
1686 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(State::S1
, exp
);
1688 if (b_signed
|| exp
== 0)
1689 new_b
.push_back(State::S0
);
1691 cell
->type
= ID($
and);
1692 cell
->parameters
[ID::B_WIDTH
] = GetSize(new_b
);
1693 cell
->setPort(ID::B
, new_b
);
1698 did_something
= true;
1704 // Find places in $alu cell where the carry is constant, and split it at these points.
1705 if (do_fine
&& !keepdc
&& cell
->type
== ID($alu
))
1707 bool a_signed
= cell
->parameters
[ID::A_SIGNED
].as_bool();
1708 bool b_signed
= cell
->parameters
[ID::B_SIGNED
].as_bool();
1709 bool is_signed
= a_signed
&& b_signed
;
1711 RTLIL::SigSpec sig_a
= assign_map(cell
->getPort(ID::A
));
1712 RTLIL::SigSpec sig_b
= assign_map(cell
->getPort(ID::B
));
1713 RTLIL::SigSpec sig_y
= assign_map(cell
->getPort(ID::Y
));
1714 RTLIL::SigSpec sig_bi
= assign_map(cell
->getPort(ID::BI
));
1715 if (GetSize(sig_a
) == 0)
1717 if (GetSize(sig_b
) == 0)
1719 sig_a
.extend_u0(GetSize(sig_y
), is_signed
);
1720 sig_b
.extend_u0(GetSize(sig_y
), is_signed
);
1722 if (sig_bi
!= State::S0
&& sig_bi
!= State::S1
)
1723 goto skip_alu_split
;
1725 std::vector
<std::pair
<int, State
>> split_points
;
1727 for (int i
= 0; i
< GetSize(sig_y
); i
++) {
1728 SigBit bit_a
= sig_a
[i
];
1729 SigBit bit_b
= sig_b
[i
];
1730 if (bit_a
!= State::S0
&& bit_a
!= State::S1
)
1732 if (bit_b
!= State::S0
&& bit_b
!= State::S1
)
1734 if (sig_bi
== State::S1
) {
1735 if (bit_b
== State::S0
)
1742 split_points
.push_back(std::make_pair(i
+ 1, bit_a
.data
));
1745 if (split_points
.empty() || split_points
[0].first
== GetSize(sig_y
))
1746 goto skip_alu_split
;
1748 for (auto &p
: split_points
)
1749 log_debug("Splitting $alu cell `%s' in module `%s' at const-carry point %d.\n",
1750 cell
->name
.c_str(), module
->name
.c_str(), p
.first
);
1752 if (split_points
.back().first
!= GetSize(sig_y
))
1753 split_points
.push_back(std::make_pair(GetSize(sig_y
), State::Sx
));
1755 RTLIL::SigSpec sig_ci
= assign_map(cell
->getPort(ID::CI
));
1757 RTLIL::SigSpec sig_x
= assign_map(cell
->getPort(ID::X
));
1758 RTLIL::SigSpec sig_co
= assign_map(cell
->getPort(ID::CO
));
1760 for (auto &p
: split_points
) {
1762 int sz
= cur
- prev
;
1763 bool last
= cur
== GetSize(sig_y
);
1765 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
1766 c
->setPort(ID::A
, sig_a
.extract(prev
, sz
));
1767 c
->setPort(ID::B
, sig_b
.extract(prev
, sz
));
1768 c
->setPort(ID::BI
, sig_bi
);
1769 c
->setPort(ID::CI
, sig_ci
);
1770 c
->setPort(ID::Y
, sig_y
.extract(prev
, sz
));
1771 c
->setPort(ID::X
, sig_x
.extract(prev
, sz
));
1772 RTLIL::SigSpec new_co
= sig_co
.extract(prev
, sz
);
1773 if (p
.second
!= State::Sx
) {
1774 module
->connect(new_co
[sz
-1], p
.second
);
1775 RTLIL::Wire
*dummy
= module
->addWire(NEW_ID
);
1776 new_co
[sz
-1] = dummy
;
1778 c
->setPort(ID::CO
, new_co
);
1779 c
->parameters
[ID::A_WIDTH
] = sz
;
1780 c
->parameters
[ID::B_WIDTH
] = sz
;
1781 c
->parameters
[ID::Y_WIDTH
] = sz
;
1782 c
->parameters
[ID::A_SIGNED
] = last
? a_signed
: false;
1783 c
->parameters
[ID::B_SIGNED
] = last
? b_signed
: false;
1789 cover("opt.opt_expr.alu_split");
1790 module
->remove(cell
);
1792 did_something
= true;
1797 // remove redundant pairs of bits in ==, ===, !=, and !==
1798 // replace cell with const driver if inputs can't be equal
1799 if (do_fine
&& cell
->type
.in(ID($eq
), ID($ne
), ID($eqx
), ID($nex
)))
1801 pool
<pair
<SigBit
, SigBit
>> redundant_cache
;
1802 mfp
<SigBit
> contradiction_cache
;
1804 contradiction_cache
.promote(State::S0
);
1805 contradiction_cache
.promote(State::S1
);
1807 int a_width
= cell
->getParam(ID::A_WIDTH
).as_int();
1808 int b_width
= cell
->getParam(ID::B_WIDTH
).as_int();
1810 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
1811 int width
= is_signed
? std::min(a_width
, b_width
) : std::max(a_width
, b_width
);
1813 SigSpec sig_a
= cell
->getPort(ID::A
);
1814 SigSpec sig_b
= cell
->getPort(ID::B
);
1816 int redundant_bits
= 0;
1818 for (int i
= width
-1; i
>= 0; i
--)
1820 SigBit bit_a
= i
< a_width
? assign_map(sig_a
[i
]) : State::S0
;
1821 SigBit bit_b
= i
< b_width
? assign_map(sig_b
[i
]) : State::S0
;
1823 if (bit_a
!= State::Sx
&& bit_a
!= State::Sz
&&
1824 bit_b
!= State::Sx
&& bit_b
!= State::Sz
)
1825 contradiction_cache
.merge(bit_a
, bit_b
);
1828 std::swap(bit_a
, bit_b
);
1830 pair
<SigBit
, SigBit
> key(bit_a
, bit_b
);
1832 if (redundant_cache
.count(key
)) {
1833 if (i
< a_width
) sig_a
.remove(i
);
1834 if (i
< b_width
) sig_b
.remove(i
);
1839 redundant_cache
.insert(key
);
1842 if (contradiction_cache
.find(State::S0
) == contradiction_cache
.find(State::S1
))
1844 SigSpec y_sig
= cell
->getPort(ID::Y
);
1845 Const
y_value(cell
->type
.in(ID($eq
), ID($eqx
)) ? 0 : 1, GetSize(y_sig
));
1847 log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
1848 log_id(cell
), log_id(module
), log_signal(y_value
));
1850 module
->connect(y_sig
, y_value
);
1851 module
->remove(cell
);
1853 did_something
= true;
1859 log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
1860 redundant_bits
, log_id(cell
->type
), log_id(cell
), log_id(module
));
1862 cell
->setPort(ID::A
, sig_a
);
1863 cell
->setPort(ID::B
, sig_b
);
1864 cell
->setParam(ID::A_WIDTH
, GetSize(sig_a
));
1865 cell
->setParam(ID::B_WIDTH
, GetSize(sig_b
));
1867 did_something
= true;
1872 // simplify comparisons
1873 if (do_fine
&& cell
->type
.in(ID($lt
), ID($ge
), ID($gt
), ID($le
)))
1875 IdString cmp_type
= cell
->type
;
1876 SigSpec var_sig
= cell
->getPort(ID::A
);
1877 SigSpec const_sig
= cell
->getPort(ID::B
);
1878 int var_width
= cell
->parameters
[ID::A_WIDTH
].as_int();
1879 int const_width
= cell
->parameters
[ID::B_WIDTH
].as_int();
1880 bool is_signed
= cell
->getParam(ID::A_SIGNED
).as_bool();
1882 if (!const_sig
.is_fully_const())
1884 std::swap(var_sig
, const_sig
);
1885 std::swap(var_width
, const_width
);
1886 if (cmp_type
== ID($gt
))
1888 else if (cmp_type
== ID($lt
))
1890 else if (cmp_type
== ID($ge
))
1892 else if (cmp_type
== ID($le
))
1896 if (const_sig
.is_fully_def() && const_sig
.is_fully_const())
1898 std::string condition
, replacement
;
1899 SigSpec
replace_sig(State::S0
, GetSize(cell
->getPort(ID::Y
)));
1900 bool replace
= false;
1901 bool remove
= false;
1905 if (const_sig
.is_fully_zero() && cmp_type
== ID($lt
)) {
1906 condition
= "unsigned X<0";
1907 replacement
= "constant 0";
1908 replace_sig
[0] = State::S0
;
1911 if (const_sig
.is_fully_zero() && cmp_type
== ID($ge
)) {
1912 condition
= "unsigned X>=0";
1913 replacement
= "constant 1";
1914 replace_sig
[0] = State::S1
;
1917 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== ID($gt
)) {
1918 condition
= "unsigned X>~0";
1919 replacement
= "constant 0";
1920 replace_sig
[0] = State::S0
;
1923 if (const_width
== var_width
&& const_sig
.is_fully_ones() && cmp_type
== ID($le
)) {
1924 condition
= "unsigned X<=~0";
1925 replacement
= "constant 1";
1926 replace_sig
[0] = State::S1
;
1931 if (const_sig
.is_onehot(&const_bit_hot
) && const_bit_hot
< var_width
)
1933 RTLIL::SigSpec
var_high_sig(RTLIL::State::S0
, var_width
- const_bit_hot
);
1934 for (int i
= const_bit_hot
; i
< var_width
; i
++) {
1935 var_high_sig
[i
- const_bit_hot
] = var_sig
[i
];
1938 if (cmp_type
== ID($lt
))
1940 condition
= stringf("unsigned X<%s", log_signal(const_sig
));
1941 replacement
= stringf("!X[%d:%d]", var_width
- 1, const_bit_hot
);
1942 module
->addLogicNot(NEW_ID
, var_high_sig
, cell
->getPort(ID::Y
));
1945 if (cmp_type
== ID($ge
))
1947 condition
= stringf("unsigned X>=%s", log_signal(const_sig
));
1948 replacement
= stringf("|X[%d:%d]", var_width
- 1, const_bit_hot
);
1949 module
->addReduceOr(NEW_ID
, var_high_sig
, cell
->getPort(ID::Y
));
1954 int const_bit_set
= get_highest_hot_index(const_sig
);
1955 if (const_bit_set
>= var_width
)
1958 if (cmp_type
== ID($lt
) || cmp_type
== ID($le
))
1960 if (cmp_type
== ID($lt
)) cmp_name
= "<";
1961 if (cmp_type
== ID($le
)) cmp_name
= "<=";
1962 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1963 replacement
= "constant 1";
1964 replace_sig
[0] = State::S1
;
1967 if (cmp_type
== ID($gt
) || cmp_type
== ID($ge
))
1969 if (cmp_type
== ID($gt
)) cmp_name
= ">";
1970 if (cmp_type
== ID($ge
)) cmp_name
= ">=";
1971 condition
= stringf("unsigned X[%d:0]%s%s", var_width
- 1, cmp_name
.c_str(), log_signal(const_sig
));
1972 replacement
= "constant 0";
1973 replace_sig
[0] = State::S0
;
1980 if (const_sig
.is_fully_zero() && cmp_type
== ID($lt
))
1982 condition
= "signed X<0";
1983 replacement
= stringf("X[%d]", var_width
- 1);
1984 replace_sig
[0] = var_sig
[var_width
- 1];
1987 if (const_sig
.is_fully_zero() && cmp_type
== ID($ge
))
1989 condition
= "signed X>=0";
1990 replacement
= stringf("X[%d]", var_width
- 1);
1991 module
->addNot(NEW_ID
, var_sig
[var_width
- 1], cell
->getPort(ID::Y
));
1996 if (replace
|| remove
)
1998 log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
1999 log_id(cell
->type
), log_id(cell
), condition
.c_str(), replacement
.c_str());
2001 module
->connect(cell
->getPort(ID::Y
), replace_sig
);
2002 module
->remove(cell
);
2003 did_something
= true;
2012 #undef FOLD_1ARG_CELL
2013 #undef FOLD_2ARG_CELL
2017 void replace_const_connections(RTLIL::Module
*module
) {
2018 SigMap
assign_map(module
);
2019 for (auto cell
: module
->selected_cells())
2021 std::vector
<std::pair
<RTLIL::IdString
, SigSpec
>> changes
;
2022 for (auto &conn
: cell
->connections()) {
2023 SigSpec mapped
= assign_map(conn
.second
);
2024 if (conn
.second
!= mapped
&& mapped
.is_fully_const())
2025 changes
.push_back({conn
.first
, mapped
});
2027 if (!changes
.empty())
2028 did_something
= true;
2029 for (auto &it
: changes
)
2030 cell
->setPort(it
.first
, it
.second
);
2034 struct OptExprPass
: public Pass
{
2035 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
2036 void help() override
2038 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2040 log(" opt_expr [options] [selection]\n");
2042 log("This pass performs const folding on internal cell types with constant inputs.\n");
2043 log("It also performs some simple expression rewriting.\n");
2045 log(" -mux_undef\n");
2046 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
2048 log(" -mux_bool\n");
2049 log(" replace $mux cells with inverters or buffers when possible\n");
2051 log(" -undriven\n");
2052 log(" replace undriven nets with undef (x) constants\n");
2054 log(" -noclkinv\n");
2055 log(" do not optimize clock inverters by changing FF types\n");
2058 log(" perform fine-grain optimizations\n");
2061 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
2064 log(" some optimizations change the behavior of the circuit with respect to\n");
2065 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
2066 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
2067 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
2070 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2072 bool mux_undef
= false;
2073 bool mux_bool
= false;
2074 bool undriven
= false;
2075 bool noclkinv
= false;
2076 bool do_fine
= false;
2077 bool keepdc
= false;
2079 log_header(design
, "Executing OPT_EXPR pass (perform const folding).\n");
2083 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2084 if (args
[argidx
] == "-mux_undef") {
2088 if (args
[argidx
] == "-mux_bool") {
2092 if (args
[argidx
] == "-undriven") {
2096 if (args
[argidx
] == "-noclkinv") {
2100 if (args
[argidx
] == "-fine") {
2104 if (args
[argidx
] == "-full") {
2111 if (args
[argidx
] == "-keepdc") {
2117 extra_args(args
, argidx
, design
);
2119 CellTypes
ct(design
);
2120 for (auto module
: design
->selected_modules())
2122 log("Optimizing module %s.\n", log_id(module
));
2125 did_something
= false;
2126 replace_undriven(module
, ct
);
2128 design
->scratchpad_set_bool("opt.did_something", true);
2133 did_something
= false;
2134 replace_const_cells(design
, module
, false /* consume_x */, mux_undef
, mux_bool
, do_fine
, keepdc
, noclkinv
);
2136 design
->scratchpad_set_bool("opt.did_something", true);
2137 } while (did_something
);
2139 replace_const_cells(design
, module
, true /* consume_x */, mux_undef
, mux_bool
, do_fine
, keepdc
, noclkinv
);
2141 design
->scratchpad_set_bool("opt.did_something", true);
2142 } while (did_something
);
2144 did_something
= false;
2145 replace_const_connections(module
);
2147 design
->scratchpad_set_bool("opt.did_something", true);
2156 PRIVATE_NAMESPACE_END