e5de2bcc4cf21cb185d5e90e1348d70cc16d8c76
[yosys.git] / passes / techmap / abc9_ops.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * 2019 Eddie Hung <eddie@fpgeh.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/utils.h"
24 #include "kernel/celltypes.h"
25 #include "kernel/timinginfo.h"
26
27 USING_YOSYS_NAMESPACE
28 PRIVATE_NAMESPACE_BEGIN
29
30 int map_autoidx;
31
32 inline std::string remap_name(RTLIL::IdString abc9_name)
33 {
34 return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
35 }
36
37 void check(RTLIL::Design *design)
38 {
39 dict<IdString,IdString> box_lookup;
40 for (auto m : design->modules()) {
41 if (m->name.begins_with("$paramod"))
42 continue;
43
44 auto flop = m->get_bool_attribute(ID(abc9_flop));
45 auto it = m->attributes.find(ID(abc9_box_id));
46 if (!flop) {
47 if (it == m->attributes.end())
48 continue;
49 auto id = it->second.as_int();
50 auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));
51 if (!r.second)
52 log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
53 log_id(m), id, log_id(r.first->second));
54 }
55
56 // Make carry in the last PI, and carry out the last PO
57 // since ABC requires it this way
58 IdString carry_in, carry_out;
59 for (const auto &port_name : m->ports) {
60 auto w = m->wire(port_name);
61 log_assert(w);
62 if (w->get_bool_attribute("\\abc9_carry")) {
63 if (w->port_input) {
64 if (carry_in != IdString())
65 log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m));
66 carry_in = port_name;
67 }
68 if (w->port_output) {
69 if (carry_out != IdString())
70 log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m));
71 carry_out = port_name;
72 }
73 }
74 }
75
76 if (carry_in != IdString() && carry_out == IdString())
77 log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m));
78 if (carry_in == IdString() && carry_out != IdString())
79 log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m));
80
81 if (flop) {
82 int num_outputs = 0;
83 for (auto port_name : m->ports) {
84 auto wire = m->wire(port_name);
85 if (wire->port_output) num_outputs++;
86 }
87 if (num_outputs != 1)
88 log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs);
89 }
90 }
91 }
92
93 void mark_scc(RTLIL::Module *module)
94 {
95 // For every unique SCC found, (arbitrarily) find the first
96 // cell in the component, and convert all wires driven by
97 // its output ports into a new PO, and drive its previous
98 // sinks with a new PI
99 pool<RTLIL::Const> ids_seen;
100 for (auto cell : module->cells()) {
101 auto it = cell->attributes.find(ID(abc9_scc_id));
102 if (it == cell->attributes.end())
103 continue;
104 auto id = it->second;
105 auto r = ids_seen.insert(id);
106 cell->attributes.erase(it);
107 if (!r.second)
108 continue;
109 for (auto &c : cell->connections_) {
110 if (c.second.is_fully_const()) continue;
111 if (cell->output(c.first)) {
112 SigBit b = c.second.as_bit();
113 Wire *w = b.wire;
114 w->set_bool_attribute(ID::keep);
115 w->attributes[ID(abc9_scc_id)] = id.as_int();
116 }
117 }
118 }
119
120 module->fixup_ports();
121 }
122
123 void prep_dff(RTLIL::Module *module)
124 {
125 auto design = module->design;
126 log_assert(design);
127
128 SigMap assign_map(module);
129
130 typedef SigSpec clkdomain_t;
131 dict<clkdomain_t, int> clk_to_mergeability;
132
133 for (auto cell : module->cells()) {
134 if (cell->type != "$__ABC9_FF_")
135 continue;
136
137 Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
138 if (abc9_clock_wire == NULL)
139 log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
140 SigSpec abc9_clock = assign_map(abc9_clock_wire);
141
142 clkdomain_t key(abc9_clock);
143
144 auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
145 auto r2 = cell->attributes.insert(ID(abc9_mergeability));;
146 log_assert(r2.second);
147 r2.first->second = r.first->second;
148 }
149
150 RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
151 if (holes_module) {
152 SigMap sigmap(holes_module);
153
154 dict<SigSpec, SigSpec> replace;
155 for (auto cell : holes_module->cells().to_vector()) {
156 if (!cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
157 "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_"))
158 continue;
159 SigBit D = cell->getPort("\\D");
160 SigBit Q = cell->getPort("\\Q");
161 // Emulate async control embedded inside $_DFF_* cell with mux in front of D
162 if (cell->type.in("$_DFF_NN0_", "$_DFF_PN0_"))
163 D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort("\\R"));
164 else if (cell->type.in("$_DFF_NN1_", "$_DFF_PN1_"))
165 D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort("\\R"));
166 else if (cell->type.in("$_DFF_NP0_", "$_DFF_PP0_"))
167 D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort("\\R"));
168 else if (cell->type.in("$_DFF_NP1_", "$_DFF_PP1_"))
169 D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort("\\R"));
170 // Remove the $_DFF_* cell from what needs to be a combinatorial box
171 holes_module->remove(cell);
172 Wire *port;
173 if (GetSize(Q.wire) == 1)
174 port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
175 else
176 port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
177 log_assert(port);
178 // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
179 // in order to extract just the combinatorial control logic that feeds the box
180 // (i.e. clock enable, synchronous reset, etc.)
181 replace.insert(std::make_pair(Q,D));
182 // Since `flatten` above would have created wires named "<cell>.Q",
183 // extract the pre-techmap cell name
184 auto pos = Q.wire->name.str().rfind(".");
185 log_assert(pos != std::string::npos);
186 IdString driver = Q.wire->name.substr(0, pos);
187 // And drive the signal that was previously driven by "DFF.Q" (typically
188 // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
189 // wire (which itself is driven an by input port) we inserted above
190 Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
191 log_assert(currQ);
192 holes_module->connect(Q, currQ);
193 }
194
195 for (auto &conn : holes_module->connections_)
196 conn.second = replace.at(sigmap(conn.second), conn.second);
197 }
198 }
199
200 void prep_xaiger(RTLIL::Module *module, bool dff)
201 {
202 auto design = module->design;
203 log_assert(design);
204
205 SigMap sigmap(module);
206
207 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
208 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
209 dict<IdString, std::vector<IdString>> box_ports;
210
211 for (auto cell : module->cells()) {
212 if (cell->type == "$__ABC9_FF_")
213 continue;
214 if (cell->has_keep_attr())
215 continue;
216
217 auto inst_module = module->design->module(cell->type);
218 bool abc9_flop = inst_module && inst_module->get_bool_attribute("\\abc9_flop");
219 if (abc9_flop && !dff)
220 continue;
221
222 if ((inst_module && inst_module->get_bool_attribute("\\abc9_box")) || abc9_flop) {
223 auto r = box_ports.insert(cell->type);
224 if (r.second) {
225 // Make carry in the last PI, and carry out the last PO
226 // since ABC requires it this way
227 IdString carry_in, carry_out;
228 for (const auto &port_name : inst_module->ports) {
229 auto w = inst_module->wire(port_name);
230 log_assert(w);
231 if (w->get_bool_attribute("\\abc9_carry")) {
232 log_assert(w->port_input != w->port_output);
233 if (w->port_input)
234 carry_in = port_name;
235 else if (w->port_output)
236 carry_out = port_name;
237 }
238 else
239 r.first->second.push_back(port_name);
240 }
241 if (carry_in != IdString()) {
242 r.first->second.push_back(carry_in);
243 r.first->second.push_back(carry_out);
244 }
245 }
246 }
247 else if (!yosys_celltypes.cell_known(cell->type))
248 continue;
249
250 // TODO: Speed up toposort -- we care about box ordering only
251 for (auto conn : cell->connections()) {
252 if (cell->input(conn.first))
253 for (auto bit : sigmap(conn.second))
254 bit_users[bit].insert(cell->name);
255
256 if (cell->output(conn.first) && !abc9_flop)
257 for (auto bit : sigmap(conn.second))
258 bit_drivers[bit].insert(cell->name);
259 }
260 toposort.node(cell->name);
261 }
262
263 if (box_ports.empty())
264 return;
265
266 for (auto &it : bit_users)
267 if (bit_drivers.count(it.first))
268 for (auto driver_cell : bit_drivers.at(it.first))
269 for (auto user_cell : it.second)
270 toposort.edge(driver_cell, user_cell);
271
272 if (ys_debug(1))
273 toposort.analyze_loops = true;
274
275 bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
276
277 if (ys_debug(1)) {
278 unsigned i = 0;
279 for (auto &it : toposort.loops) {
280 log(" loop %d\n", i++);
281 for (auto cell_name : it) {
282 auto cell = module->cell(cell_name);
283 log_assert(cell);
284 log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
285 }
286 }
287 }
288
289 log_assert(no_loops);
290
291 RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
292 log_assert(holes_module);
293 holes_module->set_bool_attribute("\\abc9_holes");
294
295 dict<IdString, Cell*> cell_cache;
296 TimingInfo timing;
297
298 int port_id = 1, box_count = 0;
299 for (auto cell_name : toposort.sorted) {
300 RTLIL::Cell *cell = module->cell(cell_name);
301 log_assert(cell);
302
303 RTLIL::Module* box_module = design->module(cell->type);
304 if (!box_module || (!box_module->get_bool_attribute("\\abc9_box") && !box_module->get_bool_attribute("\\abc9_flop")))
305 continue;
306
307 cell->attributes["\\abc9_box_seq"] = box_count++;
308
309 IdString derived_type = box_module->derive(design, cell->parameters);
310 box_module = design->module(derived_type);
311
312 auto r = cell_cache.insert(derived_type);
313 auto &holes_cell = r.first->second;
314 if (r.second) {
315 if (box_module->has_processes())
316 Pass::call_on_module(design, box_module, "proc");
317
318 if (box_module->get_bool_attribute("\\whitebox")) {
319 holes_cell = holes_module->addCell(cell->name, derived_type);
320
321 if (box_module->has_processes())
322 Pass::call_on_module(design, box_module, "proc");
323
324 int box_inputs = 0;
325 for (auto port_name : box_ports.at(cell->type)) {
326 RTLIL::Wire *w = box_module->wire(port_name);
327 log_assert(w);
328 log_assert(!w->port_input || !w->port_output);
329 auto &conn = holes_cell->connections_[port_name];
330 if (w->port_input) {
331 for (int i = 0; i < GetSize(w); i++) {
332 box_inputs++;
333 RTLIL::Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
334 if (!holes_wire) {
335 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
336 holes_wire->port_input = true;
337 holes_wire->port_id = port_id++;
338 holes_module->ports.push_back(holes_wire->name);
339 }
340 conn.append(holes_wire);
341 }
342 }
343 else if (w->port_output)
344 conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w));
345 }
346
347 // For flops only, create an extra 1-bit input that drives a new wire
348 // called "<cell>.abc9_ff.Q" that is used below
349 if (box_module->get_bool_attribute("\\abc9_flop")) {
350 box_inputs++;
351 Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
352 if (!holes_wire) {
353 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
354 holes_wire->port_input = true;
355 holes_wire->port_id = port_id++;
356 holes_module->ports.push_back(holes_wire->name);
357 }
358 Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
359 holes_module->connect(Q, holes_wire);
360 }
361 }
362 else // box_module is a blackbox
363 log_assert(holes_cell == nullptr);
364 }
365
366 for (auto port_name : box_ports.at(cell->type)) {
367 RTLIL::Wire *w = box_module->wire(port_name);
368 log_assert(w);
369 if (!w->port_output)
370 continue;
371 Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w));
372 holes_wire->port_output = true;
373 holes_wire->port_id = port_id++;
374 holes_module->ports.push_back(holes_wire->name);
375 if (holes_cell) // whitebox
376 holes_module->connect(holes_wire, holes_cell->getPort(port_name));
377 else // blackbox
378 holes_module->connect(holes_wire, Const(State::S0, GetSize(w)));
379 }
380 }
381 }
382
383 void prep_delays(RTLIL::Design *design, bool dff_mode)
384 {
385 TimingInfo timing;
386
387 // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
388 // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
389 pool<Module*> flops;
390 std::vector<Cell*> cells;
391 for (auto module : design->selected_modules()) {
392 if (module->processes.size() > 0) {
393 log("Skipping module %s as it contains processes.\n", log_id(module));
394 continue;
395 }
396
397 for (auto cell : module->cells()) {
398 if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
399 continue;
400
401 RTLIL::Module* inst_module = module->design->module(cell->type);
402 if (!inst_module)
403 continue;
404 if (!inst_module->get_blackbox_attribute())
405 continue;
406 if (inst_module->attributes.count(ID(abc9_box)))
407 continue;
408 IdString derived_type = inst_module->derive(design, cell->parameters);
409 inst_module = design->module(derived_type);
410 log_assert(inst_module);
411
412 if (dff_mode && inst_module->get_bool_attribute(ID(abc9_flop))) {
413 flops.insert(inst_module);
414 continue; // do not add $__ABC9_DELAY boxes to flops
415 // as delays will be captured in the flop box
416 }
417
418 if (!timing.count(derived_type))
419 timing.setup_module(inst_module);
420
421 cells.emplace_back(cell);
422 }
423 }
424
425 // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
426 // with required times
427 for (auto cell : cells) {
428 auto module = cell->module;
429 RTLIL::Module* inst_module = module->design->module(cell->type);
430 log_assert(inst_module);
431 IdString derived_type = inst_module->derive(design, cell->parameters);
432 inst_module = design->module(derived_type);
433 log_assert(inst_module);
434
435 auto &t = timing.at(derived_type).required;
436 for (auto &conn : cell->connections_) {
437 auto port_wire = inst_module->wire(conn.first);
438 if (!port_wire->port_input)
439 continue;
440
441 SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
442 for (int i = 0; i < GetSize(conn.second); i++) {
443 auto d = t.at(SigBit(port_wire,i), 0);
444 if (d == 0)
445 continue;
446
447 #ifndef NDEBUG
448 if (ys_debug(1)) {
449 static std::set<std::tuple<IdString,IdString,int>> seen;
450 if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
451 log_id(cell->type), log_id(conn.first), i, d);
452 }
453 #endif
454 auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
455 box->setPort(ID(I), conn.second[i]);
456 box->setPort(ID(O), O[i]);
457 box->setParam(ID(DELAY), d);
458 conn.second[i] = O[i];
459 }
460 }
461 }
462 }
463
464 void prep_lut(RTLIL::Design *design, int maxlut)
465 {
466 TimingInfo timing;
467
468 std::vector<std::tuple<int, IdString, int, std::vector<int>>> table;
469 for (auto module : design->modules()) {
470 auto it = module->attributes.find(ID(abc9_lut));
471 if (it == module->attributes.end())
472 continue;
473
474 auto &t = timing.setup_module(module);
475
476 TimingInfo::NameBit o;
477 std::vector<int> specify;
478 for (const auto &i : t.comb) {
479 auto &d = i.first.second;
480 if (o == TimingInfo::NameBit())
481 o = d;
482 else if (o != d)
483 log_error("(* abc9_lut *) module '%s' with has more than one output.\n", log_id(module));
484 specify.push_back(i.second);
485 }
486
487 if (maxlut && GetSize(specify) > maxlut)
488 continue;
489 // ABC requires non-decreasing LUT input delays
490 std::sort(specify.begin(), specify.end());
491 table.emplace_back(GetSize(specify), module->name, it->second.as_int(), std::move(specify));
492 }
493 // ABC requires ascending size
494 std::sort(table.begin(), table.end());
495
496 std::stringstream ss;
497 const auto &first = table.front();
498 // If the first entry does not start from a 1-input LUT,
499 // (as ABC requires) crop the first entry to do so
500 for (int i = 1; i < std::get<0>(first); i++) {
501 ss << "# $__ABC9_LUT" << i << std::endl;
502 ss << i << " " << std::get<2>(first);
503 for (int j = 0; j < i; j++)
504 ss << " " << std::get<3>(first)[j];
505 ss << std::endl;
506 }
507 for (const auto &i : table) {
508 ss << "# " << log_id(std::get<1>(i)) << std::endl;
509 ss << std::get<0>(i) << " " << std::get<2>(i);
510 for (const auto &j : std::get<3>(i))
511 ss << " " << j;
512 ss << std::endl;
513 }
514 design->scratchpad_set_string("abc9_ops.lut_library", ss.str());
515 }
516
517 void write_lut(RTLIL::Module *module, const std::string &dst) {
518 std::ofstream ofs(dst);
519 log_assert(ofs.is_open());
520 ofs << module->design->scratchpad_get_string("abc9_ops.lut_library");
521 ofs.close();
522 }
523
524 void prep_box(RTLIL::Design *design, bool dff_mode)
525 {
526 TimingInfo timing;
527
528 std::stringstream ss;
529 int abc9_box_id = 1;
530 for (auto module : design->modules()) {
531 auto it = module->attributes.find(ID(abc9_box_id));
532 if (it == module->attributes.end())
533 continue;
534 abc9_box_id = std::max(abc9_box_id, it->second.as_int());
535 }
536
537 dict<IdString,std::vector<IdString>> box_ports;
538 for (auto module : design->modules()) {
539 auto abc9_flop = module->get_bool_attribute(ID(abc9_flop));
540 if (abc9_flop) {
541 auto r = module->attributes.insert(ID(abc9_box_id));
542 if (!r.second)
543 continue;
544 r.first->second = abc9_box_id++;
545
546 if (dff_mode) {
547 int num_inputs = 0, num_outputs = 0;
548 for (auto port_name : module->ports) {
549 auto wire = module->wire(port_name);
550 log_assert(GetSize(wire) == 1);
551 if (wire->port_input) num_inputs++;
552 if (wire->port_output) num_outputs++;
553 }
554 log_assert(num_outputs == 1);
555
556 ss << log_id(module) << " " << r.first->second.as_int();
557 ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
558 ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
559
560 ss << "#";
561 bool first = true;
562 for (auto port_name : module->ports) {
563 auto wire = module->wire(port_name);
564 if (!wire->port_input)
565 continue;
566 if (first)
567 first = false;
568 else
569 ss << " ";
570 ss << log_id(wire);
571 }
572 ss << " abc9_ff.Q" << std::endl;
573
574 auto &t = timing.setup_module(module).required;
575 first = true;
576 for (auto port_name : module->ports) {
577 auto wire = module->wire(port_name);
578 if (!wire->port_input)
579 continue;
580 if (first)
581 first = false;
582 else
583 ss << " ";
584 log_assert(GetSize(wire) == 1);
585 auto it = t.find(SigBit(wire,0));
586 if (it == t.end())
587 // Assume that no setup time means zero
588 ss << 0;
589 else {
590 ss << it->second;
591
592 #ifndef NDEBUG
593 if (ys_debug(1)) {
594 static std::set<std::pair<IdString,IdString>> seen;
595 if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
596 log_id(port_name), it->second);
597 }
598 #endif
599 }
600
601 }
602 // Last input is 'abc9_ff.Q'
603 ss << " 0" << std::endl << std::endl;
604 continue;
605 }
606 }
607 else {
608 if (!module->attributes.erase(ID(abc9_box)))
609 continue;
610
611 auto r = module->attributes.insert(ID(abc9_box_id));
612 if (!r.second)
613 continue;
614 r.first->second = abc9_box_id++;
615 }
616
617 auto r = box_ports.insert(module->name);
618 if (r.second) {
619 // Make carry in the last PI, and carry out the last PO
620 // since ABC requires it this way
621 IdString carry_in, carry_out;
622 for (const auto &port_name : module->ports) {
623 auto w = module->wire(port_name);
624 log_assert(w);
625 if (w->get_bool_attribute("\\abc9_carry")) {
626 log_assert(w->port_input != w->port_output);
627 if (w->port_input)
628 carry_in = port_name;
629 else if (w->port_output)
630 carry_out = port_name;
631 }
632 else
633 r.first->second.push_back(port_name);
634 }
635
636 if (carry_in != IdString()) {
637 r.first->second.push_back(carry_in);
638 r.first->second.push_back(carry_out);
639 }
640 }
641
642 std::vector<SigBit> inputs;
643 std::vector<SigBit> outputs;
644 for (auto port_name : r.first->second) {
645 auto wire = module->wire(port_name);
646 if (wire->port_input)
647 for (int i = 0; i < GetSize(wire); i++)
648 inputs.emplace_back(wire, i);
649 if (wire->port_output)
650 for (int i = 0; i < GetSize(wire); i++)
651 outputs.emplace_back(wire, i);
652 }
653
654 ss << log_id(module) << " " << module->attributes.at(ID(abc9_box_id)).as_int();
655 ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
656 ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
657
658 bool first = true;
659 ss << "#";
660 for (const auto &i : inputs) {
661 if (first)
662 first = false;
663 else
664 ss << " ";
665 if (GetSize(i.wire) == 1)
666 ss << log_id(i.wire);
667 else
668 ss << log_id(i.wire) << "[" << i.offset << "]";
669 }
670 ss << std::endl;
671
672 auto &t = timing.setup_module(module).comb;
673 if (t.empty())
674 log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
675
676 for (const auto &o : outputs) {
677 first = true;
678 for (const auto &i : inputs) {
679 if (first)
680 first = false;
681 else
682 ss << " ";
683 auto jt = t.find(std::make_pair(i,o));
684 if (jt == t.end())
685 ss << "-";
686 else
687 ss << jt->second;
688 }
689 ss << " # ";
690 if (GetSize(o.wire) == 1)
691 ss << log_id(o.wire);
692 else
693 ss << log_id(o.wire) << "[" << o.offset << "]";
694 ss << std::endl;
695
696 }
697 ss << std::endl;
698 }
699
700 // ABC expects at least one box
701 if (ss.tellp() == 0)
702 ss << "(dummy) 1 0 0 0";
703
704 design->scratchpad_set_string("abc9_ops.box_library", ss.str());
705 }
706
707 void write_box(RTLIL::Module *module, const std::string &dst) {
708 std::ofstream ofs(dst);
709 log_assert(ofs.is_open());
710 ofs << module->design->scratchpad_get_string("abc9_ops.box_library");
711 ofs.close();
712 }
713
714 void reintegrate(RTLIL::Module *module)
715 {
716 auto design = module->design;
717 log_assert(design);
718
719 map_autoidx = autoidx++;
720
721 RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str()));
722 if (mapped_mod == NULL)
723 log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module));
724
725 for (auto w : mapped_mod->wires())
726 module->addWire(remap_name(w->name), GetSize(w));
727
728 dict<IdString,std::vector<IdString>> box_ports;
729
730 for (auto m : design->modules()) {
731 if (!m->attributes.count(ID(abc9_box_id)))
732 continue;
733
734 auto r = box_ports.insert(m->name);
735 if (!r.second)
736 continue;
737
738 // Make carry in the last PI, and carry out the last PO
739 // since ABC requires it this way
740 IdString carry_in, carry_out;
741 for (const auto &port_name : m->ports) {
742 auto w = m->wire(port_name);
743 log_assert(w);
744 if (w->get_bool_attribute("\\abc9_carry")) {
745 log_assert(w->port_input != w->port_output);
746 if (w->port_input)
747 carry_in = port_name;
748 else if (w->port_output)
749 carry_out = port_name;
750 }
751 else
752 r.first->second.push_back(port_name);
753 }
754
755 if (carry_in != IdString()) {
756 r.first->second.push_back(carry_in);
757 r.first->second.push_back(carry_out);
758 }
759 }
760
761 std::vector<Cell*> boxes;
762 for (auto cell : module->cells().to_vector()) {
763 if (cell->has_keep_attr())
764 continue;
765 if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
766 module->remove(cell);
767 else if (cell->attributes.erase("\\abc9_box_seq"))
768 boxes.emplace_back(cell);
769 }
770
771 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
772 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
773 dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
774 dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
775
776 std::map<IdString, int> cell_stats;
777 for (auto mapped_cell : mapped_mod->cells())
778 {
779 // TODO: Speed up toposort -- we care about NOT ordering only
780 toposort.node(mapped_cell->name);
781
782 if (mapped_cell->type == ID($_NOT_)) {
783 RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
784 RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
785 bit_users[a_bit].insert(mapped_cell->name);
786 // Ignore inouts for topo ordering
787 if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output))
788 bit_drivers[y_bit].insert(mapped_cell->name);
789
790 if (!a_bit.wire) {
791 mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
792 RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
793 log_assert(wire);
794 module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
795 }
796 else {
797 RTLIL::Cell* driver_lut = nullptr;
798 // ABC can return NOT gates that drive POs
799 if (!a_bit.wire->port_input) {
800 // If it's not a NOT gate that that comes from a PI directly,
801 // find the driver LUT and clone that to guarantee that we won't
802 // increase the max logic depth
803 // (TODO: Optimise by not cloning unless will increase depth)
804 RTLIL::IdString driver_name;
805 if (GetSize(a_bit.wire) == 1)
806 driver_name = stringf("$lut%s", a_bit.wire->name.c_str());
807 else
808 driver_name = stringf("$lut%s[%d]", a_bit.wire->name.c_str(), a_bit.offset);
809 driver_lut = mapped_mod->cell(driver_name);
810 }
811
812 if (!driver_lut) {
813 // If a driver couldn't be found (could be from PI or box CI)
814 // then implement using a LUT
815 RTLIL::Cell *cell = module->addLut(remap_name(stringf("$lut%s", mapped_cell->name.c_str())),
816 RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
817 RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
818 RTLIL::Const::from_string("01"));
819 bit2sinks[cell->getPort(ID::A)].push_back(cell);
820 cell_stats[ID($lut)]++;
821 }
822 else
823 not2drivers[mapped_cell] = driver_lut;
824 }
825 continue;
826 }
827
828 if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
829 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
830 cell->parameters = mapped_cell->parameters;
831 cell->attributes = mapped_cell->attributes;
832
833 for (auto &mapped_conn : mapped_cell->connections()) {
834 RTLIL::SigSpec newsig;
835 for (auto c : mapped_conn.second.chunks()) {
836 if (c.width == 0)
837 continue;
838 //log_assert(c.width == 1);
839 if (c.wire)
840 c.wire = module->wires_.at(remap_name(c.wire->name));
841 newsig.append(c);
842 }
843 cell->setPort(mapped_conn.first, newsig);
844
845 if (cell->input(mapped_conn.first)) {
846 for (auto i : newsig)
847 bit2sinks[i].push_back(cell);
848 for (auto i : mapped_conn.second)
849 bit_users[i].insert(mapped_cell->name);
850 }
851 if (cell->output(mapped_conn.first))
852 for (auto i : mapped_conn.second)
853 // Ignore inouts for topo ordering
854 if (i.wire && !(i.wire->port_input && i.wire->port_output))
855 bit_drivers[i].insert(mapped_cell->name);
856 }
857 }
858 else {
859 RTLIL::Cell *existing_cell = module->cell(mapped_cell->name);
860 if (!existing_cell)
861 log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell));
862
863 if (existing_cell->type == ID($__ABC9_DELAY)) {
864 SigBit I = mapped_cell->getPort(ID(i));
865 SigBit O = mapped_cell->getPort(ID(o));
866 if (I.wire)
867 I.wire = module->wires_.at(remap_name(I.wire->name));
868 log_assert(O.wire);
869 O.wire = module->wires_.at(remap_name(O.wire->name));
870 module->connect(O, I);
871 continue;
872 }
873
874 RTLIL::Module* box_module = design->module(existing_cell->type);
875 IdString derived_type = box_module->derive(design, existing_cell->parameters);
876 RTLIL::Module* derived_module = design->module(derived_type);
877 log_assert(derived_module);
878 log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at("\\abc9_box_id").as_int()));
879 mapped_cell->type = existing_cell->type;
880
881 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
882 cell->parameters = existing_cell->parameters;
883 cell->attributes = existing_cell->attributes;
884 module->swap_names(cell, existing_cell);
885
886 auto jt = mapped_cell->connections_.find("\\i");
887 log_assert(jt != mapped_cell->connections_.end());
888 SigSpec inputs = std::move(jt->second);
889 mapped_cell->connections_.erase(jt);
890 jt = mapped_cell->connections_.find("\\o");
891 log_assert(jt != mapped_cell->connections_.end());
892 SigSpec outputs = std::move(jt->second);
893 mapped_cell->connections_.erase(jt);
894
895 auto abc9_flop = box_module->attributes.count("\\abc9_flop");
896 if (!abc9_flop) {
897 for (const auto &i : inputs)
898 bit_users[i].insert(mapped_cell->name);
899 for (const auto &i : outputs)
900 // Ignore inouts for topo ordering
901 if (i.wire && !(i.wire->port_input && i.wire->port_output))
902 bit_drivers[i].insert(mapped_cell->name);
903 }
904
905 int input_count = 0, output_count = 0;
906 for (const auto &port_name : box_ports.at(derived_type)) {
907 RTLIL::Wire *w = box_module->wire(port_name);
908 log_assert(w);
909
910 SigSpec sig;
911 if (w->port_input) {
912 sig = inputs.extract(input_count, GetSize(w));
913 input_count += GetSize(w);
914 }
915 if (w->port_output) {
916 sig = outputs.extract(output_count, GetSize(w));
917 output_count += GetSize(w);
918 }
919
920 SigSpec newsig;
921 for (auto c : sig.chunks()) {
922 if (c.width == 0)
923 continue;
924 //log_assert(c.width == 1);
925 if (c.wire)
926 c.wire = module->wires_.at(remap_name(c.wire->name));
927 newsig.append(c);
928 }
929 cell->setPort(port_name, newsig);
930
931 if (w->port_input && !abc9_flop)
932 for (const auto &i : newsig)
933 bit2sinks[i].push_back(cell);
934 }
935 }
936
937 cell_stats[mapped_cell->type]++;
938 }
939
940 for (auto cell : boxes)
941 module->remove(cell);
942
943 // Copy connections (and rename) from mapped_mod to module
944 for (auto conn : mapped_mod->connections()) {
945 if (!conn.first.is_fully_const()) {
946 auto chunks = conn.first.chunks();
947 for (auto &c : chunks)
948 c.wire = module->wires_.at(remap_name(c.wire->name));
949 conn.first = std::move(chunks);
950 }
951 if (!conn.second.is_fully_const()) {
952 auto chunks = conn.second.chunks();
953 for (auto &c : chunks)
954 if (c.wire)
955 c.wire = module->wires_.at(remap_name(c.wire->name));
956 conn.second = std::move(chunks);
957 }
958 module->connect(conn);
959 }
960
961 for (auto &it : cell_stats)
962 log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
963 int in_wires = 0, out_wires = 0;
964
965 // Stitch in mapped_mod's inputs/outputs into module
966 for (auto port : mapped_mod->ports) {
967 RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
968 RTLIL::Wire *wire = module->wire(port);
969 log_assert(wire);
970 if (wire->attributes.erase(ID(abc9_scc_id))) {
971 auto r YS_ATTRIBUTE(unused) = wire->attributes.erase(ID::keep);
972 log_assert(r);
973 }
974 RTLIL::Wire *remap_wire = module->wire(remap_name(port));
975 RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire));
976 log_assert(GetSize(signal) >= GetSize(remap_wire));
977
978 RTLIL::SigSig conn;
979 if (mapped_wire->port_output) {
980 conn.first = signal;
981 conn.second = remap_wire;
982 out_wires++;
983 module->connect(conn);
984 }
985 else if (mapped_wire->port_input) {
986 conn.first = remap_wire;
987 conn.second = signal;
988 in_wires++;
989 module->connect(conn);
990 }
991 }
992
993 // ABC9 will return $_NOT_ gates in its mapping (since they are
994 // treated as being "free"), in particular driving primary
995 // outputs (real primary outputs, or cells treated as blackboxes)
996 // or driving box inputs.
997 // Instead of just mapping those $_NOT_ gates into 2-input $lut-s
998 // at an area and delay cost, see if it is possible to push
999 // this $_NOT_ into the driving LUT, or into all sink LUTs.
1000 // When this is not possible, (i.e. this signal drives two primary
1001 // outputs, only one of which is complemented) and when the driver
1002 // is a LUT, then clone the LUT so that it can be inverted without
1003 // increasing depth/delay.
1004 for (auto &it : bit_users)
1005 if (bit_drivers.count(it.first))
1006 for (auto driver_cell : bit_drivers.at(it.first))
1007 for (auto user_cell : it.second)
1008 toposort.edge(driver_cell, user_cell);
1009 bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
1010 log_assert(no_loops);
1011
1012 for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
1013 RTLIL::Cell *not_cell = mapped_mod->cell(*ii);
1014 log_assert(not_cell);
1015 if (not_cell->type != ID($_NOT_))
1016 continue;
1017 auto it = not2drivers.find(not_cell);
1018 if (it == not2drivers.end())
1019 continue;
1020 RTLIL::Cell *driver_lut = it->second;
1021 RTLIL::SigBit a_bit = not_cell->getPort(ID::A);
1022 RTLIL::SigBit y_bit = not_cell->getPort(ID::Y);
1023 RTLIL::Const driver_mask;
1024
1025 a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
1026 y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name));
1027
1028 auto jt = bit2sinks.find(a_bit);
1029 if (jt == bit2sinks.end())
1030 goto clone_lut;
1031
1032 for (auto sink_cell : jt->second)
1033 if (sink_cell->type != ID($lut))
1034 goto clone_lut;
1035
1036 // Push downstream LUTs past inverter
1037 for (auto sink_cell : jt->second) {
1038 SigSpec A = sink_cell->getPort(ID::A);
1039 RTLIL::Const mask = sink_cell->getParam(ID(LUT));
1040 int index = 0;
1041 for (; index < GetSize(A); index++)
1042 if (A[index] == a_bit)
1043 break;
1044 log_assert(index < GetSize(A));
1045 int i = 0;
1046 while (i < GetSize(mask)) {
1047 for (int j = 0; j < (1 << index); j++)
1048 std::swap(mask[i+j], mask[i+j+(1 << index)]);
1049 i += 1 << (index+1);
1050 }
1051 A[index] = y_bit;
1052 sink_cell->setPort(ID::A, A);
1053 sink_cell->setParam(ID(LUT), mask);
1054 }
1055
1056 // Since we have rewritten all sinks (which we know
1057 // to be only LUTs) to be after the inverter, we can
1058 // go ahead and clone the LUT with the expectation
1059 // that the original driving LUT will become dangling
1060 // and get cleaned away
1061 clone_lut:
1062 driver_mask = driver_lut->getParam(ID(LUT));
1063 for (auto &b : driver_mask.bits) {
1064 if (b == RTLIL::State::S0) b = RTLIL::State::S1;
1065 else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
1066 }
1067 auto cell = module->addLut(NEW_ID,
1068 driver_lut->getPort(ID::A),
1069 y_bit,
1070 driver_mask);
1071 for (auto &bit : cell->connections_.at(ID::A)) {
1072 bit.wire = module->wires_.at(remap_name(bit.wire->name));
1073 bit2sinks[bit].push_back(cell);
1074 }
1075 }
1076
1077 //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
1078 log("ABC RESULTS: input signals: %8d\n", in_wires);
1079 log("ABC RESULTS: output signals: %8d\n", out_wires);
1080
1081 design->remove(mapped_mod);
1082 }
1083
1084 struct Abc9OpsPass : public Pass {
1085 Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
1086 void help() YS_OVERRIDE
1087 {
1088 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1089 log("\n");
1090 log(" abc9_ops [options] [selection]\n");
1091 log("\n");
1092 log("This pass contains a set of supporting operations for use during ABC technology\n");
1093 log("mapping, and is expected to be called in conjunction with other operations from\n");
1094 log("the `abc9' script pass. Only fully-selected modules are supported.\n");
1095 log("\n");
1096 log(" -check\n");
1097 log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
1098 log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
1099 log("\n");
1100 log(" -prep_delays\n");
1101 log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
1102 log(" certain required times.\n");
1103 log("\n");
1104 log(" -mark_scc\n");
1105 log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n");
1106 log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n");
1107 log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n");
1108 log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n");
1109 log("\n");
1110 log(" -prep_xaiger\n");
1111 log(" prepare the design for XAIGER output. this includes computing the\n");
1112 log(" topological ordering of ABC9 boxes, as well as preparing the\n");
1113 log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
1114 log(" whiteboxes.\n");
1115 log("\n");
1116 log(" -dff\n");
1117 log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
1118 log(" during -prep_{delays,xaiger,box}.\n");
1119 log("\n");
1120 log(" -prep_dff\n");
1121 log(" compute the clock domain and initial value of each flop in the design.\n");
1122 log(" process the '$holes' module to support clock-enable functionality.\n");
1123 log("\n");
1124 log(" -prep_lut <maxlut>\n");
1125 log(" pre-compute the lut library by analysing all modules marked with\n");
1126 log(" (* abc9_lut=<area> *).\n");
1127 log("\n");
1128 log(" -write_lut <dst>\n");
1129 log(" write the pre-computed lut library to <dst>.\n");
1130 log("\n");
1131 log(" -prep_box\n");
1132 log(" pre-compute the box library by analysing all modules marked with\n");
1133 log(" (* abc9_box *).\n");
1134 log("\n");
1135 log(" -write_box <dst>\n");
1136 log(" write the pre-computed box library to <dst>.\n");
1137 log("\n");
1138 log(" -reintegrate\n");
1139 log(" for each selected module, re-intergrate the module '<module-name>$abc9'\n");
1140 log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n");
1141 log(" inputs and outputs.\n");
1142 log("\n");
1143 }
1144 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1145 {
1146 log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
1147
1148 bool check_mode = false;
1149 bool prep_delays_mode = false;
1150 bool mark_scc_mode = false;
1151 bool prep_dff_mode = false;
1152 bool prep_xaiger_mode = false;
1153 bool prep_lut_mode = false;
1154 bool prep_box_mode = false;
1155 bool reintegrate_mode = false;
1156 bool dff_mode = false;
1157 std::string write_lut_dst;
1158 int maxlut = 0;
1159 std::string write_box_dst;
1160
1161 size_t argidx;
1162 for (argidx = 1; argidx < args.size(); argidx++) {
1163 std::string arg = args[argidx];
1164 if (arg == "-check") {
1165 check_mode = true;
1166 continue;
1167 }
1168 if (arg == "-mark_scc") {
1169 mark_scc_mode = true;
1170 continue;
1171 }
1172 if (arg == "-prep_dff") {
1173 prep_dff_mode = true;
1174 continue;
1175 }
1176 if (arg == "-prep_xaiger") {
1177 prep_xaiger_mode = true;
1178 continue;
1179 }
1180 if (arg == "-prep_delays") {
1181 prep_delays_mode = true;
1182 continue;
1183 }
1184 if (arg == "-prep_lut" && argidx+1 < args.size()) {
1185 prep_lut_mode = true;
1186 maxlut = atoi(args[++argidx].c_str());
1187 continue;
1188 }
1189 if (arg == "-maxlut" && argidx+1 < args.size()) {
1190 continue;
1191 }
1192 if (arg == "-write_lut" && argidx+1 < args.size()) {
1193 write_lut_dst = args[++argidx];
1194 rewrite_filename(write_lut_dst);
1195 continue;
1196 }
1197 if (arg == "-prep_box") {
1198 prep_box_mode = true;
1199 continue;
1200 }
1201 if (arg == "-write_box" && argidx+1 < args.size()) {
1202 write_box_dst = args[++argidx];
1203 rewrite_filename(write_box_dst);
1204 continue;
1205 }
1206 if (arg == "-reintegrate") {
1207 reintegrate_mode = true;
1208 continue;
1209 }
1210 if (arg == "-dff") {
1211 dff_mode = true;
1212 continue;
1213 }
1214 break;
1215 }
1216 extra_args(args, argidx, design);
1217
1218 if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
1219 log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
1220
1221 if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
1222 log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
1223
1224 if (check_mode)
1225 check(design);
1226 if (prep_delays_mode)
1227 prep_delays(design, dff_mode);
1228 if (prep_lut_mode)
1229 prep_lut(design, maxlut);
1230 if (prep_box_mode)
1231 prep_box(design, dff_mode);
1232
1233 for (auto mod : design->selected_modules()) {
1234 if (mod->get_bool_attribute("\\abc9_holes"))
1235 continue;
1236
1237 if (mod->processes.size() > 0) {
1238 log("Skipping module %s as it contains processes.\n", log_id(mod));
1239 continue;
1240 }
1241
1242 if (!design->selected_whole_module(mod))
1243 log_error("Can't handle partially selected module %s!\n", log_id(mod));
1244
1245 if (!write_lut_dst.empty())
1246 write_lut(mod, write_lut_dst);
1247 if (!write_box_dst.empty())
1248 write_box(mod, write_box_dst);
1249 if (mark_scc_mode)
1250 mark_scc(mod);
1251 if (prep_dff_mode)
1252 prep_dff(mod);
1253 if (prep_xaiger_mode)
1254 prep_xaiger(mod, dff_mode);
1255 if (reintegrate_mode)
1256 reintegrate(mod);
1257 }
1258 }
1259 } Abc9OpsPass;
1260
1261 PRIVATE_NAMESPACE_END