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