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 "opt_status.h"
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/celltypes.h"
24 #include "kernel/log.h"
30 static bool did_something
;
32 static void replace_undriven(RTLIL::Design
*design
, RTLIL::Module
*module
)
35 SigMap
sigmap(module
);
36 SigPool driven_signals
;
40 for (auto &it
: module
->cells
)
41 for (auto &conn
: it
.second
->connections
) {
42 if (!ct
.cell_known(it
.second
->type
) || ct
.cell_output(it
.second
->type
, conn
.first
))
43 driven_signals
.add(sigmap(conn
.second
));
44 if (!ct
.cell_known(it
.second
->type
) || ct
.cell_input(it
.second
->type
, conn
.first
))
45 used_signals
.add(sigmap(conn
.second
));
48 for (auto &it
: module
->wires
) {
49 if (it
.second
->port_input
)
50 driven_signals
.add(sigmap(it
.second
));
51 if (it
.second
->port_output
)
52 used_signals
.add(sigmap(it
.second
));
53 all_signals
.add(sigmap(it
.second
));
56 all_signals
.del(driven_signals
);
57 RTLIL::SigSpec undriven_signals
= all_signals
.export_all();
59 for (auto &c
: undriven_signals
.chunks())
61 RTLIL::SigSpec sig
= c
;
63 if (c
.wire
->name
[0] == '$')
64 sig
= used_signals
.extract(sig
);
68 log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module
->name
), log_signal(c
));
69 module
->connections
.push_back(RTLIL::SigSig(c
, RTLIL::SigSpec(RTLIL::State::Sx
, c
.width
)));
70 OPT_DID_SOMETHING
= true;
74 static void replace_cell(RTLIL::Module
*module
, RTLIL::Cell
*cell
, std::string info
, std::string out_port
, RTLIL::SigSpec out_val
)
76 RTLIL::SigSpec Y
= cell
->connections
[out_port
];
77 out_val
.extend_u0(Y
.size(), false);
79 log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
80 cell
->type
.c_str(), cell
->name
.c_str(), info
.c_str(),
81 module
->name
.c_str(), log_signal(Y
), log_signal(out_val
));
82 // ILANG_BACKEND::dump_cell(stderr, "--> ", cell);
83 module
->connections
.push_back(RTLIL::SigSig(Y
, out_val
));
84 module
->cells
.erase(cell
->name
);
86 OPT_DID_SOMETHING
= true;
90 static bool group_cell_inputs(RTLIL::Module
*module
, RTLIL::Cell
*cell
, bool commutative
, bool extend_u0
, SigMap
&sigmap
)
92 std::string b_name
= cell
->connections
.count("\\B") ? "\\B" : "\\A";
94 bool a_signed
= cell
->parameters
.at("\\A_SIGNED").as_bool();
95 bool b_signed
= cell
->parameters
.at(b_name
+ "_SIGNED").as_bool();
97 RTLIL::SigSpec sig_a
= sigmap(cell
->connections
.at("\\A"));
98 RTLIL::SigSpec sig_b
= sigmap(cell
->connections
.at(b_name
));
99 RTLIL::SigSpec sig_y
= sigmap(cell
->connections
.at("\\Y"));
102 sig_a
.extend_u0(sig_y
.size(), a_signed
);
103 sig_b
.extend_u0(sig_y
.size(), b_signed
);
105 sig_a
.extend(sig_y
.size(), a_signed
);
106 sig_b
.extend(sig_y
.size(), b_signed
);
109 std::vector
<RTLIL::SigBit
> bits_a
= sig_a
, bits_b
= sig_b
, bits_y
= sig_y
;
111 enum { GRP_DYN
, GRP_CONST_A
, GRP_CONST_B
, GRP_CONST_AB
, GRP_N
};
112 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::set
<RTLIL::SigBit
>> grouped_bits
[GRP_N
];
114 for (int i
= 0; i
< SIZE(bits_y
); i
++)
116 int group_idx
= GRP_DYN
;
117 RTLIL::SigBit bit_a
= bits_a
[i
], bit_b
= bits_b
[i
];
119 if (cell
->type
== "$or" && (bit_a
== RTLIL::State::S1
|| bit_b
== RTLIL::State::S1
))
120 bit_a
= bit_b
= RTLIL::State::S1
;
122 if (cell
->type
== "$and" && (bit_a
== RTLIL::State::S0
|| bit_b
== RTLIL::State::S0
))
123 bit_a
= bit_b
= RTLIL::State::S0
;
125 if (bit_a
.wire
== NULL
&& bit_b
.wire
== NULL
)
126 group_idx
= GRP_CONST_AB
;
127 else if (bit_a
.wire
== NULL
)
128 group_idx
= GRP_CONST_A
;
129 else if (bit_b
.wire
== NULL
&& commutative
)
130 group_idx
= GRP_CONST_A
, std::swap(bit_a
, bit_b
);
131 else if (bit_b
.wire
== NULL
)
132 group_idx
= GRP_CONST_B
;
134 grouped_bits
[group_idx
][std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>(bit_a
, bit_b
)].insert(bits_y
[i
]);
137 for (int i
= 0; i
< GRP_N
; i
++)
138 if (SIZE(grouped_bits
[i
]) == SIZE(bits_y
))
141 log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
142 log_id(cell
->type
), log_id(cell
), log_id(module
));
144 for (int i
= 0; i
< GRP_N
; i
++)
146 if (grouped_bits
[i
].empty())
149 RTLIL::Wire
*new_y
= module
->addWire(NEW_ID
, SIZE(grouped_bits
[i
]));
150 RTLIL::SigSpec new_a
, new_b
;
151 RTLIL::SigSig new_conn
;
153 for (auto &it
: grouped_bits
[i
]) {
154 for (auto &bit
: it
.second
) {
155 new_conn
.first
.append_bit(bit
);
156 new_conn
.second
.append_bit(RTLIL::SigBit(new_y
, new_a
.size()));
158 new_a
.append_bit(it
.first
.first
);
159 new_b
.append_bit(it
.first
.second
);
162 RTLIL::Cell
*c
= module
->addCell(NEW_ID
, cell
->type
);
164 c
->connections
["\\A"] = new_a
;
165 c
->parameters
["\\A_WIDTH"] = new_a
.size();
166 c
->parameters
["\\A_SIGNED"] = false;
168 if (b_name
== "\\B") {
169 c
->connections
["\\B"] = new_b
;
170 c
->parameters
["\\B_WIDTH"] = new_b
.size();
171 c
->parameters
["\\B_SIGNED"] = false;
174 c
->connections
["\\Y"] = new_y
;
175 c
->parameters
["\\Y_WIDTH"] = new_y
->width
;
178 module
->connections
.push_back(new_conn
);
180 log(" New cell `%s': A=%s", log_id(c
), log_signal(new_a
));
182 log(", B=%s", log_signal(new_b
));
186 module
->remove(cell
);
187 OPT_DID_SOMETHING
= true;
188 did_something
= true;
192 static void replace_const_cells(RTLIL::Design
*design
, RTLIL::Module
*module
, bool consume_x
, bool mux_undef
, bool mux_bool
, bool do_fine
, bool keepdc
)
194 if (!design
->selected(module
))
197 SigMap
assign_map(module
);
198 std::map
<RTLIL::SigSpec
, RTLIL::SigSpec
> invert_map
;
200 std::vector
<RTLIL::Cell
*> cells
;
201 cells
.reserve(module
->cells
.size());
202 for (auto &cell_it
: module
->cells
)
203 if (design
->selected(module
, cell_it
.second
)) {
204 if ((cell_it
.second
->type
== "$_INV_" || cell_it
.second
->type
== "$not" || cell_it
.second
->type
== "$logic_not") &&
205 cell_it
.second
->connections
["\\A"].size() == 1 && cell_it
.second
->connections
["\\Y"].size() == 1)
206 invert_map
[assign_map(cell_it
.second
->connections
["\\Y"])] = assign_map(cell_it
.second
->connections
["\\A"]);
207 cells
.push_back(cell_it
.second
);
210 for (auto cell
: cells
)
212 #define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
213 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
217 if (cell
->type
== "$not" || cell
->type
== "$pos" || cell
->type
== "$bu0" ||
218 cell
->type
== "$and" || cell
->type
== "$or" || cell
->type
== "$xor" || cell
->type
== "$xnor")
219 if (group_cell_inputs(module
, cell
, true, cell
->type
!= "$pos", assign_map
))
222 if (cell
->type
== "$reduce_and")
224 RTLIL::SigSpec sig_a
= assign_map(cell
->connections
.at("\\A"));
226 RTLIL::State new_a
= RTLIL::State::S1
;
227 for (auto &bit
: sig_a
.to_sigbit_vector())
228 if (bit
== RTLIL::State::Sx
) {
229 if (new_a
== RTLIL::State::S1
)
230 new_a
= RTLIL::State::Sx
;
231 } else if (bit
== RTLIL::State::S0
) {
232 new_a
= RTLIL::State::S0
;
234 } else if (bit
.wire
!= NULL
) {
235 new_a
= RTLIL::State::Sm
;
238 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
239 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
240 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
241 cell
->connections
.at("\\A") = sig_a
= new_a
;
242 cell
->parameters
.at("\\A_WIDTH") = 1;
243 OPT_DID_SOMETHING
= true;
244 did_something
= true;
248 if (cell
->type
== "$logic_not" || cell
->type
== "$logic_and" || cell
->type
== "$logic_or" || cell
->type
== "$reduce_or" || cell
->type
== "$reduce_bool")
250 RTLIL::SigSpec sig_a
= assign_map(cell
->connections
.at("\\A"));
252 RTLIL::State new_a
= RTLIL::State::S0
;
253 for (auto &bit
: sig_a
.to_sigbit_vector())
254 if (bit
== RTLIL::State::Sx
) {
255 if (new_a
== RTLIL::State::S0
)
256 new_a
= RTLIL::State::Sx
;
257 } else if (bit
== RTLIL::State::S1
) {
258 new_a
= RTLIL::State::S1
;
260 } else if (bit
.wire
!= NULL
) {
261 new_a
= RTLIL::State::Sm
;
264 if (new_a
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_a
) != sig_a
) {
265 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
266 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_a
), log_signal(new_a
));
267 cell
->connections
.at("\\A") = sig_a
= new_a
;
268 cell
->parameters
.at("\\A_WIDTH") = 1;
269 OPT_DID_SOMETHING
= true;
270 did_something
= true;
274 if (cell
->type
== "$logic_and" || cell
->type
== "$logic_or")
276 RTLIL::SigSpec sig_b
= assign_map(cell
->connections
.at("\\B"));
278 RTLIL::State new_b
= RTLIL::State::S0
;
279 for (auto &bit
: sig_b
.to_sigbit_vector())
280 if (bit
== RTLIL::State::Sx
) {
281 if (new_b
== RTLIL::State::S0
)
282 new_b
= RTLIL::State::Sx
;
283 } else if (bit
== RTLIL::State::S1
) {
284 new_b
= RTLIL::State::S1
;
286 } else if (bit
.wire
!= NULL
) {
287 new_b
= RTLIL::State::Sm
;
290 if (new_b
!= RTLIL::State::Sm
&& RTLIL::SigSpec(new_b
) != sig_b
) {
291 log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
292 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), log_signal(sig_b
), log_signal(new_b
));
293 cell
->connections
.at("\\B") = sig_b
= new_b
;
294 cell
->parameters
.at("\\B_WIDTH") = 1;
295 OPT_DID_SOMETHING
= true;
296 did_something
= true;
301 if (cell
->type
== "$logic_or" && (assign_map(cell
->connections
.at("\\A")) == RTLIL::State::S1
|| assign_map(cell
->connections
.at("\\B")) == RTLIL::State::S1
)) {
302 replace_cell(module
, cell
, "one high", "\\Y", RTLIL::State::S1
);
306 if (cell
->type
== "$logic_and" && (assign_map(cell
->connections
.at("\\A")) == RTLIL::State::S0
|| assign_map(cell
->connections
.at("\\B")) == RTLIL::State::S0
)) {
307 replace_cell(module
, cell
, "one low", "\\Y", RTLIL::State::S0
);
311 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" ||
312 cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr" ||
313 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt" ||
314 cell
->type
== "$neg" || cell
->type
== "$add" || cell
->type
== "$sub" ||
315 cell
->type
== "$mul" || cell
->type
== "$div" || cell
->type
== "$mod" || cell
->type
== "$pow")
317 RTLIL::SigSpec sig_a
= assign_map(cell
->connections
.at("\\A"));
318 RTLIL::SigSpec sig_b
= cell
->connections
.count("\\B") ? assign_map(cell
->connections
.at("\\B")) : RTLIL::SigSpec();
320 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr")
321 sig_a
= RTLIL::SigSpec();
323 for (auto &bit
: sig_a
.to_sigbit_vector())
324 if (bit
== RTLIL::State::Sx
)
325 goto found_the_x_bit
;
327 for (auto &bit
: sig_b
.to_sigbit_vector())
328 if (bit
== RTLIL::State::Sx
)
329 goto found_the_x_bit
;
333 if (cell
->type
== "$reduce_xor" || cell
->type
== "$reduce_xnor" ||
334 cell
->type
== "$lt" || cell
->type
== "$le" || cell
->type
== "$ge" || cell
->type
== "$gt")
335 replace_cell(module
, cell
, "x-bit in input", "\\Y", RTLIL::State::Sx
);
337 replace_cell(module
, cell
, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx
, cell
->connections
.at("\\Y").size()));
342 if ((cell
->type
== "$_INV_" || cell
->type
== "$not" || cell
->type
== "$logic_not") && cell
->connections
["\\Y"].size() == 1 &&
343 invert_map
.count(assign_map(cell
->connections
["\\A"])) != 0) {
344 replace_cell(module
, cell
, "double_invert", "\\Y", invert_map
.at(assign_map(cell
->connections
["\\A"])));
348 if ((cell
->type
== "$_MUX_" || cell
->type
== "$mux") && invert_map
.count(assign_map(cell
->connections
["\\S"])) != 0) {
349 RTLIL::SigSpec tmp
= cell
->connections
["\\A"];
350 cell
->connections
["\\A"] = cell
->connections
["\\B"];
351 cell
->connections
["\\B"] = tmp
;
352 cell
->connections
["\\S"] = invert_map
.at(assign_map(cell
->connections
["\\S"]));
353 OPT_DID_SOMETHING
= true;
354 did_something
= true;
358 if (cell
->type
== "$_INV_") {
359 RTLIL::SigSpec input
= cell
->connections
["\\A"];
360 assign_map
.apply(input
);
361 if (input
.match("1")) ACTION_DO_Y(0);
362 if (input
.match("0")) ACTION_DO_Y(1);
363 if (input
.match("*")) ACTION_DO_Y(x
);
366 if (cell
->type
== "$_AND_") {
367 RTLIL::SigSpec input
;
368 input
.append(cell
->connections
["\\B"]);
369 input
.append(cell
->connections
["\\A"]);
370 assign_map
.apply(input
);
371 if (input
.match(" 0")) ACTION_DO_Y(0);
372 if (input
.match("0 ")) ACTION_DO_Y(0);
373 if (input
.match("11")) ACTION_DO_Y(1);
374 if (input
.match("**")) ACTION_DO_Y(x
);
375 if (input
.match("1*")) ACTION_DO_Y(x
);
376 if (input
.match("*1")) ACTION_DO_Y(x
);
378 if (input
.match(" *")) ACTION_DO_Y(0);
379 if (input
.match("* ")) ACTION_DO_Y(0);
381 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
382 if (input
.match("1 ")) ACTION_DO("\\Y", input
.extract(0, 1));
385 if (cell
->type
== "$_OR_") {
386 RTLIL::SigSpec input
;
387 input
.append(cell
->connections
["\\B"]);
388 input
.append(cell
->connections
["\\A"]);
389 assign_map
.apply(input
);
390 if (input
.match(" 1")) ACTION_DO_Y(1);
391 if (input
.match("1 ")) ACTION_DO_Y(1);
392 if (input
.match("00")) ACTION_DO_Y(0);
393 if (input
.match("**")) ACTION_DO_Y(x
);
394 if (input
.match("0*")) ACTION_DO_Y(x
);
395 if (input
.match("*0")) ACTION_DO_Y(x
);
397 if (input
.match(" *")) ACTION_DO_Y(1);
398 if (input
.match("* ")) ACTION_DO_Y(1);
400 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
401 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
404 if (cell
->type
== "$_XOR_") {
405 RTLIL::SigSpec input
;
406 input
.append(cell
->connections
["\\B"]);
407 input
.append(cell
->connections
["\\A"]);
408 assign_map
.apply(input
);
409 if (input
.match("00")) ACTION_DO_Y(0);
410 if (input
.match("01")) ACTION_DO_Y(1);
411 if (input
.match("10")) ACTION_DO_Y(1);
412 if (input
.match("11")) ACTION_DO_Y(0);
413 if (input
.match(" *")) ACTION_DO_Y(x
);
414 if (input
.match("* ")) ACTION_DO_Y(x
);
415 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(1, 1));
416 if (input
.match("0 ")) ACTION_DO("\\Y", input
.extract(0, 1));
419 if (cell
->type
== "$_MUX_") {
420 RTLIL::SigSpec input
;
421 input
.append(cell
->connections
["\\S"]);
422 input
.append(cell
->connections
["\\B"]);
423 input
.append(cell
->connections
["\\A"]);
424 assign_map
.apply(input
);
425 if (input
.extract(2, 1) == input
.extract(1, 1))
426 ACTION_DO("\\Y", input
.extract(2, 1));
427 if (input
.match(" 0")) ACTION_DO("\\Y", input
.extract(2, 1));
428 if (input
.match(" 1")) ACTION_DO("\\Y", input
.extract(1, 1));
429 if (input
.match("01 ")) ACTION_DO("\\Y", input
.extract(0, 1));
430 if (input
.match("10 ")) {
431 cell
->type
= "$_INV_";
432 cell
->connections
["\\A"] = input
.extract(0, 1);
433 cell
->connections
.erase("\\B");
434 cell
->connections
.erase("\\S");
437 if (input
.match("11 ")) ACTION_DO_Y(1);
438 if (input
.match("00 ")) ACTION_DO_Y(0);
439 if (input
.match("** ")) ACTION_DO_Y(x
);
440 if (input
.match("01*")) ACTION_DO_Y(x
);
441 if (input
.match("10*")) ACTION_DO_Y(x
);
443 if (input
.match("* ")) ACTION_DO("\\Y", input
.extract(1, 1));
444 if (input
.match(" * ")) ACTION_DO("\\Y", input
.extract(2, 1));
445 if (input
.match(" *")) ACTION_DO("\\Y", input
.extract(2, 1));
449 if (cell
->type
== "$eq" || cell
->type
== "$ne" || cell
->type
== "$eqx" || cell
->type
== "$nex")
451 RTLIL::SigSpec a
= cell
->connections
["\\A"];
452 RTLIL::SigSpec b
= cell
->connections
["\\B"];
454 if (cell
->parameters
["\\A_WIDTH"].as_int() != cell
->parameters
["\\B_WIDTH"].as_int()) {
455 int width
= std::max(cell
->parameters
["\\A_WIDTH"].as_int(), cell
->parameters
["\\B_WIDTH"].as_int());
456 a
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
457 b
.extend_u0(width
, cell
->parameters
["\\A_SIGNED"].as_bool() && cell
->parameters
["\\B_SIGNED"].as_bool());
460 RTLIL::SigSpec new_a
, new_b
;
461 a
.expand(), b
.expand();
463 assert(a
.chunks().size() == b
.chunks().size());
464 for (size_t i
= 0; i
< a
.chunks().size(); i
++) {
465 if (a
.chunks()[i
].wire
== NULL
&& b
.chunks()[i
].wire
== NULL
&& a
.chunks()[i
].data
.bits
[0] != b
.chunks()[i
].data
.bits
[0] &&
466 a
.chunks()[i
].data
.bits
[0] <= RTLIL::State::S1
&& b
.chunks()[i
].data
.bits
[0] <= RTLIL::State::S1
) {
467 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S0
: RTLIL::State::S1
);
468 new_y
.extend(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
469 replace_cell(module
, cell
, "empty", "\\Y", new_y
);
472 if (a
.chunks()[i
] == b
.chunks()[i
])
474 new_a
.append(a
.chunks()[i
]);
475 new_b
.append(b
.chunks()[i
]);
478 if (new_a
.size() == 0) {
479 RTLIL::SigSpec new_y
= RTLIL::SigSpec((cell
->type
== "$eq" || cell
->type
== "$eqx") ? RTLIL::State::S1
: RTLIL::State::S0
);
480 new_y
.extend(cell
->parameters
["\\Y_WIDTH"].as_int(), false);
481 replace_cell(module
, cell
, "empty", "\\Y", new_y
);
485 if (new_a
.size() < a
.size() || new_b
.size() < b
.size()) {
488 cell
->connections
["\\A"] = new_a
;
489 cell
->connections
["\\B"] = new_b
;
490 cell
->parameters
["\\A_WIDTH"] = new_a
.size();
491 cell
->parameters
["\\B_WIDTH"] = new_b
.size();
495 if ((cell
->type
== "$eq" || cell
->type
== "$ne") && cell
->parameters
["\\Y_WIDTH"].as_int() == 1 &&
496 cell
->parameters
["\\A_WIDTH"].as_int() == 1 && cell
->parameters
["\\B_WIDTH"].as_int() == 1)
498 RTLIL::SigSpec a
= assign_map(cell
->connections
["\\A"]);
499 RTLIL::SigSpec b
= assign_map(cell
->connections
["\\B"]);
501 if (a
.is_fully_const()) {
503 tmp
= a
, a
= b
, b
= tmp
;
504 cell
->connections
["\\A"] = a
;
505 cell
->connections
["\\B"] = b
;
508 if (b
.is_fully_const()) {
509 if (b
.as_bool() == (cell
->type
== "$eq")) {
510 RTLIL::SigSpec input
= b
;
511 ACTION_DO("\\Y", cell
->connections
["\\A"]);
514 cell
->parameters
.erase("\\B_WIDTH");
515 cell
->parameters
.erase("\\B_SIGNED");
516 cell
->connections
.erase("\\B");
524 bool identity_bu0
= false;
525 bool identity_wrt_a
= false;
526 bool identity_wrt_b
= false;
528 if (cell
->type
== "$add" || cell
->type
== "$sub" || cell
->type
== "$or" || cell
->type
== "$xor")
530 RTLIL::SigSpec a
= assign_map(cell
->connections
["\\A"]);
531 RTLIL::SigSpec b
= assign_map(cell
->connections
["\\B"]);
533 if (cell
->type
!= "$sub" && a
.is_fully_const() && a
.as_bool() == false)
534 identity_wrt_b
= true;
536 if (b
.is_fully_const() && b
.as_bool() == false)
537 identity_wrt_a
= true;
540 if (cell
->type
== "$shl" || cell
->type
== "$shr" || cell
->type
== "$sshl" || cell
->type
== "$sshr")
542 RTLIL::SigSpec b
= assign_map(cell
->connections
["\\B"]);
544 if (b
.is_fully_const() && b
.as_bool() == false)
545 identity_wrt_a
= true, identity_bu0
= true;
548 if (cell
->type
== "$mul")
550 RTLIL::SigSpec a
= assign_map(cell
->connections
["\\A"]);
551 RTLIL::SigSpec b
= assign_map(cell
->connections
["\\B"]);
553 if (a
.is_fully_const() && a
.size() <= 32 && a
.as_int() == 1)
554 identity_wrt_b
= true;
556 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
557 identity_wrt_a
= true;
560 if (cell
->type
== "$div")
562 RTLIL::SigSpec b
= assign_map(cell
->connections
["\\B"]);
564 if (b
.is_fully_const() && b
.size() <= 32 && b
.as_int() == 1)
565 identity_wrt_a
= true;
568 if (identity_wrt_a
|| identity_wrt_b
)
570 log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
571 cell
->type
.c_str(), cell
->name
.c_str(), module
->name
.c_str(), identity_wrt_a
? 'A' : 'B');
573 if (!identity_wrt_a
) {
574 cell
->connections
.at("\\A") = cell
->connections
.at("\\B");
575 cell
->parameters
.at("\\A_WIDTH") = cell
->parameters
.at("\\B_WIDTH");
576 cell
->parameters
.at("\\A_SIGNED") = cell
->parameters
.at("\\B_SIGNED");
579 cell
->type
= identity_bu0
? "$bu0" : "$pos";
580 cell
->connections
.erase("\\B");
581 cell
->parameters
.erase("\\B_WIDTH");
582 cell
->parameters
.erase("\\B_SIGNED");
585 OPT_DID_SOMETHING
= true;
586 did_something
= true;
591 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
592 cell
->connections
["\\A"] == RTLIL::SigSpec(0, 1) && cell
->connections
["\\B"] == RTLIL::SigSpec(1, 1)) {
593 replace_cell(module
, cell
, "mux_bool", "\\Y", cell
->connections
["\\S"]);
597 if (mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") &&
598 cell
->connections
["\\A"] == RTLIL::SigSpec(1, 1) && cell
->connections
["\\B"] == RTLIL::SigSpec(0, 1)) {
599 cell
->connections
["\\A"] = cell
->connections
["\\S"];
600 cell
->connections
.erase("\\B");
601 cell
->connections
.erase("\\S");
602 if (cell
->type
== "$mux") {
603 cell
->parameters
["\\A_WIDTH"] = cell
->parameters
["\\WIDTH"];
604 cell
->parameters
["\\Y_WIDTH"] = cell
->parameters
["\\WIDTH"];
605 cell
->parameters
["\\A_SIGNED"] = 0;
606 cell
->parameters
.erase("\\WIDTH");
609 cell
->type
= "$_INV_";
610 OPT_DID_SOMETHING
= true;
611 did_something
= true;
615 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->connections
["\\A"] == RTLIL::SigSpec(0, 1)) {
616 cell
->connections
["\\A"] = cell
->connections
["\\S"];
617 cell
->connections
.erase("\\S");
618 if (cell
->type
== "$mux") {
619 cell
->parameters
["\\A_WIDTH"] = cell
->parameters
["\\WIDTH"];
620 cell
->parameters
["\\B_WIDTH"] = cell
->parameters
["\\WIDTH"];
621 cell
->parameters
["\\Y_WIDTH"] = cell
->parameters
["\\WIDTH"];
622 cell
->parameters
["\\A_SIGNED"] = 0;
623 cell
->parameters
["\\B_SIGNED"] = 0;
624 cell
->parameters
.erase("\\WIDTH");
627 cell
->type
= "$_AND_";
628 OPT_DID_SOMETHING
= true;
629 did_something
= true;
633 if (consume_x
&& mux_bool
&& (cell
->type
== "$mux" || cell
->type
== "$_MUX_") && cell
->connections
["\\B"] == RTLIL::SigSpec(1, 1)) {
634 cell
->connections
["\\B"] = cell
->connections
["\\S"];
635 cell
->connections
.erase("\\S");
636 if (cell
->type
== "$mux") {
637 cell
->parameters
["\\A_WIDTH"] = cell
->parameters
["\\WIDTH"];
638 cell
->parameters
["\\B_WIDTH"] = cell
->parameters
["\\WIDTH"];
639 cell
->parameters
["\\Y_WIDTH"] = cell
->parameters
["\\WIDTH"];
640 cell
->parameters
["\\A_SIGNED"] = 0;
641 cell
->parameters
["\\B_SIGNED"] = 0;
642 cell
->parameters
.erase("\\WIDTH");
645 cell
->type
= "$_OR_";
646 OPT_DID_SOMETHING
= true;
647 did_something
= true;
651 if (mux_undef
&& (cell
->type
== "$mux" || cell
->type
== "$pmux")) {
652 RTLIL::SigSpec new_a
, new_b
, new_s
;
653 int width
= cell
->connections
.at("\\A").size();
654 if ((cell
->connections
.at("\\A").is_fully_undef() && cell
->connections
.at("\\B").is_fully_undef()) ||
655 cell
->connections
.at("\\S").is_fully_undef()) {
656 replace_cell(module
, cell
, "mux undef", "\\Y", cell
->connections
.at("\\A"));
659 for (int i
= 0; i
< cell
->connections
.at("\\S").size(); i
++) {
660 RTLIL::SigSpec old_b
= cell
->connections
.at("\\B").extract(i
*width
, width
);
661 RTLIL::SigSpec old_s
= cell
->connections
.at("\\S").extract(i
, 1);
662 if (old_b
.is_fully_undef() || old_s
.is_fully_undef())
667 new_a
= cell
->connections
.at("\\A");
668 if (new_a
.is_fully_undef() && new_s
.size() > 0) {
669 new_a
= new_b
.extract((new_s
.size()-1)*width
, width
);
670 new_b
= new_b
.extract(0, (new_s
.size()-1)*width
);
671 new_s
= new_s
.extract(0, new_s
.size()-1);
673 if (new_s
.size() == 0) {
674 replace_cell(module
, cell
, "mux undef", "\\Y", new_a
);
677 if (new_a
== RTLIL::SigSpec(RTLIL::State::S0
) && new_b
== RTLIL::SigSpec(RTLIL::State::S1
)) {
678 replace_cell(module
, cell
, "mux undef", "\\Y", new_s
);
681 if (cell
->connections
.at("\\S").size() != new_s
.size()) {
682 cell
->connections
.at("\\A") = new_a
;
683 cell
->connections
.at("\\B") = new_b
;
684 cell
->connections
.at("\\S") = new_s
;
685 if (new_s
.size() > 1) {
686 cell
->type
= "$pmux";
687 cell
->parameters
["\\S_WIDTH"] = new_s
.size();
690 cell
->parameters
.erase("\\S_WIDTH");
692 OPT_DID_SOMETHING
= true;
693 did_something
= true;
697 #define FOLD_1ARG_CELL(_t) \
698 if (cell->type == "$" #_t) { \
699 RTLIL::SigSpec a = cell->connections["\\A"]; \
700 assign_map.apply(a); \
701 if (a.is_fully_const()) { \
702 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
703 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
704 cell->parameters["\\A_SIGNED"].as_bool(), false, \
705 cell->parameters["\\Y_WIDTH"].as_int())); \
706 replace_cell(module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
710 #define FOLD_2ARG_CELL(_t) \
711 if (cell->type == "$" #_t) { \
712 RTLIL::SigSpec a = cell->connections["\\A"]; \
713 RTLIL::SigSpec b = cell->connections["\\B"]; \
714 assign_map.apply(a), assign_map.apply(b); \
715 if (a.is_fully_const() && b.is_fully_const()) { \
716 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
717 cell->parameters["\\A_SIGNED"].as_bool(), \
718 cell->parameters["\\B_SIGNED"].as_bool(), \
719 cell->parameters["\\Y_WIDTH"].as_int())); \
720 replace_cell(module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
731 FOLD_1ARG_CELL(reduce_and
)
732 FOLD_1ARG_CELL(reduce_or
)
733 FOLD_1ARG_CELL(reduce_xor
)
734 FOLD_1ARG_CELL(reduce_xnor
)
735 FOLD_1ARG_CELL(reduce_bool
)
737 FOLD_1ARG_CELL(logic_not
)
738 FOLD_2ARG_CELL(logic_and
)
739 FOLD_2ARG_CELL(logic_or
)
764 // be very conservative with optimizing $mux cells as we do not want to break mux trees
765 if (cell
->type
== "$mux") {
766 RTLIL::SigSpec input
= assign_map(cell
->connections
["\\S"]);
767 RTLIL::SigSpec inA
= assign_map(cell
->connections
["\\A"]);
768 RTLIL::SigSpec inB
= assign_map(cell
->connections
["\\B"]);
769 if (input
.is_fully_const())
770 ACTION_DO("\\Y", input
.as_bool() ? cell
->connections
["\\B"] : cell
->connections
["\\A"]);
772 ACTION_DO("\\Y", cell
->connections
["\\A"]);
775 if (!keepdc
&& cell
->type
== "$mul")
777 bool a_signed
= cell
->parameters
["\\A_SIGNED"].as_bool();
778 bool b_signed
= cell
->parameters
["\\B_SIGNED"].as_bool();
779 bool swapped_ab
= false;
781 RTLIL::SigSpec sig_a
= assign_map(cell
->connections
["\\A"]);
782 RTLIL::SigSpec sig_b
= assign_map(cell
->connections
["\\B"]);
783 RTLIL::SigSpec sig_y
= assign_map(cell
->connections
["\\Y"]);
785 if (sig_b
.is_fully_const() && sig_b
.size() <= 32)
786 std::swap(sig_a
, sig_b
), std::swap(a_signed
, b_signed
), swapped_ab
= true;
788 if (sig_a
.is_fully_def() && sig_a
.size() <= 32)
790 int a_val
= sig_a
.as_int();
794 log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
795 cell
->name
.c_str(), module
->name
.c_str());
797 module
->connections
.push_back(RTLIL::SigSig(sig_y
, RTLIL::SigSpec(0, sig_y
.size())));
798 module
->remove(cell
);
800 OPT_DID_SOMETHING
= true;
801 did_something
= true;
805 for (int i
= 1; i
< (a_signed
? sig_a
.size()-1 : sig_a
.size()); i
++)
806 if (a_val
== (1 << i
))
808 log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
809 a_val
, cell
->name
.c_str(), module
->name
.c_str(), i
);
812 cell
->connections
["\\A"] = cell
->connections
["\\B"];
813 cell
->parameters
["\\A_WIDTH"] = cell
->parameters
["\\B_WIDTH"];
814 cell
->parameters
["\\A_SIGNED"] = cell
->parameters
["\\B_SIGNED"];
817 std::vector
<RTLIL::SigBit
> new_b
= RTLIL::SigSpec(i
, 6);
819 while (SIZE(new_b
) > 1 && new_b
.back() == RTLIL::State::S0
)
823 cell
->parameters
["\\B_WIDTH"] = SIZE(new_b
);
824 cell
->parameters
["\\B_SIGNED"] = false;
825 cell
->connections
["\\B"] = new_b
;
828 OPT_DID_SOMETHING
= true;
829 did_something
= true;
838 #undef FOLD_1ARG_CELL
839 #undef FOLD_2ARG_CELL
843 struct OptConstPass
: public Pass
{
844 OptConstPass() : Pass("opt_const", "perform const folding") { }
847 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
849 log(" opt_const [options] [selection]\n");
851 log("This pass performs const folding on internal cell types with constant inputs.\n");
853 log(" -mux_undef\n");
854 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
857 log(" replace $mux cells with inverters or buffers when possible\n");
860 log(" replace undriven nets with undef (x) constants\n");
863 log(" some optimizations change the behavior of the circuit with respect to\n");
864 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
865 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
866 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
869 log(" perform fine-grain optimizations\n");
872 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
874 bool mux_undef
= false;
875 bool mux_bool
= false;
876 bool undriven
= false;
877 bool do_fine
= false;
880 log_header("Executing OPT_CONST pass (perform const folding).\n");
884 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
885 if (args
[argidx
] == "-mux_undef") {
889 if (args
[argidx
] == "-mux_bool") {
893 if (args
[argidx
] == "-undriven") {
897 if (args
[argidx
] == "-fine") {
901 if (args
[argidx
] == "-keepdc") {
907 extra_args(args
, argidx
, design
);
909 for (auto &mod_it
: design
->modules
)
912 replace_undriven(design
, mod_it
.second
);
916 did_something
= false;
917 replace_const_cells(design
, mod_it
.second
, false, mux_undef
, mux_bool
, do_fine
, keepdc
);
918 } while (did_something
);
919 replace_const_cells(design
, mod_it
.second
, true, mux_undef
, mux_bool
, do_fine
, keepdc
);
920 } while (did_something
);