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