aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--passes/techmap/Makefile.inc3
-rw-r--r--passes/techmap/abc9.cc231
-rw-r--r--passes/techmap/abc9_map.cc (renamed from passes/techmap/abc9_techmap.cc)163
-rw-r--r--passes/techmap/abc9_ops.cc139
4 files changed, 406 insertions, 130 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index a7c8d8c2b..734d6c10f 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -8,7 +8,8 @@ OBJS += passes/techmap/libparse.o
ifeq ($(ENABLE_ABC),1)
OBJS += passes/techmap/abc.o
OBJS += passes/techmap/abc9.o
-OBJS += passes/techmap/abc9_techmap.o
+OBJS += passes/techmap/abc9_map.o
+OBJS += passes/techmap/abc9_ops.o
ifneq ($(ABCEXTERNAL),)
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
new file mode 100644
index 000000000..e1cf188ce
--- /dev/null
+++ b/passes/techmap/abc9.cc
@@ -0,0 +1,231 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * (C) 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate
+ // to one LUT6 (instead of a LUT5 + LUT2)
+
+struct Abc9Pass : public ScriptPass
+{
+ Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" abc9 [options] [selection]\n");
+ log("\n");
+ log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n");
+ log("library to a target architecture.\n");
+ log("\n");
+ log(" -exe <command>\n");
+#ifdef ABCEXTERNAL
+ log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
+#else
+ log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+#endif
+ log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
+ log("\n");
+ log(" -script <file>\n");
+ log(" use the specified ABC script file instead of the default script.\n");
+ log("\n");
+ log(" if <file> starts with a plus sign (+), then the rest of the filename\n");
+ log(" string is interpreted as the command string to be passed to ABC. The\n");
+ log(" leading plus sign is removed and all commas (,) in the string are\n");
+ log(" replaced with blanks before the string is passed to ABC.\n");
+ log("\n");
+ log(" if no -script parameter is given, the following scripts are used:\n");
+ log("\n");
+ log(" for -lut/-luts (only one LUT size):\n");
+ // FIXME
+ //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str());
+ log("\n");
+ log(" for -lut/-luts (different LUT sizes):\n");
+ // FIXME
+ //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
+ log("\n");
+ log(" -fast\n");
+ log(" use different default scripts that are slightly faster (at the cost\n");
+ log(" of output quality):\n");
+ log("\n");
+ log(" for -lut/-luts:\n");
+ // FIXME
+ //log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str());
+ log("\n");
+ log(" -D <picoseconds>\n");
+ log(" set delay target. the string {D} in the default scripts above is\n");
+ log(" replaced by this option when used, and an empty string otherwise\n");
+ log(" (indicating best possible delay).\n");
+// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
+// log(" default scripts above.\n");
+ log("\n");
+// log(" -S <num>\n");
+// log(" maximum number of LUT inputs shared.\n");
+// log(" (replaces {S} in the default scripts above, default: -S 1)\n");
+// log("\n");
+ log(" -lut <width>\n");
+ log(" generate netlist using luts of (max) the specified width.\n");
+ log("\n");
+ log(" -lut <w1>:<w2>\n");
+ log(" generate netlist using luts of (max) the specified width <w2>. All\n");
+ log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
+ log(" the area cost doubles with each additional input bit. the delay cost\n");
+ log(" is still constant for all lut widths.\n");
+ log("\n");
+ log(" -lut <file>\n");
+ log(" pass this file with lut library to ABC.\n");
+ log("\n");
+ log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n");
+ log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
+ log(" 2, 3, .. inputs.\n");
+ log("\n");
+// log(" -dff\n");
+// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
+// log(" clock domains are automatically partitioned in clock domains and each\n");
+// log(" domain is passed through ABC independently.\n");
+// log("\n");
+// log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
+// log(" use only the specified clock domain. this is like -dff, but only FF\n");
+// log(" cells that belong to the specified clock domain are used.\n");
+// log("\n");
+// log(" -keepff\n");
+// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
+// log(" them, for example for equivalence checking.)\n");
+// log("\n");
+ log(" -nocleanup\n");
+ log(" when this option is used, the temporary files created by this pass\n");
+ log(" are not removed. this is useful for debugging.\n");
+ log("\n");
+ log(" -showtmp\n");
+ log(" print the temp dir name in log. usually this is suppressed so that the\n");
+ log(" command output is identical across runs.\n");
+ log("\n");
+ log(" -markgroups\n");
+ log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n");
+ log(" this attribute is a unique integer for each ABC process started. This\n");
+ log(" is useful for debugging the partitioning of clock domains.\n");
+ log("\n");
+ log(" -box <file>\n");
+ log(" pass this file with box library to ABC. Use with -lut.\n");
+ log("\n");
+ log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+ log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+ log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+ log("output when passing an ABC script that writes a file. Instead write your full\n");
+ log("design as BLIF file with write_blif and then load that into ABC externally if\n");
+ log("you want to use ABC to convert your design into another format.\n");
+ log("\n");
+ log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
+ log("\n");
+ help_script();
+ log("\n");
+ }
+
+ std::stringstream map_cmd;
+ bool cleanup;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ map_cmd.str("");
+ map_cmd << "abc9_map";
+ cleanup = true;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ std::string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if ((arg == "-exe" || arg == "-script" || arg == "-D" ||
+ /* arg == "-S" || */ arg == "-lut" || arg == "-luts" ||
+ arg == "-clk" || arg == "-box" || arg == "-W") &&
+ argidx+1 < args.size()) {
+ map_cmd << " " << arg << " " << args[++argidx];
+ continue;
+ }
+ if (arg == "-fast" || /*arg == "-dff" ||*/ arg == "-keepff"
+ /*|| arg == "-nocleanup"*/ || arg == "-showtmp" || arg == "-markgroups"
+ || arg == "-nomfs") {
+ map_cmd << " " << arg;
+ continue;
+ }
+ if (arg == "-nocleanup") {
+ cleanup = false;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log_header(design, "Executing ABC9 pass.\n");
+
+ run_script(design, run_from, run_to);
+ }
+
+ void script() YS_OVERRIDE
+ {
+ auto selected_modules = active_design->selected_modules();
+ active_design->selection_stack.emplace_back(false);
+
+ for (auto mod : selected_modules) {
+ log_push();
+
+ active_design->selection().select(mod);
+
+ std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
+ if (!cleanup)
+ tempdir_name[0] = tempdir_name[4] = '_';
+ tempdir_name = make_temp_dir(tempdir_name);
+
+ run("scc -set_attr abc9_scc_id {}");
+ run("abc9_ops -break_scc");
+ run("aigmap");
+ run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()),
+ "write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
+ run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()),
+ "abc9_map [options] -tempdir <abc-temp-dir>");
+ run("abc9_ops -unbreak_scc");
+
+ if (cleanup)
+ {
+ log("Removing temp directory.\n");
+ remove_directory(tempdir_name);
+ }
+
+ active_design->selection().selected_modules.clear();
+
+ log_pop();
+ }
+
+ active_design->selection_stack.pop_back();
+ }
+} Abc9Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/abc9_techmap.cc b/passes/techmap/abc9_map.cc
index 7ff68f382..40ff4bbf0 100644
--- a/passes/techmap/abc9_techmap.cc
+++ b/passes/techmap/abc9_map.cc
@@ -76,58 +76,6 @@ inline std::string remap_name(RTLIL::IdString abc9_name)
return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
}
-void handle_loops(RTLIL::Design *design)
-{
- Pass::call(design, "scc -set_attr abc9_scc_id {}");
-
- // For every unique SCC found, (arbitrarily) find the first
- // cell in the component, and select (and mark) all its output
- // wires
- pool<RTLIL::Const> ids_seen;
- for (auto cell : module->cells()) {
- auto it = cell->attributes.find(ID(abc9_scc_id));
- if (it != cell->attributes.end()) {
- auto r = ids_seen.insert(it->second);
- if (r.second) {
- for (auto &c : cell->connections_) {
- if (c.second.is_fully_const()) continue;
- if (cell->output(c.first)) {
- SigBit b = c.second.as_bit();
- Wire *w = b.wire;
- if (w->port_input) {
- // In this case, hopefully the loop break has been already created
- // Get the non-prefixed wire
- Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str()));
- log_assert(wo != nullptr);
- log_assert(wo->port_output);
- log_assert(b.offset < GetSize(wo));
- c.second = RTLIL::SigBit(wo, b.offset);
- }
- else {
- // Create a new output/input loop break
- w->port_input = true;
- w = module->wire(stringf("%s.abco", w->name.c_str()));
- if (!w) {
- w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire));
- w->port_output = true;
- }
- else {
- log_assert(w->port_input);
- log_assert(b.offset < GetSize(w));
- }
- w->set_bool_attribute(ID(abc9_scc_break));
- c.second = RTLIL::SigBit(w, b.offset);
- }
- }
- }
- }
- cell->attributes.erase(it);
- }
- }
-
- module->fixup_ports();
-}
-
std::string add_echos_to_abc9_cmd(std::string str)
{
std::string new_str, token;
@@ -254,10 +202,10 @@ struct abc9_output_filter
};
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
+ /*bool cleanup,*/ vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool show_tempdir, std::string box_file, std::string lut_file,
- std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs
+ std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs, std::string tempdir_name
)
{
module = current_module;
@@ -296,10 +244,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (dff_mode && clk_sig.empty())
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
- std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
- if (!cleanup)
- tempdir_name[0] = tempdir_name[4] = '_';
- tempdir_name = make_temp_dir(tempdir_name);
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
@@ -383,33 +327,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
}
- bool count_output = false;
- for (auto port_name : module->ports) {
- RTLIL::Wire *port_wire = module->wire(port_name);
- log_assert(port_wire);
- if (port_wire->port_output) {
- count_output = true;
- break;
- }
- }
-
log_push();
- if (count_output)
+ //if (count_output)
{
- design->selection_stack.emplace_back(false);
- RTLIL::Selection& sel = design->selection_stack.back();
- sel.select(module);
-
- handle_loops(design);
-
- Pass::call(design, "aigmap");
-
- //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
- // count_gates, GetSize(signal_list), count_input, count_output);
-
- Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
-
std::string buffer;
std::ifstream ifs;
#if 0
@@ -428,8 +349,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
design->remove(design->module(ID($__abc9__)));
#endif
- design->selection_stack.pop_back();
-
log_header(design, "Executing ABC9_MAP.\n");
if (!lut_costs.empty()) {
@@ -773,41 +692,16 @@ clone_lut:
}
}
- // Now 'unexpose' those wires by undoing
- // the expose operation -- remove them from PO/PI
- // and re-connecting them back together
- for (auto wire : module->wires()) {
- auto it = wire->attributes.find(ID(abc9_scc_break));
- if (it != wire->attributes.end()) {
- wire->attributes.erase(it);
- log_assert(wire->port_output);
- wire->port_output = false;
- std::string name = wire->name.str();
- RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5));
- log_assert(i_wire);
- log_assert(i_wire->port_input);
- i_wire->port_input = false;
- module->connect(i_wire, wire);
- }
- }
- module->fixup_ports();
-
//log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
log("ABC RESULTS: input signals: %8d\n", in_wires);
log("ABC RESULTS: output signals: %8d\n", out_wires);
design->remove(mapped_mod);
}
- else
- {
- log("Don't call ABC as there is nothing to map.\n");
- }
-
- if (cleanup)
- {
- log("Removing temp directory.\n");
- remove_directory(tempdir_name);
- }
+ //else
+ //{
+ // log("Don't call ABC as there is nothing to map.\n");
+ //}
log_pop();
}
@@ -894,10 +788,10 @@ struct Abc9TechmapPass : public Pass {
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
// log(" them, for example for equivalence checking.)\n");
// log("\n");
- log(" -nocleanup\n");
- log(" when this option is used, the temporary files created by this pass\n");
- log(" are not removed. this is useful for debugging.\n");
- log("\n");
+// log(" -nocleanup\n");
+// log(" when this option is used, the temporary files created by this pass\n");
+// log(" are not removed. this is useful for debugging.\n");
+// log("\n");
log(" -showtmp\n");
log(" print the temp dir name in log. usually this is suppressed so that the\n");
log(" command output is identical across runs.\n");
@@ -910,6 +804,9 @@ struct Abc9TechmapPass : public Pass {
log(" -box <file>\n");
log(" pass this file with box library to ABC. Use with -lut.\n");
log("\n");
+ log(" -tempdir <dir>\n");
+ log(" use this as the temp dir.\n");
+ log("\n");
log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
log("ABC on logic snippets extracted from your design. You will not get any useful\n");
@@ -922,7 +819,7 @@ struct Abc9TechmapPass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
+ log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n");
log_push();
assign_map.clear();
@@ -934,7 +831,8 @@ struct Abc9TechmapPass : public Pass {
#endif
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
- bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
+ std::string tempdir_name;
+ bool fast_mode = false, dff_mode = false, keepff = false /*, cleanup = true*/;
bool show_tempdir = false;
bool nomfs = false;
vector<int> lut_costs;
@@ -1038,10 +936,10 @@ struct Abc9TechmapPass : public Pass {
// keepff = true;
// continue;
//}
- if (arg == "-nocleanup") {
- cleanup = false;
- continue;
- }
+ //if (arg == "-nocleanup") {
+ // cleanup = false;
+ // continue;
+ //}
if (arg == "-showtmp") {
show_tempdir = true;
continue;
@@ -1062,17 +960,24 @@ struct Abc9TechmapPass : public Pass {
nomfs = true;
continue;
}
+ if (arg == "-tempdir" && argidx+1 < args.size()) {
+ tempdir_name = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
// ABC expects a box file for XAIG
if (box_file.empty())
- box_file = "+/dummy.box";
+ box_file = "+/dummy.box";
rewrite_filename(box_file);
if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
- box_file = std::string(pwd) + "/" + box_file;
+ box_file = std::string(pwd) + "/" + box_file;
+
+ if (tempdir_name.empty())
+ log_cmd_error("abc9_map '-tempdir' option is mandatory.\n");
dict<int,IdString> box_lookup;
for (auto m : design->modules()) {
@@ -1148,9 +1053,9 @@ struct Abc9TechmapPass : public Pass {
assign_map.set(mod);
if (!dff_mode || !clk_str.empty()) {
- abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, dff_mode, clk_str, keepff,
delay_target, lutin_shared, fast_mode, show_tempdir,
- box_file, lut_file, wire_delay, box_lookup, nomfs);
+ box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
continue;
}
@@ -1294,9 +1199,9 @@ struct Abc9TechmapPass : public Pass {
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
- abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
- box_file, lut_file, wire_delay, box_lookup, nomfs);
+ box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
assign_map.set(mod);
}
}
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
new file mode 100644
index 000000000..4c30efd06
--- /dev/null
+++ b/passes/techmap/abc9_ops.cc
@@ -0,0 +1,139 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void break_scc(RTLIL::Module *module)
+{
+ // For every unique SCC found, (arbitrarily) find the first
+ // cell in the component, and convert all wires driven by
+ // its output ports into a new PO, and drive its previous
+ // sinks with a new PI
+ pool<RTLIL::Const> ids_seen;
+ for (auto cell : module->selected_cells()) {
+ auto it = cell->attributes.find(ID(abc9_scc_id));
+ if (it == cell->attributes.end())
+ continue;
+ auto r = ids_seen.insert(it->second);
+ cell->attributes.erase(it);
+ if (!r.second)
+ continue;
+ for (auto &c : cell->connections_) {
+ if (c.second.is_fully_const()) continue;
+ if (cell->output(c.first)) {
+ SigBit b = c.second.as_bit();
+ Wire *w = b.wire;
+ if (w->port_input) {
+ // In this case, hopefully the loop break has been already created
+ // Get the non-prefixed wire
+ Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str()));
+ log_assert(wo != nullptr);
+ log_assert(wo->port_output);
+ log_assert(b.offset < GetSize(wo));
+ c.second = RTLIL::SigBit(wo, b.offset);
+ }
+ else {
+ // Create a new output/input loop break
+ w->port_input = true;
+ w = module->wire(stringf("%s.abco", w->name.c_str()));
+ if (!w) {
+ w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire));
+ w->port_output = true;
+ }
+ else {
+ log_assert(w->port_input);
+ log_assert(b.offset < GetSize(w));
+ }
+ w->set_bool_attribute(ID(abc9_scc_break));
+ c.second = RTLIL::SigBit(w, b.offset);
+ }
+ }
+ }
+ }
+
+ module->fixup_ports();
+}
+
+void unbreak_scc(RTLIL::Module *module) {
+ // Now 'unexpose' those wires by undoing
+ // the expose operation -- remove them from PO/PI
+ // and re-connecting them back together
+ for (auto wire : module->wires()) {
+ auto it = wire->attributes.find(ID(abc9_scc_break));
+ if (it != wire->attributes.end()) {
+ wire->attributes.erase(it);
+ log_assert(wire->port_output);
+ wire->port_output = false;
+ std::string name = wire->name.str();
+ RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5));
+ log_assert(i_wire);
+ log_assert(i_wire->port_input);
+ i_wire->port_input = false;
+ module->connect(i_wire, wire);
+ }
+ }
+ module->fixup_ports();
+}
+
+struct Abc9PrepPass : public Pass {
+ Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" abc9_ops [options] [selection]\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
+ log_push();
+
+ bool break_scc_mode = false;
+ bool unbreak_scc_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-break_scc") {
+ break_scc_mode = true;
+ continue;
+ }
+ if (arg == "-unbreak_scc") {
+ unbreak_scc_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules()) {
+ if (break_scc_mode)
+ break_scc(mod);
+ if (unbreak_scc_mode)
+ unbreak_scc(mod);
+ }
+ }
+} Abc9PrepPass;
+
+PRIVATE_NAMESPACE_END