Hook up $aldff support in various passes.
[yosys.git] / passes / opt / opt_expr.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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::Module *module, const CellTypes &ct)
35 {
36 SigMap sigmap(module);
37 SigPool driven_signals;
38 SigPool used_signals;
39 SigPool all_signals;
40
41 dict<SigBit, pair<Wire*, State>> initbits;
42 pool<Wire*> revisit_initwires;
43
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));
50 }
51
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]);
59 }
60 }
61 if (wire->port_input)
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));
66 }
67
68 all_signals.del(driven_signals);
69 RTLIL::SigSpec undriven_signals = all_signals.export_all();
70
71 for (auto &c : undriven_signals.chunks())
72 {
73 RTLIL::SigSpec sig = c;
74
75 if (c.wire->name[0] == '$')
76 sig = used_signals.extract(sig);
77 if (sig.size() == 0)
78 continue;
79
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;
87 }
88 }
89
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);
92 did_something = true;
93 }
94
95 if (!revisit_initwires.empty())
96 {
97 SigMap sm2(module);
98
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;
105 }
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;
114 }
115 }
116 }
117 }
118
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)
121 {
122 RTLIL::SigSpec Y = cell->getPort(out_port);
123 out_val.extend_u0(Y.size(), false);
124
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));
128 // log_cell(cell);
129 assign_map.add(Y, out_val);
130 module->connect(Y, out_val);
131 module->remove(cell);
132 did_something = true;
133 }
134
135 bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc)
136 {
137 IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A;
138
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();
141
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));
145
146 sig_a.extend_u0(sig_y.size(), a_signed);
147 sig_b.extend_u0(sig_y.size(), b_signed);
148
149 std::vector<RTLIL::SigBit> bits_a = sig_a, bits_b = sig_b, bits_y = sig_y;
150
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];
153
154 for (int i = 0; i < GetSize(bits_y); i++)
155 {
156 int group_idx = GRP_DYN;
157 RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
158
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;
162 }
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;
166 }
167 else if (!keepdc) {
168 if (cell->type == ID($xor)) {
169 if (bit_a == bit_b)
170 bit_a = bit_b = RTLIL::State::S0;
171 }
172 else if (cell->type == ID($xnor)) {
173 if (bit_a == bit_b)
174 bit_a = bit_b = RTLIL::State::S1; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_
175 }
176 }
177
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;
188 }
189
190 grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
191 }
192
193 for (int i = 0; i < GRP_N; i++)
194 if (GetSize(grouped_bits[i]) == GetSize(bits_y))
195 return false;
196
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));
199
200 for (int i = 0; i < GRP_N; i++)
201 {
202 if (grouped_bits[i].empty())
203 continue;
204
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;
208
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()]);
213 }
214 new_a.append(it.first.first);
215 new_b.append(it.first.second);
216 }
217
218 if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) {
219 if (!keepdc) {
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);
224 else log_abort();
225 }
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);
229 continue;
230 }
231
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);
244 else log_abort();
245 undef_y.append(new_y[i]);
246 }
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());
253 else log_abort();
254 undef_y.append(new_y[i]);
255 }
256 else {
257 def_a.append(new_a[i]);
258 def_b.append(new_b[i]);
259 def_y.append(new_y[i]);
260 }
261 }
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);
265 if (def_y.empty()) {
266 module->connect(new_conn);
267 continue;
268 }
269 }
270 new_a = std::move(def_a);
271 new_b = std::move(def_b);
272 new_y = std::move(def_y);
273 }
274
275
276 RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
277
278 c->setPort(ID::A, new_a);
279 c->parameters[ID::A_WIDTH] = new_a.size();
280 c->parameters[ID::A_SIGNED] = false;
281
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;
286 }
287
288 c->setPort(ID::Y, new_y);
289 c->parameters[ID::Y_WIDTH] = GetSize(new_y);
290 c->check();
291
292 module->connect(new_conn);
293
294 log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
295 if (b_name == ID::B)
296 log_debug(", B=%s", log_signal(new_b));
297 log_debug("\n");
298 }
299
300 cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
301
302 module->remove(cell);
303 did_something = true;
304 return true;
305 }
306
307 void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap &assign_map, const dict<RTLIL::SigSpec, RTLIL::SigSpec> &invert_map)
308 {
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());
316 }
317 }
318
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)
320 {
321 log_assert(GetSize(type1) == GetSize(type2));
322 string cell_type = cell->type.str();
323
324 if (GetSize(type1) != GetSize(cell_type))
325 return;
326
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')
331 return;
332 type1[i] = cell_type[i];
333 type2[i] = cell_type[i];
334 }
335 }
336
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;
345 }
346 }
347 }
348
349 bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
350 {
351 bool all_bits_one = true;
352 bool last_bit_one = true;
353
354 if (GetSize(value.bits) < 1)
355 return false;
356
357 if (GetSize(value.bits) == 1) {
358 if (value.bits[0] != State::S1)
359 return false;
360 if (is_signed)
361 is_negative = true;
362 return true;
363 }
364
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;
370 }
371
372 if (all_bits_one && is_signed) {
373 is_negative = true;
374 return true;
375 }
376
377 return last_bit_one;
378 }
379
380 int get_highest_hot_index(RTLIL::SigSpec signal)
381 {
382 for (int i = GetSize(signal) - 1; i >= 0; i--)
383 {
384 if (signal[i] == RTLIL::State::S0)
385 continue;
386
387 if (signal[i] == RTLIL::State::S1)
388 return i;
389
390 break;
391 }
392
393 return -1;
394 }
395
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)
397 {
398 CellTypes ct_combinational;
399 ct_combinational.setup_internals();
400 ct_combinational.setup_stdcells();
401
402 SigMap assign_map(module);
403 dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
404
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;
408
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);
420 sig.remove_const();
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);
426 }
427 cells.node(cell);
428 }
429
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);
434
435 cells.sort();
436
437 for (auto cell : cells.sorted)
438 {
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_))
441
442 if (!noclkinv)
443 {
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);
446
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);
450 }
451
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);
454
455 if (cell->type.in(ID($aldff), ID($aldffe)))
456 handle_polarity_inv(cell, ID::ALOAD, ID::ALOAD_POLARITY, assign_map, invert_map);
457
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);
460
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);
463
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);
466
467 handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", ID::C, assign_map, invert_map);
468
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);
471
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);
474
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);
478
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);
481
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);
485
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);
489
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);
492
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);
496
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);
500
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);
505
506 handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", ID::E, assign_map, invert_map);
507
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);
510
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);
514 }
515
516 bool detect_const_and = false;
517 bool detect_const_or = false;
518
519 if (cell->type.in(ID($reduce_and), ID($_AND_)))
520 detect_const_and = true;
521
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;
524
525 if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($_OR_)))
526 detect_const_or = true;
527
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;
530
531 if (detect_const_and || detect_const_or)
532 {
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;
536
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());
540 }
541
542 for (auto bit : input_bits) {
543 if (bit.wire) {
544 if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
545 found_inv = true;
546 if (non_const_input != State::Sm)
547 many_conconst = true;
548 non_const_input = many_conconst ? State::Sm : bit;
549 } else {
550 if (bit == State::S0)
551 found_zero = true;
552 else if (bit == State::S1)
553 found_one = true;
554 else
555 found_undef = true;
556 }
557 }
558
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);
562 goto next_cell;
563 }
564
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);
568 goto next_cell;
569 }
570
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);
574 goto next_cell;
575 }
576 }
577
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()))
579 {
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);
586 goto next_cell;
587 }
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));
593 goto next_cell;
594 }
595 log_abort();
596 }
597
598 if (!sig_a.wire)
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");
603 SigSpec sig_y;
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);
608 else log_abort();
609 replace_cell(assign_map, module, cell, "xor_buffer", ID::Y, sig_y);
610 goto next_cell;
611 }
612 if (cell->type.in(ID($xnor), ID($_XNOR_))) {
613 cover("opt.opt_expr.xnor_buffer");
614 SigSpec sig_y;
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));
619 }
620 else if (cell->type == ID($_XNOR_))
621 sig_y = (sig_b == State::S1 ? sig_a : module->NotGate(NEW_ID, sig_a));
622 else log_abort();
623 replace_cell(assign_map, module, cell, "xnor_buffer", ID::Y, sig_y);
624 goto next_cell;
625 }
626 log_abort();
627 }
628 }
629
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)
632 {
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;
639 } else {
640 cover("opt.opt_expr.unary_buffer");
641 replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A));
642 }
643 goto next_cell;
644 }
645
646 if (do_fine)
647 {
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))
650 goto next_cell;
651
652 if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool)))
653 {
654 SigBit neutral_bit = cell->type == ID($reduce_and) ? State::S1 : State::S0;
655
656 RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
657 RTLIL::SigSpec new_sig_a;
658
659 for (auto bit : sig_a)
660 if (bit != neutral_bit) new_sig_a.append(bit);
661
662 if (GetSize(new_sig_a) == 0)
663 new_sig_a.append(neutral_bit);
664
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;
672 }
673 }
674
675 if (cell->type.in(ID($logic_and), ID($logic_or)))
676 {
677 SigBit neutral_bit = State::S0;
678
679 RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
680 RTLIL::SigSpec new_sig_b;
681
682 for (auto bit : sig_b)
683 if (bit != neutral_bit) new_sig_b.append(bit);
684
685 if (GetSize(new_sig_b) == 0)
686 new_sig_b.append(neutral_bit);
687
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;
695 }
696 }
697
698 if (cell->type == ID($reduce_and))
699 {
700 RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
701
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;
709 break;
710 } else if (bit.wire != NULL) {
711 new_a = RTLIL::State::Sm;
712 }
713
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;
721 }
722 }
723
724 if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_bool)))
725 {
726 RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
727
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;
735 break;
736 } else if (bit.wire != NULL) {
737 new_a = RTLIL::State::Sm;
738 }
739
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;
747 }
748 }
749
750 if (cell->type.in(ID($logic_and), ID($logic_or)))
751 {
752 RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
753
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;
761 break;
762 } else if (bit.wire != NULL) {
763 new_b = RTLIL::State::Sm;
764 }
765
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;
773 }
774 }
775
776 if (cell->type.in(ID($add), ID($sub)))
777 {
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);
783
784 int minsz = GetSize(sig_y);
785 minsz = std::min(minsz, GetSize(sig_a));
786 minsz = std::min(minsz, GetSize(sig_b));
787
788 int i;
789 for (i = 0; i < minsz; i++) {
790 RTLIL::SigBit b = sig_b[i];
791 RTLIL::SigBit a = sig_a[i];
792 if (b == State::S0)
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);
798 else
799 break;
800 }
801 if (i > 0) {
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)
807 new_a = sig_a[i-1];
808 if (new_b.empty() && is_signed)
809 new_b = sig_b[i-1];
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;
815 }
816 }
817
818 if (cell->type == ID($alu))
819 {
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();
828
829 if (sig_bi != State::S0 && sig_bi != State::S1)
830 goto skip_fine_alu;
831 if (sig_ci != State::S0 && sig_ci != State::S1)
832 goto skip_fine_alu;
833
834 bool bi = sig_bi == State::S1;
835 bool ci = sig_ci == State::S1;
836
837 int minsz = GetSize(sig_y);
838 minsz = std::min(minsz, GetSize(sig_a));
839 minsz = std::min(minsz, GetSize(sig_b));
840
841 int i;
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);
849 }
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);
854 }
855 else
856 break;
857 }
858 if (i > 0) {
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)
864 new_a = sig_a[i-1];
865 if (new_b.empty() && is_signed)
866 new_b = sig_b[i-1];
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;
874 }
875 }
876 }
877 skip_fine_alu:
878
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)))
881 {
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();
884
885 if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
886 sig_a = RTLIL::SigSpec();
887
888 for (auto &bit : sig_a.to_sigbit_vector())
889 if (bit == RTLIL::State::Sx)
890 goto found_the_x_bit;
891
892 for (auto &bit : sig_b.to_sigbit_vector())
893 if (bit == RTLIL::State::Sx)
894 goto found_the_x_bit;
895
896 if (0) {
897 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);
902 else
903 replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y))));
904 goto next_cell;
905 }
906 }
907
908 if (cell->type.in(ID($shiftx), ID($shift))) {
909 SigSpec sig_a = assign_map(cell->getPort(ID::A));
910 int width;
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))
916 continue;
917 break;
918 }
919
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;
926 goto next_cell;
927 }
928 }
929
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))));
934 goto next_cell;
935 }
936
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;
945 goto next_cell;
946 }
947
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);
954 }
955
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);
967 if (consume_x) {
968 if (input.match(" *")) ACTION_DO_Y(0);
969 if (input.match("* ")) ACTION_DO_Y(0);
970 }
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));
973 }
974
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);
986 if (consume_x) {
987 if (input.match(" *")) ACTION_DO_Y(1);
988 if (input.match("* ")) ACTION_DO_Y(1);
989 }
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));
992 }
993
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);
1003 if (consume_x) {
1004 if (input.match(" *")) ACTION_DO_Y(0);
1005 if (input.match("* ")) ACTION_DO_Y(0);
1006 }
1007 }
1008
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);
1026 goto next_cell;
1027 }
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);
1033 if (mux_undef) {
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));
1037 }
1038 }
1039
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;
1053 goto next_cell;
1054 }
1055 }
1056
1057 if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex)))
1058 {
1059 RTLIL::SigSpec a = cell->getPort(ID::A);
1060 RTLIL::SigSpec b = cell->getPort(ID::B);
1061
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());
1066 }
1067
1068 RTLIL::SigSpec new_a, new_b;
1069
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);
1077 goto next_cell;
1078 }
1079 if (a[i] == b[i])
1080 continue;
1081 new_a.append(a[i]);
1082 new_b.append(b[i]);
1083 }
1084
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);
1090 goto next_cell;
1091 }
1092
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();
1099 }
1100 }
1101
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)
1104 {
1105 RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
1106 RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
1107
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);
1112 std::swap(a, b);
1113 }
1114
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))));
1119 } else
1120 if (b.as_bool() == (cell->type == ID($eq))) {
1121 RTLIL::SigSpec input = b;
1122 ACTION_DO(ID::Y, cell->getPort(ID::A));
1123 } else {
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;
1131 }
1132 goto next_cell;
1133 }
1134 }
1135
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()))
1138 {
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));
1147 }
1148 cell->unsetPort(ID::B);
1149 cell->unsetParam(ID::B_SIGNED);
1150 cell->unsetParam(ID::B_WIDTH);
1151 did_something = true;
1152 goto next_cell;
1153 }
1154
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())
1156 {
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());
1159
1160 if (cell->type.in(ID($shl), ID($sshl)))
1161 shift_bits *= -1;
1162
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());
1165
1166 if (GetSize(sig_a) < GetSize(sig_y))
1167 sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool());
1168
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];
1175 }
1176
1177 cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
1178
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));
1181
1182 module->connect(cell->getPort(ID::Y), sig_y);
1183 module->remove(cell);
1184
1185 did_something = true;
1186 goto next_cell;
1187 }
1188
1189 if (consume_x)
1190 {
1191 bool identity_wrt_a = false;
1192 bool identity_wrt_b = false;
1193 bool arith_inverse = false;
1194
1195 if (cell->type.in(ID($add), ID($sub), ID($alu), ID($or), ID($xor)))
1196 {
1197 RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
1198 RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
1199
1200 bool sub = cell->type == ID($sub);
1201
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));
1205
1206 sub = (sig_ci == State::S1 && sig_bi == State::S1);
1207
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))
1211 goto skip_identity;
1212 }
1213
1214 if (!sub && a.is_fully_const() && a.as_bool() == false)
1215 identity_wrt_b = true;
1216
1217 if (b.is_fully_const() && b.as_bool() == false)
1218 identity_wrt_a = true;
1219 }
1220
1221 if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
1222 {
1223 RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
1224
1225 if (b.is_fully_const() && b.as_bool() == false)
1226 identity_wrt_a = true;
1227 }
1228
1229 if (cell->type == ID($mul))
1230 {
1231 RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
1232 RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
1233
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;
1236 else
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;
1239 }
1240
1241 if (cell->type == ID($div))
1242 {
1243 RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
1244
1245 if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
1246 identity_wrt_a = true;
1247 }
1248
1249 if (identity_wrt_a || identity_wrt_b)
1250 {
1251 if (identity_wrt_a)
1252 cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
1253 if (identity_wrt_b)
1254 cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
1255
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');
1258
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) {
1266 /* sub, b is 0 */
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));
1271 } else {
1272 /* add */
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));
1277 }
1278 cell->unsetPort(ID::BI);
1279 cell->unsetPort(ID::CI);
1280 cell->unsetPort(ID::X);
1281 cell->unsetPort(ID::CO);
1282 }
1283
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));
1288 }
1289
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);
1294 cell->check();
1295
1296 did_something = true;
1297 goto next_cell;
1298 }
1299 }
1300 skip_identity:
1301
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));
1306 goto next_cell;
1307 }
1308
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);
1323 } else
1324 cell->type = ID($_NOT_);
1325 did_something = true;
1326 goto next_cell;
1327 }
1328
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);
1343 } else
1344 cell->type = ID($_AND_);
1345 did_something = true;
1346 goto next_cell;
1347 }
1348
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);
1363 } else
1364 cell->type = ID($_OR_);
1365 did_something = true;
1366 goto next_cell;
1367 }
1368
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));
1376 goto next_cell;
1377 }
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())
1382 continue;
1383 new_b.append(old_b);
1384 new_s.append(old_s);
1385 }
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);
1391 }
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);
1395 goto next_cell;
1396 }
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);
1400 goto next_cell;
1401 }
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();
1412 } else {
1413 cell->type = ID($mux);
1414 cell->parameters.erase(ID::S_WIDTH);
1415 }
1416 did_something = true;
1417 }
1418 }
1419
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); \
1431 goto next_cell; \
1432 } \
1433 }
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); \
1446 goto next_cell; \
1447 } \
1448 }
1449
1450 FOLD_1ARG_CELL(not)
1451 FOLD_2ARG_CELL(and)
1452 FOLD_2ARG_CELL(or)
1453 FOLD_2ARG_CELL(xor)
1454 FOLD_2ARG_CELL(xnor)
1455
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)
1461
1462 FOLD_1ARG_CELL(logic_not)
1463 FOLD_2ARG_CELL(logic_and)
1464 FOLD_2ARG_CELL(logic_or)
1465
1466 FOLD_2ARG_CELL(shl)
1467 FOLD_2ARG_CELL(shr)
1468 FOLD_2ARG_CELL(sshl)
1469 FOLD_2ARG_CELL(sshr)
1470 FOLD_2ARG_CELL(shift)
1471 FOLD_2ARG_CELL(shiftx)
1472
1473 FOLD_2ARG_CELL(lt)
1474 FOLD_2ARG_CELL(le)
1475 FOLD_2ARG_CELL(eq)
1476 FOLD_2ARG_CELL(ne)
1477 FOLD_2ARG_CELL(gt)
1478 FOLD_2ARG_CELL(ge)
1479
1480 FOLD_2ARG_CELL(add)
1481 FOLD_2ARG_CELL(sub)
1482 FOLD_2ARG_CELL(mul)
1483 FOLD_2ARG_CELL(div)
1484 FOLD_2ARG_CELL(mod)
1485 FOLD_2ARG_CELL(divfloor)
1486 FOLD_2ARG_CELL(modfloor)
1487 FOLD_2ARG_CELL(pow)
1488
1489 FOLD_1ARG_CELL(pos)
1490 FOLD_1ARG_CELL(neg)
1491
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));
1501 }
1502
1503 if (!keepdc && cell->type == ID($mul))
1504 {
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;
1508
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));
1512
1513 if (sig_b.is_fully_const())
1514 std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
1515
1516 if (sig_a.is_fully_def())
1517 {
1518 if (sig_a.is_fully_zero())
1519 {
1520 cover("opt.opt_expr.mul_shift.zero");
1521
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());
1524
1525 module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
1526 module->remove(cell);
1527
1528 did_something = true;
1529 goto next_cell;
1530 }
1531
1532 int exp;
1533 if (sig_a.is_onehot(&exp) && !(a_signed && exp == GetSize(sig_a) - 1))
1534 {
1535 if (swapped_ab)
1536 cover("opt.opt_expr.mul_shift.swapped");
1537 else
1538 cover("opt.opt_expr.mul_shift.unswapped");
1539
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);
1542
1543 if (!swapped_ab) {
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);
1547 }
1548
1549 Const new_b = exp;
1550
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);
1555 cell->check();
1556
1557 did_something = true;
1558 goto next_cell;
1559 }
1560 }
1561
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)
1567 break;
1568 for (b_zeros = 0; b_zeros < GetSize(sig_b); b_zeros++)
1569 if (sig_b[b_zeros] != RTLIL::State::S0)
1570 break;
1571 if (a_zeros || b_zeros) {
1572 int y_zeros = a_zeros + b_zeros;
1573 cover("opt.opt_expr.mul_low_zeros");
1574
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());
1577
1578 if (y_zeros >= GetSize(sig_y)) {
1579 module->connect(sig_y, RTLIL::SigSpec(0, GetSize(sig_y)));
1580 module->remove(cell);
1581
1582 did_something = true;
1583 goto next_cell;
1584 }
1585
1586 if (a_zeros) {
1587 cell->setPort(ID::A, sig_a.extract_end(a_zeros));
1588 cell->parameters[ID::A_WIDTH] = GetSize(sig_a) - a_zeros;
1589 }
1590 if (b_zeros) {
1591 cell->setPort(ID::B, sig_b.extract_end(b_zeros));
1592 cell->parameters[ID::B_WIDTH] = GetSize(sig_b) - b_zeros;
1593 }
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)));
1597 cell->check();
1598
1599 did_something = true;
1600 goto next_cell;
1601 }
1602 }
1603
1604 if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor)))
1605 {
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));
1611
1612 if (sig_b.is_fully_def())
1613 {
1614 if (sig_b.is_fully_zero())
1615 {
1616 cover("opt.opt_expr.divmod_zero");
1617
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());
1620
1621 module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
1622 module->remove(cell);
1623
1624 did_something = true;
1625 goto next_cell;
1626 }
1627
1628 int exp;
1629 if (!keepdc && sig_b.is_onehot(&exp) && !(b_signed && exp == GetSize(sig_b) - 1))
1630 {
1631 if (cell->type.in(ID($div), ID($divfloor)))
1632 {
1633 cover("opt.opt_expr.div_shift");
1634
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);
1639
1640 Const new_b = exp;
1641
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);
1646
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);
1652
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);
1657 }
1658
1659 cell->check();
1660 }
1661 else if (cell->type.in(ID($mod), ID($modfloor)))
1662 {
1663 cover("opt.opt_expr.mod_mask");
1664
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());
1669
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)
1673 {
1674 module->remove(cell);
1675 SigSpec truncating = sig_a.extract(0, exp);
1676
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);
1680
1681 truncating.append(extend_bit);
1682 module->addPos(NEW_ID, truncating, sig_y, true);
1683 }
1684 else
1685 {
1686 std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, exp);
1687
1688 if (b_signed || exp == 0)
1689 new_b.push_back(State::S0);
1690
1691 cell->type = ID($and);
1692 cell->parameters[ID::B_WIDTH] = GetSize(new_b);
1693 cell->setPort(ID::B, new_b);
1694 cell->check();
1695 }
1696 }
1697
1698 did_something = true;
1699 goto next_cell;
1700 }
1701 }
1702 }
1703
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))
1706 {
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;
1710
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)
1716 sig_a = State::S0;
1717 if (GetSize(sig_b) == 0)
1718 sig_b = State::S0;
1719 sig_a.extend_u0(GetSize(sig_y), is_signed);
1720 sig_b.extend_u0(GetSize(sig_y), is_signed);
1721
1722 if (sig_bi != State::S0 && sig_bi != State::S1)
1723 goto skip_alu_split;
1724
1725 std::vector<std::pair<int, State>> split_points;
1726
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)
1731 continue;
1732 if (bit_b != State::S0 && bit_b != State::S1)
1733 continue;
1734 if (sig_bi == State::S1) {
1735 if (bit_b == State::S0)
1736 bit_b = State::S1;
1737 else
1738 bit_b = State::S0;
1739 }
1740 if (bit_a != bit_b)
1741 continue;
1742 split_points.push_back(std::make_pair(i + 1, bit_a.data));
1743 }
1744
1745 if (split_points.empty() || split_points[0].first == GetSize(sig_y))
1746 goto skip_alu_split;
1747
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);
1751
1752 if (split_points.back().first != GetSize(sig_y))
1753 split_points.push_back(std::make_pair(GetSize(sig_y), State::Sx));
1754
1755 RTLIL::SigSpec sig_ci = assign_map(cell->getPort(ID::CI));
1756 int prev = 0;
1757 RTLIL::SigSpec sig_x = assign_map(cell->getPort(ID::X));
1758 RTLIL::SigSpec sig_co = assign_map(cell->getPort(ID::CO));
1759
1760 for (auto &p : split_points) {
1761 int cur = p.first;
1762 int sz = cur - prev;
1763 bool last = cur == GetSize(sig_y);
1764
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;
1777 }
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;
1784
1785 prev = p.first;
1786 sig_ci = p.second;
1787 }
1788
1789 cover("opt.opt_expr.alu_split");
1790 module->remove(cell);
1791
1792 did_something = true;
1793 goto next_cell;
1794 }
1795 skip_alu_split:
1796
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)))
1800 {
1801 pool<pair<SigBit, SigBit>> redundant_cache;
1802 mfp<SigBit> contradiction_cache;
1803
1804 contradiction_cache.promote(State::S0);
1805 contradiction_cache.promote(State::S1);
1806
1807 int a_width = cell->getParam(ID::A_WIDTH).as_int();
1808 int b_width = cell->getParam(ID::B_WIDTH).as_int();
1809
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);
1812
1813 SigSpec sig_a = cell->getPort(ID::A);
1814 SigSpec sig_b = cell->getPort(ID::B);
1815
1816 int redundant_bits = 0;
1817
1818 for (int i = width-1; i >= 0; i--)
1819 {
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;
1822
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);
1826
1827 if (bit_b < bit_a)
1828 std::swap(bit_a, bit_b);
1829
1830 pair<SigBit, SigBit> key(bit_a, bit_b);
1831
1832 if (redundant_cache.count(key)) {
1833 if (i < a_width) sig_a.remove(i);
1834 if (i < b_width) sig_b.remove(i);
1835 redundant_bits++;
1836 continue;
1837 }
1838
1839 redundant_cache.insert(key);
1840 }
1841
1842 if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1))
1843 {
1844 SigSpec y_sig = cell->getPort(ID::Y);
1845 Const y_value(cell->type.in(ID($eq), ID($eqx)) ? 0 : 1, GetSize(y_sig));
1846
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));
1849
1850 module->connect(y_sig, y_value);
1851 module->remove(cell);
1852
1853 did_something = true;
1854 goto next_cell;
1855 }
1856
1857 if (redundant_bits)
1858 {
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));
1861
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));
1866
1867 did_something = true;
1868 goto next_cell;
1869 }
1870 }
1871
1872 // simplify comparisons
1873 if (do_fine && cell->type.in(ID($lt), ID($ge), ID($gt), ID($le)))
1874 {
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();
1881
1882 if (!const_sig.is_fully_const())
1883 {
1884 std::swap(var_sig, const_sig);
1885 std::swap(var_width, const_width);
1886 if (cmp_type == ID($gt))
1887 cmp_type = ID($lt);
1888 else if (cmp_type == ID($lt))
1889 cmp_type = ID($gt);
1890 else if (cmp_type == ID($ge))
1891 cmp_type = ID($le);
1892 else if (cmp_type == ID($le))
1893 cmp_type = ID($ge);
1894 }
1895
1896 if (const_sig.is_fully_def() && const_sig.is_fully_const())
1897 {
1898 std::string condition, replacement;
1899 SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID::Y)));
1900 bool replace = false;
1901 bool remove = false;
1902
1903 if (!is_signed)
1904 { /* unsigned */
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;
1909 replace = true;
1910 }
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;
1915 replace = true;
1916 }
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;
1921 replace = true;
1922 }
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;
1927 replace = true;
1928 }
1929
1930 int const_bit_hot;
1931 if (const_sig.is_onehot(&const_bit_hot) && const_bit_hot < var_width)
1932 {
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];
1936 }
1937
1938 if (cmp_type == ID($lt))
1939 {
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));
1943 remove = true;
1944 }
1945 if (cmp_type == ID($ge))
1946 {
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));
1950 remove = true;
1951 }
1952 }
1953
1954 int const_bit_set = get_highest_hot_index(const_sig);
1955 if (const_bit_set >= var_width)
1956 {
1957 string cmp_name;
1958 if (cmp_type == ID($lt) || cmp_type == ID($le))
1959 {
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;
1965 replace = true;
1966 }
1967 if (cmp_type == ID($gt) || cmp_type == ID($ge))
1968 {
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;
1974 replace = true;
1975 }
1976 }
1977 }
1978 else
1979 { /* signed */
1980 if (const_sig.is_fully_zero() && cmp_type == ID($lt))
1981 {
1982 condition = "signed X<0";
1983 replacement = stringf("X[%d]", var_width - 1);
1984 replace_sig[0] = var_sig[var_width - 1];
1985 replace = true;
1986 }
1987 if (const_sig.is_fully_zero() && cmp_type == ID($ge))
1988 {
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));
1992 remove = true;
1993 }
1994 }
1995
1996 if (replace || remove)
1997 {
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());
2000 if (replace)
2001 module->connect(cell->getPort(ID::Y), replace_sig);
2002 module->remove(cell);
2003 did_something = true;
2004 goto next_cell;
2005 }
2006 }
2007 }
2008
2009 next_cell:;
2010 #undef ACTION_DO
2011 #undef ACTION_DO_Y
2012 #undef FOLD_1ARG_CELL
2013 #undef FOLD_2ARG_CELL
2014 }
2015 }
2016
2017 void replace_const_connections(RTLIL::Module *module) {
2018 SigMap assign_map(module);
2019 for (auto cell : module->selected_cells())
2020 {
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});
2026 }
2027 if (!changes.empty())
2028 did_something = true;
2029 for (auto &it : changes)
2030 cell->setPort(it.first, it.second);
2031 }
2032 }
2033
2034 struct OptExprPass : public Pass {
2035 OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
2036 void help() override
2037 {
2038 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2039 log("\n");
2040 log(" opt_expr [options] [selection]\n");
2041 log("\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");
2044 log("\n");
2045 log(" -mux_undef\n");
2046 log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
2047 log("\n");
2048 log(" -mux_bool\n");
2049 log(" replace $mux cells with inverters or buffers when possible\n");
2050 log("\n");
2051 log(" -undriven\n");
2052 log(" replace undriven nets with undef (x) constants\n");
2053 log("\n");
2054 log(" -noclkinv\n");
2055 log(" do not optimize clock inverters by changing FF types\n");
2056 log("\n");
2057 log(" -fine\n");
2058 log(" perform fine-grain optimizations\n");
2059 log("\n");
2060 log(" -full\n");
2061 log(" alias for -mux_undef -mux_bool -undriven -fine\n");
2062 log("\n");
2063 log(" -keepdc\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");
2068 log("\n");
2069 }
2070 void execute(std::vector<std::string> args, RTLIL::Design *design) override
2071 {
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;
2078
2079 log_header(design, "Executing OPT_EXPR pass (perform const folding).\n");
2080 log_push();
2081
2082 size_t argidx;
2083 for (argidx = 1; argidx < args.size(); argidx++) {
2084 if (args[argidx] == "-mux_undef") {
2085 mux_undef = true;
2086 continue;
2087 }
2088 if (args[argidx] == "-mux_bool") {
2089 mux_bool = true;
2090 continue;
2091 }
2092 if (args[argidx] == "-undriven") {
2093 undriven = true;
2094 continue;
2095 }
2096 if (args[argidx] == "-noclkinv") {
2097 noclkinv = true;
2098 continue;
2099 }
2100 if (args[argidx] == "-fine") {
2101 do_fine = true;
2102 continue;
2103 }
2104 if (args[argidx] == "-full") {
2105 mux_undef = true;
2106 mux_bool = true;
2107 undriven = true;
2108 do_fine = true;
2109 continue;
2110 }
2111 if (args[argidx] == "-keepdc") {
2112 keepdc = true;
2113 continue;
2114 }
2115 break;
2116 }
2117 extra_args(args, argidx, design);
2118
2119 CellTypes ct(design);
2120 for (auto module : design->selected_modules())
2121 {
2122 log("Optimizing module %s.\n", log_id(module));
2123
2124 if (undriven) {
2125 did_something = false;
2126 replace_undriven(module, ct);
2127 if (did_something)
2128 design->scratchpad_set_bool("opt.did_something", true);
2129 }
2130
2131 do {
2132 do {
2133 did_something = false;
2134 replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
2135 if (did_something)
2136 design->scratchpad_set_bool("opt.did_something", true);
2137 } while (did_something);
2138 if (!keepdc)
2139 replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
2140 if (did_something)
2141 design->scratchpad_set_bool("opt.did_something", true);
2142 } while (did_something);
2143
2144 did_something = false;
2145 replace_const_connections(module);
2146 if (did_something)
2147 design->scratchpad_set_bool("opt.did_something", true);
2148
2149 log_suppressed();
2150 }
2151
2152 log_pop();
2153 }
2154 } OptExprPass;
2155
2156 PRIVATE_NAMESPACE_END