Add handling of constant reset signals to opt_rmdff
[yosys.git] / passes / opt / opt_expr.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
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"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <algorithm>
28
29 USING_YOSYS_NAMESPACE
30 PRIVATE_NAMESPACE_BEGIN
31
32 bool did_something;
33
34 void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
35 {
36 CellTypes ct(design);
37 SigMap sigmap(module);
38 SigPool driven_signals;
39 SigPool used_signals;
40 SigPool all_signals;
41
42 for (auto cell : module->cells())
43 for (auto &conn : cell->connections()) {
44 if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
45 driven_signals.add(sigmap(conn.second));
46 if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first))
47 used_signals.add(sigmap(conn.second));
48 }
49
50 for (auto wire : module->wires()) {
51 if (wire->port_input)
52 driven_signals.add(sigmap(wire));
53 if (wire->port_output)
54 used_signals.add(sigmap(wire));
55 all_signals.add(sigmap(wire));
56 }
57
58 all_signals.del(driven_signals);
59 RTLIL::SigSpec undriven_signals = all_signals.export_all();
60
61 for (auto &c : undriven_signals.chunks())
62 {
63 RTLIL::SigSpec sig = c;
64
65 if (c.wire->name[0] == '$')
66 sig = used_signals.extract(sig);
67 if (sig.size() == 0)
68 continue;
69
70 log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
71 module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
72 did_something = true;
73 }
74 }
75
76 void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
77 {
78 RTLIL::SigSpec Y = cell->getPort(out_port);
79 out_val.extend_u0(Y.size(), false);
80
81 log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
82 cell->type.c_str(), cell->name.c_str(), info.c_str(),
83 module->name.c_str(), log_signal(Y), log_signal(out_val));
84 // log_cell(cell);
85 assign_map.add(Y, out_val);
86 module->connect(Y, out_val);
87 module->remove(cell);
88 did_something = true;
89 }
90
91 bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
92 {
93 std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
94
95 bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
96 bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool();
97
98 RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A"));
99 RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name));
100 RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
101
102 sig_a.extend_u0(sig_y.size(), a_signed);
103 sig_b.extend_u0(sig_y.size(), b_signed);
104
105 std::vector<RTLIL::SigBit> bits_a = sig_a, bits_b = sig_b, bits_y = sig_y;
106
107 enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N };
108 std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::set<RTLIL::SigBit>> grouped_bits[GRP_N];
109
110 for (int i = 0; i < GetSize(bits_y); i++)
111 {
112 int group_idx = GRP_DYN;
113 RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
114
115 if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
116 bit_a = bit_b = RTLIL::State::S1;
117
118 if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
119 bit_a = bit_b = RTLIL::State::S0;
120
121 if (bit_a.wire == NULL && bit_b.wire == NULL)
122 group_idx = GRP_CONST_AB;
123 else if (bit_a.wire == NULL)
124 group_idx = GRP_CONST_A;
125 else if (bit_b.wire == NULL && commutative)
126 group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
127 else if (bit_b.wire == NULL)
128 group_idx = GRP_CONST_B;
129
130 grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
131 }
132
133 for (int i = 0; i < GRP_N; i++)
134 if (GetSize(grouped_bits[i]) == GetSize(bits_y))
135 return false;
136
137 log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
138 log_id(cell->type), log_id(cell), log_id(module));
139
140 for (int i = 0; i < GRP_N; i++)
141 {
142 if (grouped_bits[i].empty())
143 continue;
144
145 RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
146 RTLIL::SigSpec new_a, new_b;
147 RTLIL::SigSig new_conn;
148
149 for (auto &it : grouped_bits[i]) {
150 for (auto &bit : it.second) {
151 new_conn.first.append_bit(bit);
152 new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.size()));
153 }
154 new_a.append_bit(it.first.first);
155 new_b.append_bit(it.first.second);
156 }
157
158 RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
159
160 c->setPort("\\A", new_a);
161 c->parameters["\\A_WIDTH"] = new_a.size();
162 c->parameters["\\A_SIGNED"] = false;
163
164 if (b_name == "\\B") {
165 c->setPort("\\B", new_b);
166 c->parameters["\\B_WIDTH"] = new_b.size();
167 c->parameters["\\B_SIGNED"] = false;
168 }
169
170 c->setPort("\\Y", new_y);
171 c->parameters["\\Y_WIDTH"] = new_y->width;
172 c->check();
173
174 module->connect(new_conn);
175
176 log(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
177 if (b_name == "\\B")
178 log(", B=%s", log_signal(new_b));
179 log("\n");
180 }
181
182 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
183
184 module->remove(cell);
185 did_something = true;
186 return true;
187 }
188
189 void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap &assign_map, const dict<RTLIL::SigSpec, RTLIL::SigSpec> &invert_map)
190 {
191 SigSpec sig = assign_map(cell->getPort(port));
192 if (invert_map.count(sig)) {
193 log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
194 log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
195 log_signal(sig), log_signal(invert_map.at(sig)));
196 cell->setPort(port, (invert_map.at(sig)));
197 cell->setParam(param, !cell->getParam(param).as_bool());
198 }
199 }
200
201 void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdString port, const SigMap &assign_map, const dict<RTLIL::SigSpec, RTLIL::SigSpec> &invert_map)
202 {
203 log_assert(GetSize(type1) == GetSize(type2));
204 string cell_type = cell->type.str();
205
206 if (GetSize(type1) != GetSize(cell_type))
207 return;
208
209 for (int i = 0; i < GetSize(type1); i++) {
210 log_assert((type1[i] == '?') == (type2[i] == '?'));
211 if (type1[i] == '?') {
212 if (cell_type[i] != '0' && cell_type[i] != '1' && cell_type[i] != 'N' && cell_type[i] != 'P')
213 return;
214 type1[i] = cell_type[i];
215 type2[i] = cell_type[i];
216 }
217 }
218
219 if (cell->type.in(type1, type2)) {
220 SigSpec sig = assign_map(cell->getPort(port));
221 if (invert_map.count(sig)) {
222 log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
223 log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
224 log_signal(sig), log_signal(invert_map.at(sig)));
225 cell->setPort(port, (invert_map.at(sig)));
226 cell->type = cell->type == type1 ? type2 : type1;
227 }
228 }
229 }
230
231 bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
232 {
233 bool all_bits_one = true;
234 bool last_bit_one = true;
235
236 if (GetSize(value.bits) < 1)
237 return false;
238
239 if (GetSize(value.bits) == 1) {
240 if (value.bits[0] != State::S1)
241 return false;
242 if (is_signed)
243 is_negative = true;
244 return true;
245 }
246
247 for (int i = 0; i < GetSize(value.bits); i++) {
248 if (value.bits[i] != State::S1)
249 all_bits_one = false;
250 if (value.bits[i] != (i ? State::S0 : State::S1))
251 last_bit_one = false;
252 }
253
254 if (all_bits_one && is_signed) {
255 is_negative = true;
256 return true;
257 }
258
259 return last_bit_one;
260 }
261
262 // if the signal has only one bit set, return the index of that bit.
263 // otherwise return -1
264 int get_onehot_bit_index(RTLIL::SigSpec signal)
265 {
266 int bit_index = -1;
267
268 for (int i = 0; i < GetSize(signal); i++)
269 {
270 if (signal[i] == RTLIL::State::S0)
271 continue;
272
273 if (signal[i] != RTLIL::State::S1)
274 return -1;
275
276 if (bit_index != -1)
277 return -1;
278
279 bit_index = i;
280 }
281
282 return bit_index;
283 }
284
285 void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
286 {
287 if (!design->selected(module))
288 return;
289
290 CellTypes ct_combinational;
291 ct_combinational.setup_internals();
292 ct_combinational.setup_stdcells();
293
294 SigMap assign_map(module);
295 dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
296
297 TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
298 dict<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
299 dict<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
300
301 for (auto cell : module->cells())
302 if (design->selected(module, cell) && cell->type[0] == '$') {
303 if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") &&
304 cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1)
305 invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A"));
306 if ((cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == SigSpec(State::S1) && cell->getPort("\\B") == SigSpec(State::S0))
307 invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\S"));
308 if (ct_combinational.cell_known(cell->type))
309 for (auto &conn : cell->connections()) {
310 RTLIL::SigSpec sig = assign_map(conn.second);
311 sig.remove_const();
312 if (ct_combinational.cell_input(cell->type, conn.first))
313 cell_to_inbit[cell].insert(sig.begin(), sig.end());
314 if (ct_combinational.cell_output(cell->type, conn.first))
315 for (auto &bit : sig)
316 outbit_to_cell[bit].insert(cell);
317 }
318 cells.node(cell);
319 }
320
321 for (auto &it_right : cell_to_inbit)
322 for (auto &it_sigbit : it_right.second)
323 for (auto &it_left : outbit_to_cell[it_sigbit])
324 cells.edge(it_left, it_right.first);
325
326 cells.sort();
327
328 for (auto cell : cells.sorted)
329 {
330 #define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
331 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
332
333 if (clkinv)
334 {
335 if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
336 handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map);
337
338 if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) {
339 handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map);
340 handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map);
341 }
342
343 if (cell->type.in("$dffe", "$dlatch", "$dlatchsr"))
344 handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map);
345
346 handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map);
347 handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map);
348
349 handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map);
350
351 handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map);
352 handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map);
353
354 handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map);
355 handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map);
356
357 handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map);
358 handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map);
359 handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map);
360
361 handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map);
362
363 handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map);
364 handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map);
365 handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map);
366 }
367
368 bool detect_const_and = false;
369 bool detect_const_or = false;
370
371 if (cell->type.in("$reduce_and", "$_AND_"))
372 detect_const_and = true;
373
374 if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
375 detect_const_and = true;
376
377 if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
378 detect_const_or = true;
379
380 if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
381 detect_const_or = true;
382
383 if (detect_const_and || detect_const_or)
384 {
385 pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
386 bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
387 SigBit non_const_input = State::Sm;
388
389 if (cell->hasPort("\\B")) {
390 vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
391 input_bits.insert(more_bits.begin(), more_bits.end());
392 }
393
394 for (auto bit : input_bits) {
395 if (bit.wire) {
396 if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
397 found_inv = true;
398 if (non_const_input != State::Sm)
399 many_conconst = true;
400 non_const_input = many_conconst ? State::Sm : bit;
401 } else {
402 if (bit == State::S0)
403 found_zero = true;
404 else if (bit == State::S1)
405 found_one = true;
406 else
407 found_undef = true;
408 }
409 }
410
411 if (detect_const_and && (found_zero || found_inv)) {
412 cover("opt.opt_expr.const_and");
413 replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0);
414 goto next_cell;
415 }
416
417 if (detect_const_or && (found_one || found_inv)) {
418 cover("opt.opt_expr.const_or");
419 replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
420 goto next_cell;
421 }
422
423 if (non_const_input != State::Sm && !found_undef) {
424 cover("opt.opt_expr.and_or_buffer");
425 replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input);
426 goto next_cell;
427 }
428 }
429
430 if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
431 GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1)
432 {
433 if (cell->type == "$reduce_xnor") {
434 cover("opt.opt_expr.reduce_xnor_not");
435 log("Replacing %s cell `%s' in module `%s' with $not cell.\n",
436 log_id(cell->type), log_id(cell->name), log_id(module));
437 cell->type = "$not";
438 } else {
439 cover("opt.opt_expr.unary_buffer");
440 replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
441 }
442 goto next_cell;
443 }
444
445 if (do_fine)
446 {
447 if (cell->type == "$not" || cell->type == "$pos" ||
448 cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor")
449 if (group_cell_inputs(module, cell, true, assign_map))
450 goto next_cell;
451
452 if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" ||
453 cell->type == "$reduce_or" || cell->type == "$reduce_and" || cell->type == "$reduce_bool")
454 {
455 SigBit neutral_bit = cell->type == "$reduce_and" ? State::S1 : State::S0;
456
457 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
458 RTLIL::SigSpec new_sig_a;
459
460 for (auto bit : sig_a)
461 if (bit != neutral_bit) new_sig_a.append(bit);
462
463 if (GetSize(new_sig_a) == 0)
464 new_sig_a.append(neutral_bit);
465
466 if (GetSize(new_sig_a) < GetSize(sig_a)) {
467 cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
468 log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
469 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
470 cell->setPort("\\A", new_sig_a);
471 cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
472 did_something = true;
473 }
474 }
475
476 if (cell->type == "$logic_and" || cell->type == "$logic_or")
477 {
478 SigBit neutral_bit = State::S0;
479
480 RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
481 RTLIL::SigSpec new_sig_b;
482
483 for (auto bit : sig_b)
484 if (bit != neutral_bit) new_sig_b.append(bit);
485
486 if (GetSize(new_sig_b) == 0)
487 new_sig_b.append(neutral_bit);
488
489 if (GetSize(new_sig_b) < GetSize(sig_b)) {
490 cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
491 log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
492 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
493 cell->setPort("\\B", new_sig_b);
494 cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
495 did_something = true;
496 }
497 }
498
499 if (cell->type == "$reduce_and")
500 {
501 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
502
503 RTLIL::State new_a = RTLIL::State::S1;
504 for (auto &bit : sig_a.to_sigbit_vector())
505 if (bit == RTLIL::State::Sx) {
506 if (new_a == RTLIL::State::S1)
507 new_a = RTLIL::State::Sx;
508 } else if (bit == RTLIL::State::S0) {
509 new_a = RTLIL::State::S0;
510 break;
511 } else if (bit.wire != NULL) {
512 new_a = RTLIL::State::Sm;
513 }
514
515 if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
516 cover("opt.opt_expr.fine.$reduce_and");
517 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
518 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
519 cell->setPort("\\A", sig_a = new_a);
520 cell->parameters.at("\\A_WIDTH") = 1;
521 did_something = true;
522 }
523 }
524
525 if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool")
526 {
527 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
528
529 RTLIL::State new_a = RTLIL::State::S0;
530 for (auto &bit : sig_a.to_sigbit_vector())
531 if (bit == RTLIL::State::Sx) {
532 if (new_a == RTLIL::State::S0)
533 new_a = RTLIL::State::Sx;
534 } else if (bit == RTLIL::State::S1) {
535 new_a = RTLIL::State::S1;
536 break;
537 } else if (bit.wire != NULL) {
538 new_a = RTLIL::State::Sm;
539 }
540
541 if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
542 cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
543 log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
544 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
545 cell->setPort("\\A", sig_a = new_a);
546 cell->parameters.at("\\A_WIDTH") = 1;
547 did_something = true;
548 }
549 }
550
551 if (cell->type == "$logic_and" || cell->type == "$logic_or")
552 {
553 RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
554
555 RTLIL::State new_b = RTLIL::State::S0;
556 for (auto &bit : sig_b.to_sigbit_vector())
557 if (bit == RTLIL::State::Sx) {
558 if (new_b == RTLIL::State::S0)
559 new_b = RTLIL::State::Sx;
560 } else if (bit == RTLIL::State::S1) {
561 new_b = RTLIL::State::S1;
562 break;
563 } else if (bit.wire != NULL) {
564 new_b = RTLIL::State::Sm;
565 }
566
567 if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
568 cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
569 log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
570 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
571 cell->setPort("\\B", sig_b = new_b);
572 cell->parameters.at("\\B_WIDTH") = 1;
573 did_something = true;
574 }
575 }
576 }
577
578 if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
579 cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
580 cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
581 cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" ||
582 cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow")
583 {
584 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
585 RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec();
586
587 if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
588 sig_a = RTLIL::SigSpec();
589
590 for (auto &bit : sig_a.to_sigbit_vector())
591 if (bit == RTLIL::State::Sx)
592 goto found_the_x_bit;
593
594 for (auto &bit : sig_b.to_sigbit_vector())
595 if (bit == RTLIL::State::Sx)
596 goto found_the_x_bit;
597
598 if (0) {
599 found_the_x_bit:
600 cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
601 "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
602 if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
603 cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
604 replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx);
605 else
606 replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size()));
607 goto next_cell;
608 }
609 }
610
611 if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
612 invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
613 cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
614 replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
615 goto next_cell;
616 }
617
618 if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
619 cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
620 log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
621 RTLIL::SigSpec tmp = cell->getPort("\\A");
622 cell->setPort("\\A", cell->getPort("\\B"));
623 cell->setPort("\\B", tmp);
624 cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S"))));
625 did_something = true;
626 goto next_cell;
627 }
628
629 if (cell->type == "$_NOT_") {
630 RTLIL::SigSpec input = cell->getPort("\\A");
631 assign_map.apply(input);
632 if (input.match("1")) ACTION_DO_Y(0);
633 if (input.match("0")) ACTION_DO_Y(1);
634 if (input.match("*")) ACTION_DO_Y(x);
635 }
636
637 if (cell->type == "$_AND_") {
638 RTLIL::SigSpec input;
639 input.append(cell->getPort("\\B"));
640 input.append(cell->getPort("\\A"));
641 assign_map.apply(input);
642 if (input.match(" 0")) ACTION_DO_Y(0);
643 if (input.match("0 ")) ACTION_DO_Y(0);
644 if (input.match("11")) ACTION_DO_Y(1);
645 if (input.match("**")) ACTION_DO_Y(x);
646 if (input.match("1*")) ACTION_DO_Y(x);
647 if (input.match("*1")) ACTION_DO_Y(x);
648 if (consume_x) {
649 if (input.match(" *")) ACTION_DO_Y(0);
650 if (input.match("* ")) ACTION_DO_Y(0);
651 }
652 if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
653 if (input.match("1 ")) ACTION_DO("\\Y", input.extract(0, 1));
654 }
655
656 if (cell->type == "$_OR_") {
657 RTLIL::SigSpec input;
658 input.append(cell->getPort("\\B"));
659 input.append(cell->getPort("\\A"));
660 assign_map.apply(input);
661 if (input.match(" 1")) ACTION_DO_Y(1);
662 if (input.match("1 ")) ACTION_DO_Y(1);
663 if (input.match("00")) ACTION_DO_Y(0);
664 if (input.match("**")) ACTION_DO_Y(x);
665 if (input.match("0*")) ACTION_DO_Y(x);
666 if (input.match("*0")) ACTION_DO_Y(x);
667 if (consume_x) {
668 if (input.match(" *")) ACTION_DO_Y(1);
669 if (input.match("* ")) ACTION_DO_Y(1);
670 }
671 if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1));
672 if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1));
673 }
674
675 if (cell->type == "$_XOR_") {
676 RTLIL::SigSpec input;
677 input.append(cell->getPort("\\B"));
678 input.append(cell->getPort("\\A"));
679 assign_map.apply(input);
680 if (input.match("00")) ACTION_DO_Y(0);
681 if (input.match("01")) ACTION_DO_Y(1);
682 if (input.match("10")) ACTION_DO_Y(1);
683 if (input.match("11")) ACTION_DO_Y(0);
684 if (input.match(" *")) ACTION_DO_Y(x);
685 if (input.match("* ")) ACTION_DO_Y(x);
686 if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1));
687 if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1));
688 }
689
690 if (cell->type == "$_MUX_") {
691 RTLIL::SigSpec input;
692 input.append(cell->getPort("\\S"));
693 input.append(cell->getPort("\\B"));
694 input.append(cell->getPort("\\A"));
695 assign_map.apply(input);
696 if (input.extract(2, 1) == input.extract(1, 1))
697 ACTION_DO("\\Y", input.extract(2, 1));
698 if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1));
699 if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
700 if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
701 if (input.match("10 ")) {
702 cover("opt.opt_expr.mux_to_inv");
703 cell->type = "$_NOT_";
704 cell->setPort("\\A", input.extract(0, 1));
705 cell->unsetPort("\\B");
706 cell->unsetPort("\\S");
707 goto next_cell;
708 }
709 if (input.match("11 ")) ACTION_DO_Y(1);
710 if (input.match("00 ")) ACTION_DO_Y(0);
711 if (input.match("** ")) ACTION_DO_Y(x);
712 if (input.match("01*")) ACTION_DO_Y(x);
713 if (input.match("10*")) ACTION_DO_Y(x);
714 if (mux_undef) {
715 if (input.match("* ")) ACTION_DO("\\Y", input.extract(1, 1));
716 if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1));
717 if (input.match(" *")) ACTION_DO("\\Y", input.extract(2, 1));
718 }
719 }
720
721 if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
722 {
723 RTLIL::SigSpec a = cell->getPort("\\A");
724 RTLIL::SigSpec b = cell->getPort("\\B");
725
726 if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) {
727 int width = max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
728 a.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool());
729 b.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool());
730 }
731
732 RTLIL::SigSpec new_a, new_b;
733
734 log_assert(GetSize(a) == GetSize(b));
735 for (int i = 0; i < GetSize(a); i++) {
736 if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
737 cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
738 RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
739 new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
740 replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
741 goto next_cell;
742 }
743 if (a[i] == b[i])
744 continue;
745 new_a.append(a[i]);
746 new_b.append(b[i]);
747 }
748
749 if (new_a.size() == 0) {
750 cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
751 RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
752 new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
753 replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
754 goto next_cell;
755 }
756
757 if (new_a.size() < a.size() || new_b.size() < b.size()) {
758 cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
759 cell->setPort("\\A", new_a);
760 cell->setPort("\\B", new_b);
761 cell->parameters["\\A_WIDTH"] = new_a.size();
762 cell->parameters["\\B_WIDTH"] = new_b.size();
763 }
764 }
765
766 if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 &&
767 cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1)
768 {
769 RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
770 RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
771
772 if (a.is_fully_const() && !b.is_fully_const()) {
773 cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
774 cell->setPort("\\A", b);
775 cell->setPort("\\B", a);
776 std::swap(a, b);
777 }
778
779 if (b.is_fully_const()) {
780 if (b.as_bool() == (cell->type == "$eq")) {
781 RTLIL::SigSpec input = b;
782 ACTION_DO("\\Y", cell->getPort("\\A"));
783 } else {
784 cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
785 log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
786 cell->type = "$not";
787 cell->parameters.erase("\\B_WIDTH");
788 cell->parameters.erase("\\B_SIGNED");
789 cell->unsetPort("\\B");
790 did_something = true;
791 }
792 goto next_cell;
793 }
794 }
795
796 if ((cell->type == "$eq" || cell->type == "$ne") &&
797 (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
798 {
799 cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
800 log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
801 log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
802 cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
803 if (assign_map(cell->getPort("\\A")).is_fully_zero()) {
804 cell->setPort("\\A", cell->getPort("\\B"));
805 cell->setParam("\\A_SIGNED", cell->getParam("\\B_SIGNED"));
806 cell->setParam("\\A_WIDTH", cell->getParam("\\B_WIDTH"));
807 }
808 cell->unsetPort("\\B");
809 cell->unsetParam("\\B_SIGNED");
810 cell->unsetParam("\\B_WIDTH");
811 did_something = true;
812 goto next_cell;
813 }
814
815 if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const())
816 {
817 bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool();
818 int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool());
819
820 if (cell->type.in("$shl", "$sshl"))
821 shift_bits *= -1;
822
823 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
824 RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int());
825
826 if (GetSize(sig_a) < GetSize(sig_y))
827 sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool());
828
829 for (int i = 0; i < GetSize(sig_y); i++) {
830 int idx = i + shift_bits;
831 if (0 <= idx && idx < GetSize(sig_a))
832 sig_y[i] = sig_a[idx];
833 else if (GetSize(sig_a) <= idx && sign_ext)
834 sig_y[i] = sig_a[GetSize(sig_a)-1];
835 }
836
837 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
838
839 log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
840 log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
841
842 module->connect(cell->getPort("\\Y"), sig_y);
843 module->remove(cell);
844
845 did_something = true;
846 goto next_cell;
847 }
848
849 if (!keepdc)
850 {
851 bool identity_wrt_a = false;
852 bool identity_wrt_b = false;
853 bool arith_inverse = false;
854
855 if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor")
856 {
857 RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
858 RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
859
860 if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false)
861 identity_wrt_b = true;
862
863 if (b.is_fully_const() && b.as_bool() == false)
864 identity_wrt_a = true;
865 }
866
867 if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
868 {
869 RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
870
871 if (b.is_fully_const() && b.as_bool() == false)
872 identity_wrt_a = true;
873 }
874
875 if (cell->type == "$mul")
876 {
877 RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
878 RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
879
880 if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam("\\A_SIGNED").as_bool(), arith_inverse))
881 identity_wrt_b = true;
882 else
883 if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam("\\B_SIGNED").as_bool(), arith_inverse))
884 identity_wrt_a = true;
885 }
886
887 if (cell->type == "$div")
888 {
889 RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
890
891 if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
892 identity_wrt_a = true;
893 }
894
895 if (identity_wrt_a || identity_wrt_b)
896 {
897 if (identity_wrt_a)
898 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
899 if (identity_wrt_b)
900 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
901
902 log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
903 cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
904
905 if (!identity_wrt_a) {
906 cell->setPort("\\A", cell->getPort("\\B"));
907 cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
908 cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
909 }
910
911 cell->type = arith_inverse ? "$neg" : "$pos";
912 cell->unsetPort("\\B");
913 cell->parameters.erase("\\B_WIDTH");
914 cell->parameters.erase("\\B_SIGNED");
915 cell->check();
916
917 did_something = true;
918 goto next_cell;
919 }
920 }
921
922 if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
923 cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
924 cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
925 replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
926 goto next_cell;
927 }
928
929 if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
930 cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
931 cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
932 log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
933 cell->setPort("\\A", cell->getPort("\\S"));
934 cell->unsetPort("\\B");
935 cell->unsetPort("\\S");
936 if (cell->type == "$mux") {
937 Const width = cell->parameters["\\WIDTH"];
938 cell->parameters["\\A_WIDTH"] = width;
939 cell->parameters["\\Y_WIDTH"] = width;
940 cell->parameters["\\A_SIGNED"] = 0;
941 cell->parameters.erase("\\WIDTH");
942 cell->type = "$not";
943 } else
944 cell->type = "$_NOT_";
945 did_something = true;
946 goto next_cell;
947 }
948
949 if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
950 cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
951 log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
952 cell->setPort("\\A", cell->getPort("\\S"));
953 cell->unsetPort("\\S");
954 if (cell->type == "$mux") {
955 Const width = cell->parameters["\\WIDTH"];
956 cell->parameters["\\A_WIDTH"] = width;
957 cell->parameters["\\B_WIDTH"] = width;
958 cell->parameters["\\Y_WIDTH"] = width;
959 cell->parameters["\\A_SIGNED"] = 0;
960 cell->parameters["\\B_SIGNED"] = 0;
961 cell->parameters.erase("\\WIDTH");
962 cell->type = "$and";
963 } else
964 cell->type = "$_AND_";
965 did_something = true;
966 goto next_cell;
967 }
968
969 if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
970 cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
971 log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
972 cell->setPort("\\B", cell->getPort("\\S"));
973 cell->unsetPort("\\S");
974 if (cell->type == "$mux") {
975 Const width = cell->parameters["\\WIDTH"];
976 cell->parameters["\\A_WIDTH"] = width;
977 cell->parameters["\\B_WIDTH"] = width;
978 cell->parameters["\\Y_WIDTH"] = width;
979 cell->parameters["\\A_SIGNED"] = 0;
980 cell->parameters["\\B_SIGNED"] = 0;
981 cell->parameters.erase("\\WIDTH");
982 cell->type = "$or";
983 } else
984 cell->type = "$_OR_";
985 did_something = true;
986 goto next_cell;
987 }
988
989 if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) {
990 RTLIL::SigSpec new_a, new_b, new_s;
991 int width = cell->getPort("\\A").size();
992 if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
993 cell->getPort("\\S").is_fully_undef()) {
994 cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
995 replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
996 goto next_cell;
997 }
998 for (int i = 0; i < cell->getPort("\\S").size(); i++) {
999 RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width);
1000 RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1);
1001 if (old_b.is_fully_undef() || old_s.is_fully_undef())
1002 continue;
1003 new_b.append(old_b);
1004 new_s.append(old_s);
1005 }
1006 new_a = cell->getPort("\\A");
1007 if (new_a.is_fully_undef() && new_s.size() > 0) {
1008 new_a = new_b.extract((new_s.size()-1)*width, width);
1009 new_b = new_b.extract(0, (new_s.size()-1)*width);
1010 new_s = new_s.extract(0, new_s.size()-1);
1011 }
1012 if (new_s.size() == 0) {
1013 cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
1014 replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
1015 goto next_cell;
1016 }
1017 if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
1018 cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
1019 replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
1020 goto next_cell;
1021 }
1022 if (cell->getPort("\\S").size() != new_s.size()) {
1023 cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
1024 log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
1025 GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
1026 cell->setPort("\\A", new_a);
1027 cell->setPort("\\B", new_b);
1028 cell->setPort("\\S", new_s);
1029 if (new_s.size() > 1) {
1030 cell->type = "$pmux";
1031 cell->parameters["\\S_WIDTH"] = new_s.size();
1032 } else {
1033 cell->type = "$mux";
1034 cell->parameters.erase("\\S_WIDTH");
1035 }
1036 did_something = true;
1037 }
1038 }
1039
1040 #define FOLD_1ARG_CELL(_t) \
1041 if (cell->type == "$" #_t) { \
1042 RTLIL::SigSpec a = cell->getPort("\\A"); \
1043 assign_map.apply(a); \
1044 if (a.is_fully_const()) { \
1045 RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
1046 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
1047 cell->parameters["\\A_SIGNED"].as_bool(), false, \
1048 cell->parameters["\\Y_WIDTH"].as_int())); \
1049 cover("opt.opt_expr.const.$" #_t); \
1050 replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
1051 goto next_cell; \
1052 } \
1053 }
1054 #define FOLD_2ARG_CELL(_t) \
1055 if (cell->type == "$" #_t) { \
1056 RTLIL::SigSpec a = cell->getPort("\\A"); \
1057 RTLIL::SigSpec b = cell->getPort("\\B"); \
1058 assign_map.apply(a), assign_map.apply(b); \
1059 if (a.is_fully_const() && b.is_fully_const()) { \
1060 RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
1061 cell->parameters["\\A_SIGNED"].as_bool(), \
1062 cell->parameters["\\B_SIGNED"].as_bool(), \
1063 cell->parameters["\\Y_WIDTH"].as_int())); \
1064 cover("opt.opt_expr.const.$" #_t); \
1065 replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
1066 goto next_cell; \
1067 } \
1068 }
1069
1070 FOLD_1ARG_CELL(not)
1071 FOLD_2ARG_CELL(and)
1072 FOLD_2ARG_CELL(or)
1073 FOLD_2ARG_CELL(xor)
1074 FOLD_2ARG_CELL(xnor)
1075
1076 FOLD_1ARG_CELL(reduce_and)
1077 FOLD_1ARG_CELL(reduce_or)
1078 FOLD_1ARG_CELL(reduce_xor)
1079 FOLD_1ARG_CELL(reduce_xnor)
1080 FOLD_1ARG_CELL(reduce_bool)
1081
1082 FOLD_1ARG_CELL(logic_not)
1083 FOLD_2ARG_CELL(logic_and)
1084 FOLD_2ARG_CELL(logic_or)
1085
1086 FOLD_2ARG_CELL(shl)
1087 FOLD_2ARG_CELL(shr)
1088 FOLD_2ARG_CELL(sshl)
1089 FOLD_2ARG_CELL(sshr)
1090 FOLD_2ARG_CELL(shift)
1091 FOLD_2ARG_CELL(shiftx)
1092
1093 FOLD_2ARG_CELL(lt)
1094 FOLD_2ARG_CELL(le)
1095 FOLD_2ARG_CELL(eq)
1096 FOLD_2ARG_CELL(ne)
1097 FOLD_2ARG_CELL(gt)
1098 FOLD_2ARG_CELL(ge)
1099
1100 FOLD_2ARG_CELL(add)
1101 FOLD_2ARG_CELL(sub)
1102 FOLD_2ARG_CELL(mul)
1103 FOLD_2ARG_CELL(div)
1104 FOLD_2ARG_CELL(mod)
1105 FOLD_2ARG_CELL(pow)
1106
1107 FOLD_1ARG_CELL(pos)
1108 FOLD_1ARG_CELL(neg)
1109
1110 // be very conservative with optimizing $mux cells as we do not want to break mux trees
1111 if (cell->type == "$mux") {
1112 RTLIL::SigSpec input = assign_map(cell->getPort("\\S"));
1113 RTLIL::SigSpec inA = assign_map(cell->getPort("\\A"));
1114 RTLIL::SigSpec inB = assign_map(cell->getPort("\\B"));
1115 if (input.is_fully_const())
1116 ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A"));
1117 else if (inA == inB)
1118 ACTION_DO("\\Y", cell->getPort("\\A"));
1119 }
1120
1121 if (!keepdc && cell->type == "$mul")
1122 {
1123 bool a_signed = cell->parameters["\\A_SIGNED"].as_bool();
1124 bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
1125 bool swapped_ab = false;
1126
1127 RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
1128 RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
1129 RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
1130
1131 if (sig_b.is_fully_const() && sig_b.size() <= 32)
1132 std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
1133
1134 if (sig_a.is_fully_def() && sig_a.size() <= 32)
1135 {
1136 int a_val = sig_a.as_int();
1137
1138 if (a_val == 0)
1139 {
1140 cover("opt.opt_expr.mul_shift.zero");
1141
1142 log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
1143 cell->name.c_str(), module->name.c_str());
1144
1145 module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
1146 module->remove(cell);
1147
1148 did_something = true;
1149 goto next_cell;
1150 }
1151
1152 for (int i = 1; i < (a_signed ? sig_a.size()-1 : sig_a.size()); i++)
1153 if (a_val == (1 << i))
1154 {
1155 if (swapped_ab)
1156 cover("opt.opt_expr.mul_shift.swapped");
1157 else
1158 cover("opt.opt_expr.mul_shift.unswapped");
1159
1160 log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1161 a_val, cell->name.c_str(), module->name.c_str(), i);
1162
1163 if (!swapped_ab) {
1164 cell->setPort("\\A", cell->getPort("\\B"));
1165 cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
1166 cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
1167 }
1168
1169 std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
1170
1171 while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
1172 new_b.pop_back();
1173
1174 cell->type = "$shl";
1175 cell->parameters["\\B_WIDTH"] = GetSize(new_b);
1176 cell->parameters["\\B_SIGNED"] = false;
1177 cell->setPort("\\B", new_b);
1178 cell->check();
1179
1180 did_something = true;
1181 goto next_cell;
1182 }
1183 }
1184 }
1185
1186 if (!keepdc && cell->type.in("$div", "$mod"))
1187 {
1188 bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
1189 SigSpec sig_b = assign_map(cell->getPort("\\B"));
1190 SigSpec sig_y = assign_map(cell->getPort("\\Y"));
1191
1192 if (sig_b.is_fully_def() && sig_b.size() <= 32)
1193 {
1194 int b_val = sig_b.as_int();
1195
1196 if (b_val == 0)
1197 {
1198 cover("opt.opt_expr.divmod_zero");
1199
1200 log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
1201 cell->name.c_str(), module->name.c_str());
1202
1203 module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
1204 module->remove(cell);
1205
1206 did_something = true;
1207 goto next_cell;
1208 }
1209
1210 for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
1211 if (b_val == (1 << i))
1212 {
1213 if (cell->type == "$div")
1214 {
1215 cover("opt.opt_expr.div_shift");
1216
1217 log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
1218 b_val, cell->name.c_str(), module->name.c_str(), i);
1219
1220 std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
1221
1222 while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
1223 new_b.pop_back();
1224
1225 cell->type = "$shr";
1226 cell->parameters["\\B_WIDTH"] = GetSize(new_b);
1227 cell->parameters["\\B_SIGNED"] = false;
1228 cell->setPort("\\B", new_b);
1229 cell->check();
1230 }
1231 else
1232 {
1233 cover("opt.opt_expr.mod_mask");
1234
1235 log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
1236 b_val, cell->name.c_str(), module->name.c_str());
1237
1238 std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
1239
1240 if (b_signed)
1241 new_b.push_back(State::S0);
1242
1243 cell->type = "$and";
1244 cell->parameters["\\B_WIDTH"] = GetSize(new_b);
1245 cell->setPort("\\B", new_b);
1246 cell->check();
1247 }
1248
1249 did_something = true;
1250 goto next_cell;
1251 }
1252 }
1253 }
1254
1255 // replace a<0 or a>=0 with the top bit of a
1256 if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
1257 {
1258 //used to decide whether the signal needs to be negated
1259 bool is_lt = false;
1260
1261 //references the variable signal in the comparison
1262 RTLIL::SigSpec sigVar;
1263
1264 //references the constant signal in the comparison
1265 RTLIL::SigSpec sigConst;
1266
1267 // note that this signal must be constant for the optimization
1268 // to take place, but it is not checked beforehand.
1269 // If new passes are added, this signal must be checked for const-ness
1270
1271 //width of the variable port
1272 int width;
1273 int const_width;
1274
1275 bool var_signed;
1276
1277 if (cell->type == "$lt" || cell->type == "$ge") {
1278 is_lt = cell->type == "$lt" ? 1 : 0;
1279 sigVar = cell->getPort("\\A");
1280 sigConst = cell->getPort("\\B");
1281 width = cell->parameters["\\A_WIDTH"].as_int();
1282 const_width = cell->parameters["\\B_WIDTH"].as_int();
1283 var_signed = cell->parameters["\\A_SIGNED"].as_bool();
1284 } else
1285 if (cell->type == "$gt" || cell->type == "$le") {
1286 is_lt = cell->type == "$gt" ? 1 : 0;
1287 sigVar = cell->getPort("\\B");
1288 sigConst = cell->getPort("\\A");
1289 width = cell->parameters["\\B_WIDTH"].as_int();
1290 const_width = cell->parameters["\\A_WIDTH"].as_int();
1291 var_signed = cell->parameters["\\B_SIGNED"].as_bool();
1292 } else
1293 log_abort();
1294
1295 // replace a(signed) < 0 with the high bit of a
1296 if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
1297 {
1298 RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int());
1299 a_prime[0] = sigVar[width - 1];
1300 if (is_lt) {
1301 log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
1302 log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
1303 module->connect(cell->getPort("\\Y"), a_prime);
1304 module->remove(cell);
1305 } else {
1306 log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
1307 log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
1308 module->addNot(NEW_ID, a_prime, cell->getPort("\\Y"));
1309 module->remove(cell);
1310 }
1311 did_something = true;
1312 goto next_cell;
1313 } else
1314 if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
1315 {
1316 if (sigConst.is_fully_zero()) {
1317 RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
1318 if (is_lt) {
1319 log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
1320 log_id(cell->type), log_id(cell));
1321 a_prime[0] = RTLIL::State::S0;
1322 } else {
1323 log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
1324 log_id(cell->type), log_id(cell));
1325 a_prime[0] = RTLIL::State::S1;
1326 }
1327 module->connect(cell->getPort("\\Y"), a_prime);
1328 module->remove(cell);
1329 did_something = true;
1330 goto next_cell;
1331 }
1332
1333 int const_bit_set = get_onehot_bit_index(sigConst);
1334 if (const_bit_set >= 0 && const_bit_set < width) {
1335 int bit_set = const_bit_set;
1336 RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
1337 for (int i = bit_set; i < width; i++) {
1338 a_prime[i - bit_set] = sigVar[i];
1339 }
1340 if (is_lt) {
1341 log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
1342 log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
1343 module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y"));
1344 } else {
1345 log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
1346 log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
1347 module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y"));
1348 }
1349 module->remove(cell);
1350 did_something = true;
1351 goto next_cell;
1352 }
1353 else if(const_bit_set >= width && const_bit_set >= 0){
1354 RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
1355 if(is_lt){
1356 a_prime[0] = RTLIL::State::S1;
1357 log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
1358 }
1359 else{
1360 log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
1361 }
1362 module->connect(cell->getPort("\\Y"), a_prime);
1363 module->remove(cell);
1364 did_something = true;
1365 goto next_cell;
1366
1367 }
1368 }
1369 }
1370
1371 next_cell:;
1372 #undef ACTION_DO
1373 #undef ACTION_DO_Y
1374 #undef FOLD_1ARG_CELL
1375 #undef FOLD_2ARG_CELL
1376 }
1377 }
1378
1379 struct OptExprPass : public Pass {
1380 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
1381 virtual void help()
1382 {
1383 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1384 log("\n");
1385 log(" opt_expr [options] [selection]\n");
1386 log("\n");
1387 log("This pass performs const folding on internal cell types with constant inputs.\n");
1388 log("It also performs some simple expression rewritring.\n");
1389 log("\n");
1390 log(" -mux_undef\n");
1391 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
1392 log("\n");
1393 log(" -mux_bool\n");
1394 log(" replace $mux cells with inverters or buffers when possible\n");
1395 log("\n");
1396 log(" -undriven\n");
1397 log(" replace undriven nets with undef (x) constants\n");
1398 log("\n");
1399 log(" -clkinv\n");
1400 log(" optimize clock inverters by changing FF types\n");
1401 log("\n");
1402 log(" -fine\n");
1403 log(" perform fine-grain optimizations\n");
1404 log("\n");
1405 log(" -full\n");
1406 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
1407 log("\n");
1408 log(" -keepdc\n");
1409 log(" some optimizations change the behavior of the circuit with respect to\n");
1410 log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
1411 log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
1412 log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
1413 log("\n");
1414 }
1415 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
1416 {
1417 bool mux_undef = false;
1418 bool mux_bool = false;
1419 bool undriven = false;
1420 bool clkinv = false;
1421 bool do_fine = false;
1422 bool keepdc = false;
1423
1424 log_header(design, "Executing OPT_EXPR pass (perform const folding).\n");
1425 log_push();
1426
1427 size_t argidx;
1428 for (argidx = 1; argidx < args.size(); argidx++) {
1429 if (args[argidx] == "-mux_undef") {
1430 mux_undef = true;
1431 continue;
1432 }
1433 if (args[argidx] == "-mux_bool") {
1434 mux_bool = true;
1435 continue;
1436 }
1437 if (args[argidx] == "-undriven") {
1438 undriven = true;
1439 continue;
1440 }
1441 if (args[argidx] == "-clkinv") {
1442 clkinv = true;
1443 continue;
1444 }
1445 if (args[argidx] == "-fine") {
1446 do_fine = true;
1447 continue;
1448 }
1449 if (args[argidx] == "-full") {
1450 mux_undef = true;
1451 mux_bool = true;
1452 undriven = true;
1453 do_fine = true;
1454 continue;
1455 }
1456 if (args[argidx] == "-keepdc") {
1457 keepdc = true;
1458 continue;
1459 }
1460 break;
1461 }
1462 extra_args(args, argidx, design);
1463
1464 for (auto module : design->selected_modules())
1465 {
1466 if (undriven)
1467 replace_undriven(design, module);
1468
1469 do {
1470 do {
1471 did_something = false;
1472 replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv);
1473 if (did_something)
1474 design->scratchpad_set_bool("opt.did_something", true);
1475 } while (did_something);
1476 replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
1477 } while (did_something);
1478 }
1479
1480 log_pop();
1481 }
1482 } OptExprPass;
1483
1484 PRIVATE_NAMESPACE_END