abc9_ops: use TimingInfo for -prep_{lut,box} too
[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
297 int port_id = 1, box_count = 0;
298 for (auto cell_name : toposort.sorted) {
299 RTLIL::Cell *cell = module->cell(cell_name);
300 log_assert(cell);
301
302 RTLIL::Module* box_module = design->module(cell->type);
303 if (!box_module || (!box_module->get_bool_attribute("\\abc9_box") && !box_module->get_bool_attribute("\\abc9_flop")))
304 continue;
305
306 cell->attributes["\\abc9_box_seq"] = box_count++;
307
308 IdString derived_type = box_module->derive(design, cell->parameters);
309 box_module = design->module(derived_type);
310
311 auto r = cell_cache.insert(derived_type);
312 auto &holes_cell = r.first->second;
313 if (r.second) {
314 if (box_module->has_processes())
315 Pass::call_on_module(design, box_module, "proc");
316
317 if (box_module->get_bool_attribute("\\whitebox")) {
318 holes_cell = holes_module->addCell(cell->name, derived_type);
319
320 if (box_module->has_processes())
321 Pass::call_on_module(design, box_module, "proc");
322
323 int box_inputs = 0;
324 for (auto port_name : box_ports.at(cell->type)) {
325 RTLIL::Wire *w = box_module->wire(port_name);
326 log_assert(w);
327 log_assert(!w->port_input || !w->port_output);
328 auto &conn = holes_cell->connections_[port_name];
329 if (w->port_input) {
330 for (int i = 0; i < GetSize(w); i++) {
331 box_inputs++;
332 RTLIL::Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
333 if (!holes_wire) {
334 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
335 holes_wire->port_input = true;
336 holes_wire->port_id = port_id++;
337 holes_module->ports.push_back(holes_wire->name);
338 }
339 conn.append(holes_wire);
340 }
341 }
342 else if (w->port_output)
343 conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w));
344 }
345
346 // For flops only, create an extra 1-bit input that drives a new wire
347 // called "<cell>.abc9_ff.Q" that is used below
348 if (box_module->get_bool_attribute("\\abc9_flop")) {
349 box_inputs++;
350 Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
351 if (!holes_wire) {
352 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
353 holes_wire->port_input = true;
354 holes_wire->port_id = port_id++;
355 holes_module->ports.push_back(holes_wire->name);
356 }
357 Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
358 holes_module->connect(Q, holes_wire);
359 }
360 }
361 else // box_module is a blackbox
362 log_assert(holes_cell == nullptr);
363 }
364
365 for (auto port_name : box_ports.at(cell->type)) {
366 RTLIL::Wire *w = box_module->wire(port_name);
367 log_assert(w);
368 if (!w->port_output)
369 continue;
370 Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w));
371 holes_wire->port_output = true;
372 holes_wire->port_id = port_id++;
373 holes_module->ports.push_back(holes_wire->name);
374 if (holes_cell) // whitebox
375 holes_module->connect(holes_wire, holes_cell->getPort(port_name));
376 else // blackbox
377 holes_module->connect(holes_wire, Const(State::S0, GetSize(w)));
378 }
379 }
380 }
381
382 void prep_delays(RTLIL::Design *design, bool dff_mode)
383 {
384 // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
385 // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
386 pool<Module*> flops;
387 std::vector<Cell*> cells;
388 for (auto module : design->selected_modules()) {
389 if (module->processes.size() > 0) {
390 log("Skipping module %s as it contains processes.\n", log_id(module));
391 continue;
392 }
393
394 for (auto cell : module->cells()) {
395 if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
396 continue;
397
398 RTLIL::Module* inst_module = module->design->module(cell->type);
399 if (!inst_module)
400 continue;
401 if (!inst_module->get_blackbox_attribute())
402 continue;
403 if (inst_module->attributes.count(ID(abc9_box)))
404 continue;
405 IdString blackboxes_type = inst_module->derive(design, cell->parameters);
406 inst_module = design->module(blackboxes_type);
407 log_assert(inst_module);
408
409 if (dff_mode && inst_module->get_bool_attribute(ID(abc9_flop))) {
410 flops.insert(inst_module);
411 continue; // do not add $__ABC9_DELAY boxes to flops
412 // as delays will be captured in the flop box
413 }
414
415 cells.emplace_back(cell);
416 }
417 }
418
419 const TimingInfo timing(design);
420
421 // Transform all $specify3 and $specrule to abc9_{arrival,required} attributes
422 // TODO: Deprecate
423 pool<Wire*> ports;
424 std::stringstream ss;
425 for (auto module : design->modules()) {
426
427 auto it = timing.find(module->name);
428 if (it == timing.end())
429 continue;
430
431 const auto &t = it->second;
432 if (t.arrival.empty() && t.required.empty())
433 continue;
434
435 const auto &arrival = t.arrival;
436 const auto &required = t.required;
437
438 ports.clear();
439 for (const auto &i : arrival)
440 ports.insert(i.first.wire);
441 for (auto wire : ports) {
442 log_assert(wire->port_output);
443 ss.str("");
444 if (GetSize(wire) == 1)
445 wire->attributes[ID(abc9_arrival)] = arrival.at(SigBit(wire,0));
446 else {
447 bool first = true;
448 for (auto b : SigSpec(wire)) {
449 if (first)
450 first = false;
451 else
452 ss << " ";
453 ss << arrival.at(b, 0);
454 }
455 wire->attributes[ID(abc9_arrival)] = ss.str();
456 }
457 }
458
459 ports.clear();
460 for (const auto &i : required)
461 ports.insert(i.first.wire);
462 for (auto wire : ports) {
463 log_assert(wire->port_input);
464 ss.str("");
465 if (GetSize(wire) == 1)
466 wire->attributes[ID(abc9_required)] = required.at(SigBit(wire,0));
467 else {
468 bool first = true;
469 for (auto b : SigSpec(wire)) {
470 if (first)
471 first = false;
472 else
473 ss << " ";
474 ss << required.at(b, 0);
475 }
476 wire->attributes[ID(abc9_required)] = ss.str();
477 }
478 }
479 }
480
481 // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
482 // with (* abc9_required *) attributes
483 dict<IdString,dict<IdString,std::vector<int>>> requireds_cache;
484 for (auto cell : cells) {
485 auto module = cell->module;
486 RTLIL::Module* inst_module = module->design->module(cell->type);
487 log_assert(inst_module);
488 IdString derived_type = inst_module->derive(design, cell->parameters);
489 inst_module = design->module(derived_type);
490 log_assert(inst_module);
491
492 auto &cell_requireds = requireds_cache[derived_type];
493 for (auto &conn : cell->connections_) {
494 auto port_wire = inst_module->wire(conn.first);
495 if (!port_wire->port_input)
496 continue;
497
498 auto r = cell_requireds.insert(conn.first);
499 auto &requireds = r.first->second;
500 if (r.second) {
501 auto it = port_wire->attributes.find("\\abc9_required");
502 if (it == port_wire->attributes.end())
503 continue;
504 if (it->second.flags == 0) {
505 int delay = it->second.as_int();
506 requireds.emplace_back(delay);
507 }
508 else
509 for (const auto &tok : split_tokens(it->second.decode_string())) {
510 int delay = atoi(tok.c_str());
511 requireds.push_back(delay);
512 }
513 }
514
515 if (requireds.empty())
516 continue;
517
518 SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
519 auto it = requireds.begin();
520 for (int i = 0; i < GetSize(conn.second); ++i) {
521 #ifndef NDEBUG
522 if (ys_debug(1)) {
523 static std::set<std::pair<IdString,IdString>> seen;
524 if (seen.emplace(derived_type, conn.first).second) log("%s.%s abc9_required = '%s'\n", log_id(cell->type), log_id(conn.first),
525 port_wire->attributes.at("\\abc9_required").decode_string().c_str());
526 }
527 #endif
528 auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
529 box->setPort(ID(I), conn.second[i]);
530 box->setPort(ID(O), O[i]);
531 box->setParam(ID(DELAY), *it);
532 if (requireds.size() > 1)
533 it++;
534 conn.second[i] = O[i];
535 }
536 }
537 }
538 }
539
540 void prep_lut(RTLIL::Design *design, int maxlut)
541 {
542 const TimingInfo timing(design);
543
544 std::vector<std::tuple<int, IdString, int, std::vector<int>>> table;
545 for (auto module : design->modules()) {
546 auto it = module->attributes.find(ID(abc9_lut));
547 if (it == module->attributes.end())
548 continue;
549
550 auto jt = timing.find(module->name);
551 if (jt == timing.end())
552 continue;
553
554 SigBit o;
555 std::vector<int> specify;
556 auto &t = jt->second;
557 for (const auto &i : t.comb) {
558 auto &d = i.first.second;
559 log_dump(o, d);
560 if (o == SigBit())
561 o = d;
562 else if (o != d)
563 log_error("(* abc9_lut *) module '%s' with has more than one output.\n", log_id(module));
564 specify.push_back(i.second);
565 }
566
567 if (maxlut && GetSize(specify) > maxlut)
568 continue;
569 // ABC requires non-decreasing LUT input delays
570 std::sort(specify.begin(), specify.end());
571 table.emplace_back(GetSize(specify), module->name, it->second.as_int(), std::move(specify));
572 }
573 // ABC requires ascending size
574 std::sort(table.begin(), table.end());
575
576 std::stringstream ss;
577 const auto &first = table.front();
578 // If the first entry does not start from a 1-input LUT,
579 // (as ABC requires) crop the first entry to do so
580 for (int i = 1; i < std::get<0>(first); i++) {
581 ss << "# $__ABC9_LUT" << i << std::endl;
582 ss << i << " " << std::get<2>(first);
583 for (int j = 0; j < i; j++)
584 ss << " " << std::get<3>(first)[j];
585 ss << std::endl;
586 }
587 for (const auto &i : table) {
588 ss << "# " << log_id(std::get<1>(i)) << std::endl;
589 ss << std::get<0>(i) << " " << std::get<2>(i);
590 for (const auto &j : std::get<3>(i))
591 ss << " " << j;
592 ss << std::endl;
593 }
594 design->scratchpad_set_string("abc9_ops.lut_library", ss.str());
595 }
596
597 void write_lut(RTLIL::Module *module, const std::string &dst) {
598 std::ofstream ofs(dst);
599 log_assert(ofs.is_open());
600 ofs << module->design->scratchpad_get_string("abc9_ops.lut_library");
601 ofs.close();
602 }
603
604 void prep_box(RTLIL::Design *design, bool dff_mode)
605 {
606 const TimingInfo timing(design);
607
608 std::stringstream ss;
609 int abc9_box_id = 1;
610 for (auto module : design->modules()) {
611 auto it = module->attributes.find(ID(abc9_box_id));
612 if (it == module->attributes.end())
613 continue;
614 abc9_box_id = std::max(abc9_box_id, it->second.as_int());
615 }
616
617 dict<IdString,std::vector<IdString>> box_ports;
618 for (auto module : design->modules()) {
619 auto abc9_flop = module->get_bool_attribute(ID(abc9_flop));
620 if (abc9_flop) {
621 auto r = module->attributes.insert(ID(abc9_box_id));
622 if (!r.second)
623 continue;
624 r.first->second = abc9_box_id++;
625
626 if (dff_mode) {
627 int num_inputs = 0, num_outputs = 0;
628 for (auto port_name : module->ports) {
629 auto wire = module->wire(port_name);
630 log_assert(GetSize(wire) == 1);
631 if (wire->port_input) num_inputs++;
632 if (wire->port_output) num_outputs++;
633 }
634 log_assert(num_outputs == 1);
635
636 ss << log_id(module) << " " << r.first->second.as_int();
637 ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
638 ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
639
640 ss << "#";
641 bool first = true;
642 for (auto port_name : module->ports) {
643 auto wire = module->wire(port_name);
644 if (!wire->port_input)
645 continue;
646 if (first)
647 first = false;
648 else
649 ss << " ";
650 ss << log_id(wire);
651 }
652 ss << " abc9_ff.Q" << std::endl;
653
654 first = true;
655 for (auto port_name : module->ports) {
656 auto wire = module->wire(port_name);
657 if (!wire->port_input)
658 continue;
659 if (first)
660 first = false;
661 else
662 ss << " ";
663 auto it = wire->attributes.find("\\abc9_required");
664 if (it == wire->attributes.end())
665 ss << 0;
666 else {
667 log_assert(it->second.flags == 0);
668 ss << it->second.as_int();
669
670 #ifndef NDEBUG
671 if (ys_debug(1)) {
672 static std::set<std::pair<IdString,IdString>> seen;
673 if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
674 log_id(port_name), it->second.as_int());
675 }
676 #endif
677 }
678
679 }
680 // Last input is 'abc9_ff.Q'
681 ss << " 0" << std::endl << std::endl;
682 continue;
683 }
684 }
685 else {
686 if (!module->attributes.erase(ID(abc9_box)))
687 continue;
688
689 auto r = module->attributes.insert(ID(abc9_box_id));
690 if (!r.second)
691 continue;
692 r.first->second = abc9_box_id++;
693 }
694
695 auto r = box_ports.insert(module->name);
696 if (r.second) {
697 // Make carry in the last PI, and carry out the last PO
698 // since ABC requires it this way
699 IdString carry_in, carry_out;
700 for (const auto &port_name : module->ports) {
701 auto w = module->wire(port_name);
702 log_assert(w);
703 if (w->get_bool_attribute("\\abc9_carry")) {
704 log_assert(w->port_input != w->port_output);
705 if (w->port_input)
706 carry_in = port_name;
707 else if (w->port_output)
708 carry_out = port_name;
709 }
710 else
711 r.first->second.push_back(port_name);
712 }
713
714 if (carry_in != IdString()) {
715 r.first->second.push_back(carry_in);
716 r.first->second.push_back(carry_out);
717 }
718 }
719
720 std::vector<SigBit> inputs;
721 std::vector<SigBit> outputs;
722 for (auto port_name : r.first->second) {
723 auto wire = module->wire(port_name);
724 if (wire->port_input)
725 for (int i = 0; i < GetSize(wire); i++)
726 inputs.emplace_back(wire, i);
727 if (wire->port_output)
728 for (int i = 0; i < GetSize(wire); i++)
729 outputs.emplace_back(wire, i);
730 }
731
732 ss << log_id(module) << " " << module->attributes.at(ID(abc9_box_id)).as_int();
733 ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
734 ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
735
736 bool first = true;
737 ss << "#";
738 for (const auto &i : inputs) {
739 if (first)
740 first = false;
741 else
742 ss << " ";
743 if (GetSize(i.wire) == 1)
744 ss << log_id(i.wire);
745 else
746 ss << log_id(i.wire) << "[" << i.offset << "]";
747 }
748 ss << std::endl;
749
750 auto it = timing.find(module->name);
751 if (it == timing.end())
752 log_error("(* abc9_box *) module '%s' has no timing information.\n", log_id(module));
753
754 const auto &t = it->second.comb;
755 for (const auto &o : outputs) {
756 first = true;
757 for (const auto &i : inputs) {
758 if (first)
759 first = false;
760 else
761 ss << " ";
762 auto jt = t.find(std::make_pair(i,o));
763 if (jt == t.end())
764 ss << "-";
765 else
766 ss << jt->second;
767 }
768 ss << " # ";
769 if (GetSize(o.wire) == 1)
770 ss << log_id(o.wire);
771 else
772 ss << log_id(o.wire) << "[" << o.offset << "]";
773 ss << std::endl;
774
775 }
776 ss << std::endl;
777 }
778
779 // ABC expects at least one box
780 if (ss.tellp() == 0)
781 ss << "(dummy) 1 0 0 0";
782
783 design->scratchpad_set_string("abc9_ops.box_library", ss.str());
784 }
785
786 void write_box(RTLIL::Module *module, const std::string &dst) {
787 std::ofstream ofs(dst);
788 log_assert(ofs.is_open());
789 ofs << module->design->scratchpad_get_string("abc9_ops.box_library");
790 ofs.close();
791 }
792
793 void reintegrate(RTLIL::Module *module)
794 {
795 auto design = module->design;
796 log_assert(design);
797
798 map_autoidx = autoidx++;
799
800 RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str()));
801 if (mapped_mod == NULL)
802 log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module));
803
804 for (auto w : mapped_mod->wires())
805 module->addWire(remap_name(w->name), GetSize(w));
806
807 dict<IdString,std::vector<IdString>> box_ports;
808
809 for (auto m : design->modules()) {
810 if (!m->attributes.count(ID(abc9_box_id)))
811 continue;
812
813 auto r = box_ports.insert(m->name);
814 if (!r.second)
815 continue;
816
817 // Make carry in the last PI, and carry out the last PO
818 // since ABC requires it this way
819 IdString carry_in, carry_out;
820 for (const auto &port_name : m->ports) {
821 auto w = m->wire(port_name);
822 log_assert(w);
823 if (w->get_bool_attribute("\\abc9_carry")) {
824 log_assert(w->port_input != w->port_output);
825 if (w->port_input)
826 carry_in = port_name;
827 else if (w->port_output)
828 carry_out = port_name;
829 }
830 else
831 r.first->second.push_back(port_name);
832 }
833
834 if (carry_in != IdString()) {
835 r.first->second.push_back(carry_in);
836 r.first->second.push_back(carry_out);
837 }
838 }
839
840 std::vector<Cell*> boxes;
841 for (auto cell : module->cells().to_vector()) {
842 if (cell->has_keep_attr())
843 continue;
844 if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
845 module->remove(cell);
846 else if (cell->attributes.erase("\\abc9_box_seq"))
847 boxes.emplace_back(cell);
848 }
849
850 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
851 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
852 dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
853 dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
854
855 std::map<IdString, int> cell_stats;
856 for (auto mapped_cell : mapped_mod->cells())
857 {
858 // TODO: Speed up toposort -- we care about NOT ordering only
859 toposort.node(mapped_cell->name);
860
861 if (mapped_cell->type == ID($_NOT_)) {
862 RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
863 RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
864 bit_users[a_bit].insert(mapped_cell->name);
865 // Ignore inouts for topo ordering
866 if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output))
867 bit_drivers[y_bit].insert(mapped_cell->name);
868
869 if (!a_bit.wire) {
870 mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
871 RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
872 log_assert(wire);
873 module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
874 }
875 else {
876 RTLIL::Cell* driver_lut = nullptr;
877 // ABC can return NOT gates that drive POs
878 if (!a_bit.wire->port_input) {
879 // If it's not a NOT gate that that comes from a PI directly,
880 // find the driver LUT and clone that to guarantee that we won't
881 // increase the max logic depth
882 // (TODO: Optimise by not cloning unless will increase depth)
883 RTLIL::IdString driver_name;
884 if (GetSize(a_bit.wire) == 1)
885 driver_name = stringf("$lut%s", a_bit.wire->name.c_str());
886 else
887 driver_name = stringf("$lut%s[%d]", a_bit.wire->name.c_str(), a_bit.offset);
888 driver_lut = mapped_mod->cell(driver_name);
889 }
890
891 if (!driver_lut) {
892 // If a driver couldn't be found (could be from PI or box CI)
893 // then implement using a LUT
894 RTLIL::Cell *cell = module->addLut(remap_name(stringf("$lut%s", mapped_cell->name.c_str())),
895 RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
896 RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
897 RTLIL::Const::from_string("01"));
898 bit2sinks[cell->getPort(ID::A)].push_back(cell);
899 cell_stats[ID($lut)]++;
900 }
901 else
902 not2drivers[mapped_cell] = driver_lut;
903 }
904 continue;
905 }
906
907 if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
908 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
909 cell->parameters = mapped_cell->parameters;
910 cell->attributes = mapped_cell->attributes;
911
912 for (auto &mapped_conn : mapped_cell->connections()) {
913 RTLIL::SigSpec newsig;
914 for (auto c : mapped_conn.second.chunks()) {
915 if (c.width == 0)
916 continue;
917 //log_assert(c.width == 1);
918 if (c.wire)
919 c.wire = module->wires_.at(remap_name(c.wire->name));
920 newsig.append(c);
921 }
922 cell->setPort(mapped_conn.first, newsig);
923
924 if (cell->input(mapped_conn.first)) {
925 for (auto i : newsig)
926 bit2sinks[i].push_back(cell);
927 for (auto i : mapped_conn.second)
928 bit_users[i].insert(mapped_cell->name);
929 }
930 if (cell->output(mapped_conn.first))
931 for (auto i : mapped_conn.second)
932 // Ignore inouts for topo ordering
933 if (i.wire && !(i.wire->port_input && i.wire->port_output))
934 bit_drivers[i].insert(mapped_cell->name);
935 }
936 }
937 else {
938 RTLIL::Cell *existing_cell = module->cell(mapped_cell->name);
939 if (!existing_cell)
940 log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell));
941
942 if (existing_cell->type == ID($__ABC9_DELAY)) {
943 SigBit I = mapped_cell->getPort(ID(i));
944 SigBit O = mapped_cell->getPort(ID(o));
945 if (I.wire)
946 I.wire = module->wires_.at(remap_name(I.wire->name));
947 log_assert(O.wire);
948 O.wire = module->wires_.at(remap_name(O.wire->name));
949 module->connect(O, I);
950 continue;
951 }
952
953 RTLIL::Module* box_module = design->module(existing_cell->type);
954 IdString derived_type = box_module->derive(design, existing_cell->parameters);
955 RTLIL::Module* derived_module = design->module(derived_type);
956 log_assert(derived_module);
957 log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at("\\abc9_box_id").as_int()));
958 mapped_cell->type = existing_cell->type;
959
960 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
961 cell->parameters = existing_cell->parameters;
962 cell->attributes = existing_cell->attributes;
963 module->swap_names(cell, existing_cell);
964
965 auto jt = mapped_cell->connections_.find("\\i");
966 log_assert(jt != mapped_cell->connections_.end());
967 SigSpec inputs = std::move(jt->second);
968 mapped_cell->connections_.erase(jt);
969 jt = mapped_cell->connections_.find("\\o");
970 log_assert(jt != mapped_cell->connections_.end());
971 SigSpec outputs = std::move(jt->second);
972 mapped_cell->connections_.erase(jt);
973
974 auto abc9_flop = box_module->attributes.count("\\abc9_flop");
975 if (!abc9_flop) {
976 for (const auto &i : inputs)
977 bit_users[i].insert(mapped_cell->name);
978 for (const auto &i : outputs)
979 // Ignore inouts for topo ordering
980 if (i.wire && !(i.wire->port_input && i.wire->port_output))
981 bit_drivers[i].insert(mapped_cell->name);
982 }
983
984 int input_count = 0, output_count = 0;
985 for (const auto &port_name : box_ports.at(derived_type)) {
986 RTLIL::Wire *w = box_module->wire(port_name);
987 log_assert(w);
988
989 SigSpec sig;
990 if (w->port_input) {
991 sig = inputs.extract(input_count, GetSize(w));
992 input_count += GetSize(w);
993 }
994 if (w->port_output) {
995 sig = outputs.extract(output_count, GetSize(w));
996 output_count += GetSize(w);
997 }
998
999 SigSpec newsig;
1000 for (auto c : sig.chunks()) {
1001 if (c.width == 0)
1002 continue;
1003 //log_assert(c.width == 1);
1004 if (c.wire)
1005 c.wire = module->wires_.at(remap_name(c.wire->name));
1006 newsig.append(c);
1007 }
1008 cell->setPort(port_name, newsig);
1009
1010 if (w->port_input && !abc9_flop)
1011 for (const auto &i : newsig)
1012 bit2sinks[i].push_back(cell);
1013 }
1014 }
1015
1016 cell_stats[mapped_cell->type]++;
1017 }
1018
1019 for (auto cell : boxes)
1020 module->remove(cell);
1021
1022 // Copy connections (and rename) from mapped_mod to module
1023 for (auto conn : mapped_mod->connections()) {
1024 if (!conn.first.is_fully_const()) {
1025 auto chunks = conn.first.chunks();
1026 for (auto &c : chunks)
1027 c.wire = module->wires_.at(remap_name(c.wire->name));
1028 conn.first = std::move(chunks);
1029 }
1030 if (!conn.second.is_fully_const()) {
1031 auto chunks = conn.second.chunks();
1032 for (auto &c : chunks)
1033 if (c.wire)
1034 c.wire = module->wires_.at(remap_name(c.wire->name));
1035 conn.second = std::move(chunks);
1036 }
1037 module->connect(conn);
1038 }
1039
1040 for (auto &it : cell_stats)
1041 log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
1042 int in_wires = 0, out_wires = 0;
1043
1044 // Stitch in mapped_mod's inputs/outputs into module
1045 for (auto port : mapped_mod->ports) {
1046 RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
1047 RTLIL::Wire *wire = module->wire(port);
1048 log_assert(wire);
1049 if (wire->attributes.erase(ID(abc9_scc_id))) {
1050 auto r YS_ATTRIBUTE(unused) = wire->attributes.erase(ID::keep);
1051 log_assert(r);
1052 }
1053 RTLIL::Wire *remap_wire = module->wire(remap_name(port));
1054 RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire));
1055 log_assert(GetSize(signal) >= GetSize(remap_wire));
1056
1057 RTLIL::SigSig conn;
1058 if (mapped_wire->port_output) {
1059 conn.first = signal;
1060 conn.second = remap_wire;
1061 out_wires++;
1062 module->connect(conn);
1063 }
1064 else if (mapped_wire->port_input) {
1065 conn.first = remap_wire;
1066 conn.second = signal;
1067 in_wires++;
1068 module->connect(conn);
1069 }
1070 }
1071
1072 // ABC9 will return $_NOT_ gates in its mapping (since they are
1073 // treated as being "free"), in particular driving primary
1074 // outputs (real primary outputs, or cells treated as blackboxes)
1075 // or driving box inputs.
1076 // Instead of just mapping those $_NOT_ gates into 2-input $lut-s
1077 // at an area and delay cost, see if it is possible to push
1078 // this $_NOT_ into the driving LUT, or into all sink LUTs.
1079 // When this is not possible, (i.e. this signal drives two primary
1080 // outputs, only one of which is complemented) and when the driver
1081 // is a LUT, then clone the LUT so that it can be inverted without
1082 // increasing depth/delay.
1083 for (auto &it : bit_users)
1084 if (bit_drivers.count(it.first))
1085 for (auto driver_cell : bit_drivers.at(it.first))
1086 for (auto user_cell : it.second)
1087 toposort.edge(driver_cell, user_cell);
1088 bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
1089 log_assert(no_loops);
1090
1091 for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
1092 RTLIL::Cell *not_cell = mapped_mod->cell(*ii);
1093 log_assert(not_cell);
1094 if (not_cell->type != ID($_NOT_))
1095 continue;
1096 auto it = not2drivers.find(not_cell);
1097 if (it == not2drivers.end())
1098 continue;
1099 RTLIL::Cell *driver_lut = it->second;
1100 RTLIL::SigBit a_bit = not_cell->getPort(ID::A);
1101 RTLIL::SigBit y_bit = not_cell->getPort(ID::Y);
1102 RTLIL::Const driver_mask;
1103
1104 a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
1105 y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name));
1106
1107 auto jt = bit2sinks.find(a_bit);
1108 if (jt == bit2sinks.end())
1109 goto clone_lut;
1110
1111 for (auto sink_cell : jt->second)
1112 if (sink_cell->type != ID($lut))
1113 goto clone_lut;
1114
1115 // Push downstream LUTs past inverter
1116 for (auto sink_cell : jt->second) {
1117 SigSpec A = sink_cell->getPort(ID::A);
1118 RTLIL::Const mask = sink_cell->getParam(ID(LUT));
1119 int index = 0;
1120 for (; index < GetSize(A); index++)
1121 if (A[index] == a_bit)
1122 break;
1123 log_assert(index < GetSize(A));
1124 int i = 0;
1125 while (i < GetSize(mask)) {
1126 for (int j = 0; j < (1 << index); j++)
1127 std::swap(mask[i+j], mask[i+j+(1 << index)]);
1128 i += 1 << (index+1);
1129 }
1130 A[index] = y_bit;
1131 sink_cell->setPort(ID::A, A);
1132 sink_cell->setParam(ID(LUT), mask);
1133 }
1134
1135 // Since we have rewritten all sinks (which we know
1136 // to be only LUTs) to be after the inverter, we can
1137 // go ahead and clone the LUT with the expectation
1138 // that the original driving LUT will become dangling
1139 // and get cleaned away
1140 clone_lut:
1141 driver_mask = driver_lut->getParam(ID(LUT));
1142 for (auto &b : driver_mask.bits) {
1143 if (b == RTLIL::State::S0) b = RTLIL::State::S1;
1144 else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
1145 }
1146 auto cell = module->addLut(NEW_ID,
1147 driver_lut->getPort(ID::A),
1148 y_bit,
1149 driver_mask);
1150 for (auto &bit : cell->connections_.at(ID::A)) {
1151 bit.wire = module->wires_.at(remap_name(bit.wire->name));
1152 bit2sinks[bit].push_back(cell);
1153 }
1154 }
1155
1156 //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
1157 log("ABC RESULTS: input signals: %8d\n", in_wires);
1158 log("ABC RESULTS: output signals: %8d\n", out_wires);
1159
1160 design->remove(mapped_mod);
1161 }
1162
1163 struct Abc9OpsPass : public Pass {
1164 Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
1165 void help() YS_OVERRIDE
1166 {
1167 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1168 log("\n");
1169 log(" abc9_ops [options] [selection]\n");
1170 log("\n");
1171 log("This pass contains a set of supporting operations for use during ABC technology\n");
1172 log("mapping, and is expected to be called in conjunction with other operations from\n");
1173 log("the `abc9' script pass. Only fully-selected modules are supported.\n");
1174 log("\n");
1175 log(" -check\n");
1176 log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
1177 log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
1178 log("\n");
1179 log(" -prep_delays\n");
1180 log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
1181 log(" certain delays, e.g. (* abc9_required *) values.\n");
1182 log("\n");
1183 log(" -mark_scc\n");
1184 log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n");
1185 log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n");
1186 log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n");
1187 log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n");
1188 log("\n");
1189 log(" -prep_xaiger\n");
1190 log(" prepare the design for XAIGER output. this includes computing the\n");
1191 log(" topological ordering of ABC9 boxes, as well as preparing the\n");
1192 log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
1193 log(" whiteboxes.\n");
1194 log("\n");
1195 log(" -dff\n");
1196 log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
1197 log(" during -prep_{delays,xaiger,box}.\n");
1198 log("\n");
1199 log(" -prep_dff\n");
1200 log(" compute the clock domain and initial value of each flop in the design.\n");
1201 log(" process the '$holes' module to support clock-enable functionality.\n");
1202 log("\n");
1203 log(" -prep_lut <maxlut>\n");
1204 log(" pre-compute the lut library by analysing all modules marked with\n");
1205 log(" (* abc9_lut=<area> *).\n");
1206 log("\n");
1207 log(" -write_lut <dst>\n");
1208 log(" write the pre-computed lut library to <dst>.\n");
1209 log("\n");
1210 log(" -prep_box\n");
1211 log(" pre-compute the box library by analysing all modules marked with\n");
1212 log(" (* abc9_box *).\n");
1213 log("\n");
1214 log(" -write_box <dst>\n");
1215 log(" write the pre-computed box library to <dst>.\n");
1216 log("\n");
1217 log(" -reintegrate\n");
1218 log(" for each selected module, re-intergrate the module '<module-name>$abc9'\n");
1219 log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n");
1220 log(" inputs and outputs.\n");
1221 log("\n");
1222 }
1223 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1224 {
1225 log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
1226
1227 bool check_mode = false;
1228 bool prep_delays_mode = false;
1229 bool mark_scc_mode = false;
1230 bool prep_dff_mode = false;
1231 bool prep_xaiger_mode = false;
1232 bool prep_lut_mode = false;
1233 bool prep_box_mode = false;
1234 bool reintegrate_mode = false;
1235 bool dff_mode = false;
1236 std::string write_lut_dst;
1237 int maxlut = 0;
1238 std::string write_box_dst;
1239
1240 size_t argidx;
1241 for (argidx = 1; argidx < args.size(); argidx++) {
1242 std::string arg = args[argidx];
1243 if (arg == "-check") {
1244 check_mode = true;
1245 continue;
1246 }
1247 if (arg == "-mark_scc") {
1248 mark_scc_mode = true;
1249 continue;
1250 }
1251 if (arg == "-prep_dff") {
1252 prep_dff_mode = true;
1253 continue;
1254 }
1255 if (arg == "-prep_xaiger") {
1256 prep_xaiger_mode = true;
1257 continue;
1258 }
1259 if (arg == "-prep_delays") {
1260 prep_delays_mode = true;
1261 continue;
1262 }
1263 if (arg == "-prep_lut" && argidx+1 < args.size()) {
1264 prep_lut_mode = true;
1265 maxlut = atoi(args[++argidx].c_str());
1266 continue;
1267 }
1268 if (arg == "-maxlut" && argidx+1 < args.size()) {
1269 continue;
1270 }
1271 if (arg == "-write_lut" && argidx+1 < args.size()) {
1272 write_lut_dst = args[++argidx];
1273 rewrite_filename(write_lut_dst);
1274 continue;
1275 }
1276 if (arg == "-prep_box") {
1277 prep_box_mode = true;
1278 continue;
1279 }
1280 if (arg == "-write_box" && argidx+1 < args.size()) {
1281 write_box_dst = args[++argidx];
1282 rewrite_filename(write_box_dst);
1283 continue;
1284 }
1285 if (arg == "-reintegrate") {
1286 reintegrate_mode = true;
1287 continue;
1288 }
1289 if (arg == "-dff") {
1290 dff_mode = true;
1291 continue;
1292 }
1293 break;
1294 }
1295 extra_args(args, argidx, design);
1296
1297 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))
1298 log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
1299
1300 if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
1301 log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
1302
1303 if (check_mode)
1304 check(design);
1305 if (prep_delays_mode)
1306 prep_delays(design, dff_mode);
1307 if (prep_lut_mode)
1308 prep_lut(design, maxlut);
1309 if (prep_box_mode)
1310 prep_box(design, dff_mode);
1311
1312 for (auto mod : design->selected_modules()) {
1313 if (mod->get_bool_attribute("\\abc9_holes"))
1314 continue;
1315
1316 if (mod->processes.size() > 0) {
1317 log("Skipping module %s as it contains processes.\n", log_id(mod));
1318 continue;
1319 }
1320
1321 if (!design->selected_whole_module(mod))
1322 log_error("Can't handle partially selected module %s!\n", log_id(mod));
1323
1324 if (!write_lut_dst.empty())
1325 write_lut(mod, write_lut_dst);
1326 if (!write_box_dst.empty())
1327 write_box(mod, write_box_dst);
1328 if (mark_scc_mode)
1329 mark_scc(mod);
1330 if (prep_dff_mode)
1331 prep_dff(mod);
1332 if (prep_xaiger_mode)
1333 prep_xaiger(mod, dff_mode);
1334 if (reintegrate_mode)
1335 reintegrate(mod);
1336 }
1337 }
1338 } Abc9OpsPass;
1339
1340 PRIVATE_NAMESPACE_END