6f089447e47daa12154d7fddd00698874e094a9c
[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
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 int map_autoidx;
30
31 inline std::string remap_name(RTLIL::IdString abc9_name)
32 {
33 return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
34 }
35
36 void break_scc(RTLIL::Module *module)
37 {
38 // For every unique SCC found, (arbitrarily) find the first
39 // cell in the component, and convert all wires driven by
40 // its output ports into a new PO, and drive its previous
41 // sinks with a new PI
42 pool<RTLIL::Const> ids_seen;
43 for (auto cell : module->cells()) {
44 auto it = cell->attributes.find(ID(abc9_scc_id));
45 if (it == cell->attributes.end())
46 continue;
47 auto r = ids_seen.insert(it->second);
48 cell->attributes.erase(it);
49 if (!r.second)
50 continue;
51 for (auto &c : cell->connections_) {
52 if (c.second.is_fully_const()) continue;
53 if (cell->output(c.first)) {
54 SigBit b = c.second.as_bit();
55 Wire *w = b.wire;
56 if (w->port_input) {
57 // In this case, hopefully the loop break has been already created
58 // Get the non-prefixed wire
59 Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str()));
60 log_assert(wo != nullptr);
61 log_assert(wo->port_output);
62 log_assert(b.offset < GetSize(wo));
63 c.second = RTLIL::SigBit(wo, b.offset);
64 }
65 else {
66 // Create a new output/input loop break
67 w->port_input = true;
68 w = module->wire(stringf("%s.abco", w->name.c_str()));
69 if (!w) {
70 w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire));
71 w->port_output = true;
72 }
73 else {
74 log_assert(w->port_input);
75 log_assert(b.offset < GetSize(w));
76 }
77 w->set_bool_attribute(ID(abc9_scc_break));
78 c.second = RTLIL::SigBit(w, b.offset);
79 }
80 }
81 }
82 }
83
84 module->fixup_ports();
85 }
86
87 void unbreak_scc(RTLIL::Module *module)
88 {
89 // Now 'unexpose' those wires by undoing
90 // the expose operation -- remove them from PO/PI
91 // and re-connecting them back together
92 for (auto wire : module->wires()) {
93 auto it = wire->attributes.find(ID(abc9_scc_break));
94 if (it != wire->attributes.end()) {
95 wire->attributes.erase(it);
96 log_assert(wire->port_output);
97 wire->port_output = false;
98 std::string name = wire->name.str();
99 RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5));
100 log_assert(i_wire);
101 log_assert(i_wire->port_input);
102 i_wire->port_input = false;
103 module->connect(i_wire, wire);
104 }
105 }
106 module->fixup_ports();
107 }
108
109 void prep_dff(RTLIL::Module *module)
110 {
111 auto design = module->design;
112 log_assert(design);
113
114 SigMap assign_map(module);
115
116 typedef SigSpec clkdomain_t;
117 dict<clkdomain_t, int> clk_to_mergeability;
118
119 for (auto cell : module->cells()) {
120 if (cell->type != "$__ABC9_FF_")
121 continue;
122
123 Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
124 if (abc9_clock_wire == NULL)
125 log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
126 SigSpec abc9_clock = assign_map(abc9_clock_wire);
127
128 clkdomain_t key(abc9_clock);
129
130 auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
131 auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second));
132 log_assert(r2.second);
133
134 Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str()));
135 if (abc9_init_wire == NULL)
136 log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
137 log_assert(GetSize(abc9_init_wire) == 1);
138 SigSpec abc9_init = assign_map(abc9_init_wire);
139 if (!abc9_init.is_fully_const())
140 log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
141 r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
142 log_assert(r2.second);
143 }
144
145 RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
146 if (holes_module) {
147 dict<SigSig, SigSig> replace;
148 for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) {
149 auto cell = it->second;
150 if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
151 "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
152 SigBit D = cell->getPort("\\D");
153 SigBit Q = cell->getPort("\\Q");
154 // Remove the DFF cell from what needs to be a combinatorial box
155 it = holes_module->cells_.erase(it);
156 Wire *port;
157 if (GetSize(Q.wire) == 1)
158 port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
159 else
160 port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
161 log_assert(port);
162 // Prepare to replace "assign <port> = DFF.Q;" with "assign <port> = DFF.D;"
163 // in order to extract the combinatorial control logic that feeds the box
164 // (i.e. clock enable, synchronous reset, etc.)
165 replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D)));
166 // Since `flatten` above would have created wires named "<cell>.Q",
167 // extract the pre-techmap cell name
168 auto pos = Q.wire->name.str().rfind(".");
169 log_assert(pos != std::string::npos);
170 IdString driver = Q.wire->name.substr(0, pos);
171 // And drive the signal that was previously driven by "DFF.Q" (typically
172 // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
173 // wire (which itself is driven an input port) we inserted above
174 Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
175 log_assert(currQ);
176 holes_module->connect(Q, currQ);
177 }
178 else
179 ++it;
180 }
181
182 for (auto &conn : holes_module->connections_)
183 conn = replace.at(conn, conn);
184 }
185 }
186
187 void prep_holes(RTLIL::Module *module, bool dff)
188 {
189 auto design = module->design;
190 log_assert(design);
191
192 SigMap sigmap(module);
193
194 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
195 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
196 bool abc9_box_seen = false;
197
198 for (auto cell : module->cells()) {
199 if (cell->type == "$__ABC9_FF_")
200 continue;
201
202 auto inst_module = module->design->module(cell->type);
203 bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id");
204 bool abc9_flop = false;
205 if (abc9_box) {
206 abc9_flop = inst_module->get_bool_attribute("\\abc9_flop");
207 if (abc9_flop && !dff)
208 continue;
209 abc9_box_seen = abc9_box;
210 }
211 else if (!yosys_celltypes.cell_known(cell->type))
212 continue;
213
214 for (auto conn : cell->connections()) {
215 if (cell->input(conn.first))
216 for (auto bit : sigmap(conn.second))
217 bit_users[bit].insert(cell->name);
218
219 if (cell->output(conn.first) && !abc9_flop)
220 for (auto bit : sigmap(conn.second))
221 bit_drivers[bit].insert(cell->name);
222 }
223
224 toposort.node(cell->name);
225 }
226
227 if (!abc9_box_seen)
228 return;
229
230 for (auto &it : bit_users)
231 if (bit_drivers.count(it.first))
232 for (auto driver_cell : bit_drivers.at(it.first))
233 for (auto user_cell : it.second)
234 toposort.edge(driver_cell, user_cell);
235
236 if (ys_debug(1))
237 toposort.analyze_loops = true;
238
239 bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
240
241 if (ys_debug(1)) {
242 unsigned i = 0;
243 for (auto &it : toposort.loops) {
244 log(" loop %d\n", i++);
245 for (auto cell_name : it) {
246 auto cell = module->cell(cell_name);
247 log_assert(cell);
248 log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
249 }
250 }
251 }
252
253 log_assert(no_loops);
254
255 vector<Cell*> box_list;
256 for (auto cell_name : toposort.sorted) {
257 RTLIL::Cell *cell = module->cell(cell_name);
258 log_assert(cell);
259
260 RTLIL::Module* box_module = design->module(cell->type);
261 if (!box_module || !box_module->attributes.count("\\abc9_box_id"))
262 continue;
263
264 bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */);
265
266 // Fully pad all unused input connections of this box cell with S0
267 // Fully pad all undriven output connections of this box cell with anonymous wires
268 for (const auto &port_name : box_module->ports) {
269 RTLIL::Wire* w = box_module->wire(port_name);
270 log_assert(w);
271 auto it = cell->connections_.find(port_name);
272 if (w->port_input) {
273 RTLIL::SigSpec rhs;
274 if (it != cell->connections_.end()) {
275 if (GetSize(it->second) < GetSize(w))
276 it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second)));
277 rhs = it->second;
278 }
279 else {
280 rhs = RTLIL::SigSpec(State::S0, GetSize(w));
281 cell->setPort(port_name, rhs);
282 }
283 }
284 if (w->port_output) {
285 RTLIL::SigSpec rhs;
286 auto it = cell->connections_.find(w->name);
287 if (it != cell->connections_.end()) {
288 if (GetSize(it->second) < GetSize(w))
289 it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
290 rhs = it->second;
291 }
292 else {
293 Wire *wire = module->addWire(NEW_ID, GetSize(w));
294 if (blackbox)
295 wire->set_bool_attribute(ID(abc9_padding));
296 rhs = wire;
297 cell->setPort(port_name, rhs);
298 }
299 }
300 }
301
302 cell->attributes["\\abc9_box_seq"] = box_list.size();
303 box_list.emplace_back(cell);
304 }
305 log_assert(!box_list.empty());
306
307 RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
308 log_assert(holes_module);
309 holes_module->set_bool_attribute("\\abc9_holes");
310
311 dict<IdString, Cell*> cell_cache;
312 dict<IdString, std::vector<IdString>> box_ports;
313
314 int port_id = 1;
315 for (auto cell : box_list) {
316 RTLIL::Module* orig_box_module = design->module(cell->type);
317 log_assert(orig_box_module);
318 IdString derived_name = orig_box_module->derive(design, cell->parameters);
319 RTLIL::Module* box_module = design->module(derived_name);
320 if (box_module->has_processes())
321 Pass::call_on_module(design, box_module, "proc");
322
323 int box_inputs = 0;
324 auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
325 Cell *holes_cell = r.first->second;
326 if (r.second && box_module->get_bool_attribute("\\whitebox")) {
327 holes_cell = holes_module->addCell(cell->name, cell->type);
328 holes_cell->parameters = cell->parameters;
329 r.first->second = holes_cell;
330 }
331
332 auto r2 = box_ports.insert(cell->type);
333 if (r2.second) {
334 // Make carry in the last PI, and carry out the last PO
335 // since ABC requires it this way
336 IdString carry_in, carry_out;
337 for (const auto &port_name : box_module->ports) {
338 auto w = box_module->wire(port_name);
339 log_assert(w);
340 if (w->get_bool_attribute("\\abc9_carry")) {
341 if (w->port_input) {
342 if (carry_in != IdString())
343 log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module));
344 carry_in = port_name;
345 }
346 if (w->port_output) {
347 if (carry_out != IdString())
348 log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module));
349 carry_out = port_name;
350 }
351 }
352 else
353 r2.first->second.push_back(port_name);
354 }
355
356 if (carry_in != IdString() && carry_out == IdString())
357 log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module));
358 if (carry_in == IdString() && carry_out != IdString())
359 log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module));
360 if (carry_in != IdString()) {
361 r2.first->second.push_back(carry_in);
362 r2.first->second.push_back(carry_out);
363 }
364 }
365
366 for (const auto &port_name : box_ports.at(cell->type)) {
367 RTLIL::Wire *w = box_module->wire(port_name);
368 log_assert(w);
369 RTLIL::Wire *holes_wire;
370 RTLIL::SigSpec port_sig;
371 if (w->port_input)
372 for (int i = 0; i < GetSize(w); i++) {
373 box_inputs++;
374 holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
375 if (!holes_wire) {
376 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
377 holes_wire->port_input = true;
378 holes_wire->port_id = port_id++;
379 holes_module->ports.push_back(holes_wire->name);
380 }
381 if (holes_cell)
382 port_sig.append(holes_wire);
383 }
384 if (w->port_output)
385 for (int i = 0; i < GetSize(w); i++) {
386 if (GetSize(w) == 1)
387 holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name)));
388 else
389 holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i));
390 holes_wire->port_output = true;
391 holes_wire->port_id = port_id++;
392 holes_module->ports.push_back(holes_wire->name);
393 if (holes_cell)
394 port_sig.append(holes_wire);
395 else
396 holes_module->connect(holes_wire, State::S0);
397 }
398 if (!port_sig.empty()) {
399 if (r.second)
400 holes_cell->setPort(w->name, port_sig);
401 else
402 holes_module->connect(holes_cell->getPort(w->name), port_sig);
403 }
404 }
405
406 // For flops only, create an extra 1-bit input that drives a new wire
407 // called "<cell>.$abc9_currQ" that is used below
408 if (box_module->get_bool_attribute("\\abc9_flop")) {
409 log_assert(holes_cell);
410
411 box_inputs++;
412 Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
413 if (!holes_wire) {
414 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
415 holes_wire->port_input = true;
416 holes_wire->port_id = port_id++;
417 holes_module->ports.push_back(holes_wire->name);
418 }
419 Wire *w = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
420 holes_module->connect(w, holes_wire);
421 }
422 }
423 }
424
425 void reintegrate(RTLIL::Module *module)
426 {
427 auto design = module->design;
428 log_assert(design);
429
430 map_autoidx = autoidx++;
431
432 RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str()));
433 if (mapped_mod == NULL)
434 log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module));
435
436 for (auto w : mapped_mod->wires())
437 module->addWire(remap_name(w->name), GetSize(w));
438
439 dict<IdString,IdString> box_lookup;
440 dict<IdString,std::vector<IdString>> box_ports;
441
442 for (auto m : design->modules()) {
443 auto it = m->attributes.find(ID(abc9_box_id));
444 if (it == m->attributes.end())
445 continue;
446 if (m->name.begins_with("$paramod"))
447 continue;
448 auto id = it->second.as_int();
449 auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));
450 if (!r.second)
451 log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
452 log_id(m), id, log_id(r.first->second));
453 log_assert(r.second);
454
455 auto r2 = box_ports.insert(m->name);
456 if (r2.second) {
457 // Make carry in the last PI, and carry out the last PO
458 // since ABC requires it this way
459 IdString carry_in, carry_out;
460 for (const auto &port_name : m->ports) {
461 auto w = m->wire(port_name);
462 log_assert(w);
463 if (w->get_bool_attribute("\\abc9_carry")) {
464 if (w->port_input) {
465 if (carry_in != IdString())
466 log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
467 carry_in = port_name;
468 }
469 if (w->port_output) {
470 if (carry_out != IdString())
471 log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m));
472 carry_out = port_name;
473 }
474 }
475 else
476 r2.first->second.push_back(port_name);
477 }
478
479 if (carry_in != IdString() && carry_out == IdString())
480 log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m));
481 if (carry_in == IdString() && carry_out != IdString())
482 log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m));
483 if (carry_in != IdString()) {
484 r2.first->second.push_back(carry_in);
485 r2.first->second.push_back(carry_out);
486 }
487 }
488 }
489
490 std::vector<Cell*> boxes;
491 for (auto cell : module->cells().to_vector()) {
492 if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
493 module->remove(cell);
494 else if (cell->attributes.erase("\\abc9_box_seq"))
495 boxes.emplace_back(cell);
496 }
497
498 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
499 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
500 dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
501 dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
502
503 std::map<IdString, int> cell_stats;
504 for (auto mapped_cell : mapped_mod->cells())
505 {
506 toposort.node(mapped_cell->name);
507
508 if (mapped_cell->type == ID($_NOT_)) {
509 RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
510 RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
511 bit_users[a_bit].insert(mapped_cell->name);
512 bit_drivers[y_bit].insert(mapped_cell->name);
513
514 if (!a_bit.wire) {
515 mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
516 RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
517 log_assert(wire);
518 module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
519 }
520 else {
521 RTLIL::Cell* driver_lut = nullptr;
522 // ABC can return NOT gates that drive POs
523 if (!a_bit.wire->port_input) {
524 // If it's not a NOT gate that that comes from a PI directly,
525 // find the driver LUT and clone that to guarantee that we won't
526 // increase the max logic depth
527 // (TODO: Optimise by not cloning unless will increase depth)
528 RTLIL::IdString driver_name;
529 if (GetSize(a_bit.wire) == 1)
530 driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
531 else
532 driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
533 driver_lut = mapped_mod->cell(driver_name);
534 }
535
536 if (!driver_lut) {
537 // If a driver couldn't be found (could be from PI or box CI)
538 // then implement using a LUT
539 RTLIL::Cell *cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())),
540 RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
541 RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
542 RTLIL::Const::from_string("01"));
543 bit2sinks[cell->getPort(ID::A)].push_back(cell);
544 cell_stats[ID($lut)]++;
545 }
546 else
547 not2drivers[mapped_cell] = driver_lut;
548 }
549 continue;
550 }
551
552 if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
553 // Convert buffer into direct connection
554 if (mapped_cell->type == ID($lut) &&
555 GetSize(mapped_cell->getPort(ID::A)) == 1 &&
556 mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
557 SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name));
558 SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name));
559 module->connect(my_y, my_a);
560 log_abort();
561 continue;
562 }
563 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
564 cell->parameters = mapped_cell->parameters;
565 cell->attributes = mapped_cell->attributes;
566
567 for (auto &mapped_conn : mapped_cell->connections()) {
568 RTLIL::SigSpec newsig;
569 for (auto c : mapped_conn.second.chunks()) {
570 if (c.width == 0)
571 continue;
572 //log_assert(c.width == 1);
573 if (c.wire)
574 c.wire = module->wires_.at(remap_name(c.wire->name));
575 newsig.append(c);
576 }
577 cell->setPort(mapped_conn.first, newsig);
578
579 if (cell->input(mapped_conn.first)) {
580 for (auto i : newsig)
581 bit2sinks[i].push_back(cell);
582 for (auto i : mapped_conn.second)
583 bit_users[i].insert(mapped_cell->name);
584 }
585 if (cell->output(mapped_conn.first))
586 for (auto i : mapped_conn.second)
587 bit_drivers[i].insert(mapped_cell->name);
588 }
589 }
590 else {
591 RTLIL::Cell *existing_cell = module->cell(mapped_cell->name);
592 log_assert(existing_cell);
593 log_assert(mapped_cell->type.begins_with("$__boxid"));
594
595 auto type = box_lookup.at(mapped_cell->type, IdString());
596 if (type == IdString())
597 log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid"));
598 mapped_cell->type = type;
599
600 RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
601 cell->parameters = existing_cell->parameters;
602 cell->attributes = existing_cell->attributes;
603 module->swap_names(cell, existing_cell);
604
605 auto it = mapped_cell->connections_.find("\\i");
606 log_assert(it != mapped_cell->connections_.end());
607 SigSpec inputs = std::move(it->second);
608 mapped_cell->connections_.erase(it);
609 it = mapped_cell->connections_.find("\\o");
610 log_assert(it != mapped_cell->connections_.end());
611 SigSpec outputs = std::move(it->second);
612 mapped_cell->connections_.erase(it);
613
614 RTLIL::Module* box_module = design->module(mapped_cell->type);
615 auto abc9_flop = box_module->attributes.count("\\abc9_flop");
616 if (!abc9_flop) {
617 for (const auto &i : inputs)
618 bit_users[i].insert(mapped_cell->name);
619 for (const auto &i : outputs)
620 bit_drivers[i].insert(mapped_cell->name);
621 }
622
623 int input_count = 0, output_count = 0;
624 for (const auto &port_name : box_ports.at(cell->type)) {
625 RTLIL::Wire *w = box_module->wire(port_name);
626 log_assert(w);
627
628 SigSpec sig;
629 if (w->port_input) {
630 sig = inputs.extract(input_count, GetSize(w));
631 input_count += GetSize(w);
632 }
633 if (w->port_output) {
634 sig = outputs.extract(output_count, GetSize(w));
635 output_count += GetSize(w);
636 }
637
638 SigSpec newsig;
639 for (auto c : sig.chunks()) {
640 if (c.width == 0)
641 continue;
642 //log_assert(c.width == 1);
643 if (c.wire)
644 c.wire = module->wires_.at(remap_name(c.wire->name));
645 newsig.append(c);
646 }
647
648 auto it = existing_cell->connections_.find(port_name);
649 if (it == existing_cell->connections_.end())
650 continue;
651 if (GetSize(newsig) > GetSize(it->second))
652 newsig = newsig.extract(0, GetSize(it->second));
653 else
654 log_assert(GetSize(newsig) == GetSize(it->second));
655
656 cell->setPort(port_name, newsig);
657
658 if (w->port_input && !abc9_flop)
659 for (const auto &i : newsig)
660 bit2sinks[i].push_back(cell);
661 }
662 }
663
664 cell_stats[mapped_cell->type]++;
665 }
666
667 for (auto cell : boxes)
668 module->remove(cell);
669
670 // Copy connections (and rename) from mapped_mod to module
671 for (auto conn : mapped_mod->connections()) {
672 if (!conn.first.is_fully_const()) {
673 auto chunks = conn.first.chunks();
674 for (auto &c : chunks)
675 c.wire = module->wires_.at(remap_name(c.wire->name));
676 conn.first = std::move(chunks);
677 }
678 if (!conn.second.is_fully_const()) {
679 auto chunks = conn.second.chunks();
680 for (auto &c : chunks)
681 if (c.wire)
682 c.wire = module->wires_.at(remap_name(c.wire->name));
683 conn.second = std::move(chunks);
684 }
685 module->connect(conn);
686 }
687
688 for (auto &it : cell_stats)
689 log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
690 int in_wires = 0, out_wires = 0;
691
692 // Stitch in mapped_mod's inputs/outputs into module
693 for (auto port : mapped_mod->ports) {
694 RTLIL::Wire *w = mapped_mod->wire(port);
695 RTLIL::Wire *wire = module->wire(port);
696 log_assert(wire);
697 RTLIL::Wire *remap_wire = module->wire(remap_name(port));
698 RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire));
699 log_assert(GetSize(signal) >= GetSize(remap_wire));
700
701 RTLIL::SigSig conn;
702 if (w->port_output) {
703 conn.first = signal;
704 conn.second = remap_wire;
705 out_wires++;
706 module->connect(conn);
707 }
708 else if (w->port_input) {
709 conn.first = remap_wire;
710 conn.second = signal;
711 in_wires++;
712 module->connect(conn);
713 }
714 }
715
716 for (auto &it : bit_users)
717 if (bit_drivers.count(it.first))
718 for (auto driver_cell : bit_drivers.at(it.first))
719 for (auto user_cell : it.second)
720 toposort.edge(driver_cell, user_cell);
721 bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
722 log_assert(no_loops);
723
724 for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
725 RTLIL::Cell *not_cell = mapped_mod->cell(*ii);
726 log_assert(not_cell);
727 if (not_cell->type != ID($_NOT_))
728 continue;
729 auto it = not2drivers.find(not_cell);
730 if (it == not2drivers.end())
731 continue;
732 RTLIL::Cell *driver_lut = it->second;
733 RTLIL::SigBit a_bit = not_cell->getPort(ID::A);
734 RTLIL::SigBit y_bit = not_cell->getPort(ID::Y);
735 RTLIL::Const driver_mask;
736
737 a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
738 y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name));
739
740 auto jt = bit2sinks.find(a_bit);
741 if (jt == bit2sinks.end())
742 goto clone_lut;
743
744 for (auto sink_cell : jt->second)
745 if (sink_cell->type != ID($lut))
746 goto clone_lut;
747
748 // Push downstream LUTs past inverter
749 for (auto sink_cell : jt->second) {
750 SigSpec A = sink_cell->getPort(ID::A);
751 RTLIL::Const mask = sink_cell->getParam(ID(LUT));
752 int index = 0;
753 for (; index < GetSize(A); index++)
754 if (A[index] == a_bit)
755 break;
756 log_assert(index < GetSize(A));
757 int i = 0;
758 while (i < GetSize(mask)) {
759 for (int j = 0; j < (1 << index); j++)
760 std::swap(mask[i+j], mask[i+j+(1 << index)]);
761 i += 1 << (index+1);
762 }
763 A[index] = y_bit;
764 sink_cell->setPort(ID::A, A);
765 sink_cell->setParam(ID(LUT), mask);
766 }
767
768 // Since we have rewritten all sinks (which we know
769 // to be only LUTs) to be after the inverter, we can
770 // go ahead and clone the LUT with the expectation
771 // that the original driving LUT will become dangling
772 // and get cleaned away
773 clone_lut:
774 driver_mask = driver_lut->getParam(ID(LUT));
775 for (auto &b : driver_mask.bits) {
776 if (b == RTLIL::State::S0) b = RTLIL::State::S1;
777 else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
778 }
779 auto cell = module->addLut(NEW_ID,
780 driver_lut->getPort(ID::A),
781 y_bit,
782 driver_mask);
783 for (auto &bit : cell->connections_.at(ID::A)) {
784 bit.wire = module->wires_.at(remap_name(bit.wire->name));
785 bit2sinks[bit].push_back(cell);
786 }
787 }
788
789 //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
790 log("ABC RESULTS: input signals: %8d\n", in_wires);
791 log("ABC RESULTS: output signals: %8d\n", out_wires);
792
793 design->remove(mapped_mod);
794 }
795
796 struct Abc9OpsPass : public Pass {
797 Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
798 void help() YS_OVERRIDE
799 {
800 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
801 log("\n");
802 log(" abc9_ops [options] [selection]\n");
803 log("\n");
804 }
805 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
806 {
807 log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
808
809 bool break_scc_mode = false;
810 bool unbreak_scc_mode = false;
811 bool prep_dff_mode = false;
812 bool prep_holes_mode = false;
813 bool reintegrate_mode = false;
814 bool dff_mode = false;
815
816 size_t argidx;
817 for (argidx = 1; argidx < args.size(); argidx++) {
818 std::string arg = args[argidx];
819 if (arg == "-break_scc") {
820 break_scc_mode = true;
821 continue;
822 }
823 if (arg == "-unbreak_scc") {
824 unbreak_scc_mode = true;
825 continue;
826 }
827 if (arg == "-prep_dff") {
828 prep_dff_mode = true;
829 continue;
830 }
831 if (arg == "-prep_holes") {
832 prep_holes_mode = true;
833 continue;
834 }
835 if (arg == "-reintegrate") {
836 reintegrate_mode = true;
837 continue;
838 }
839 if (arg == "-dff") {
840 dff_mode = true;
841 continue;
842 }
843 break;
844 }
845 extra_args(args, argidx, design);
846
847 if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode))
848 log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n");
849
850 if (dff_mode && !prep_holes_mode)
851 log_cmd_error("'-dff' option is only relevant for -prep_holes.\n");
852
853 for (auto mod : design->selected_modules()) {
854 if (mod->get_bool_attribute("\\abc9_holes"))
855 continue;
856
857 if (mod->processes.size() > 0) {
858 log("Skipping module %s as it contains processes.\n", log_id(mod));
859 continue;
860 }
861
862 if (!design->selected_whole_module(mod))
863 log_error("Can't handle partially selected module %s!\n", log_id(mod));
864
865 if (break_scc_mode)
866 break_scc(mod);
867 if (unbreak_scc_mode)
868 unbreak_scc(mod);
869 if (prep_dff_mode)
870 prep_dff(mod);
871 if (prep_holes_mode)
872 prep_holes(mod, dff_mode);
873 if (reintegrate_mode)
874 reintegrate(mod);
875 }
876 }
877 } Abc9OpsPass;
878
879 PRIVATE_NAMESPACE_END