aboutsummaryrefslogtreecommitdiffstats
path: root/passes/techmap
diff options
context:
space:
mode:
Diffstat (limited to 'passes/techmap')
-rw-r--r--passes/techmap/abc.cc399
-rw-r--r--passes/techmap/abc9.cc834
-rw-r--r--passes/techmap/clkbufmap.cc41
-rw-r--r--passes/techmap/iopadmap.cc315
4 files changed, 745 insertions, 844 deletions
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index b29480e26..581652a41 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -29,17 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
-#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2"
-#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}"
-#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
-
-#define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}"
-#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if"
-#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}"
-#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map"
+#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
+#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+
+#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
+#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
+#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -747,6 +747,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+ if (script_file.empty() && !delay_target.empty())
+ for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
+ abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
+
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
@@ -1510,7 +1514,47 @@ struct AbcPass : public Pass {
#endif
#endif
- size_t argidx;
+ // get arguments from scratchpad first, then override by command arguments
+ std::string lut_arg, luts_arg, g_arg;
+ exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */);
+ script_file = design->scratchpad_get_string("abc.script", script_file);
+ liberty_file = design->scratchpad_get_string("abc.liberty", liberty_file);
+ constr_file = design->scratchpad_get_string("abc.constr", constr_file);
+ if (design->scratchpad.count("abc.D")) {
+ delay_target = "-D " + design->scratchpad_get_string("abc.D");
+ }
+ if (design->scratchpad.count("abc.I")) {
+ sop_inputs = "-I " + design->scratchpad_get_string("abc.I");
+ }
+ if (design->scratchpad.count("abc.P")) {
+ sop_products = "-P " + design->scratchpad_get_string("abc.P");
+ }
+ if (design->scratchpad.count("abc.S")) {
+ lutin_shared = "-S " + design->scratchpad_get_string("abc.S");
+ }
+ lut_arg = design->scratchpad_get_string("abc.lut", lut_arg);
+ luts_arg = design->scratchpad_get_string("abc.luts", luts_arg);
+ sop_mode = design->scratchpad_get_bool("abc.sop", sop_mode);
+ map_mux4 = design->scratchpad_get_bool("abc.mux4", map_mux4);
+ map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8);
+ map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16);
+ abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress);
+ g_arg = design->scratchpad_get_string("abc.g", g_arg);
+
+ fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode);
+ dff_mode = design->scratchpad_get_bool("abc.dff", dff_mode);
+ if (design->scratchpad.count("abc.clk")) {
+ clk_str = design->scratchpad_get_string("abc.clk");
+ dff_mode = true;
+ }
+ keepff = design->scratchpad_get_bool("abc.keepff", keepff);
+ cleanup = !design->scratchpad_get_bool("abc.nocleanup", !cleanup);
+ keepff = design->scratchpad_get_bool("abc.keepff", keepff);
+ show_tempdir = design->scratchpad_get_bool("abc.showtmp", show_tempdir);
+ markgroups = design->scratchpad_get_bool("abc.markgroups", markgroups);
+
+ size_t argidx, g_argidx;
+ bool g_arg_from_cmd = false;
char pwd [PATH_MAX];
if (!getcwd(pwd, sizeof(pwd))) {
log_cmd_error("getcwd failed: %s\n", strerror(errno));
@@ -1524,23 +1568,14 @@ struct AbcPass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
- rewrite_filename(script_file);
- if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
- script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
- rewrite_filename(liberty_file);
- if (!liberty_file.empty() && !is_absolute_path(liberty_file))
- liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
- rewrite_filename(constr_file);
constr_file = args[++argidx];
- if (!constr_file.empty() && !is_absolute_path(constr_file))
- constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
if (arg == "-D" && argidx+1 < args.size()) {
@@ -1560,37 +1595,11 @@ struct AbcPass : public Pass {
continue;
}
if (arg == "-lut" && argidx+1 < args.size()) {
- string arg = args[++argidx];
- size_t pos = arg.find_first_of(':');
- int lut_mode = 0, lut_mode2 = 0;
- if (pos != string::npos) {
- lut_mode = atoi(arg.substr(0, pos).c_str());
- lut_mode2 = atoi(arg.substr(pos+1).c_str());
- } else {
- lut_mode = atoi(arg.c_str());
- lut_mode2 = lut_mode;
- }
- lut_costs.clear();
- for (int i = 0; i < lut_mode; i++)
- lut_costs.push_back(1);
- for (int i = lut_mode; i < lut_mode2; i++)
- lut_costs.push_back(2 << (i - lut_mode));
+ lut_arg = args[++argidx];
continue;
}
if (arg == "-luts" && argidx+1 < args.size()) {
- lut_costs.clear();
- for (auto &tok : split_tokens(args[++argidx], ",")) {
- auto parts = split_tokens(tok, ":");
- if (GetSize(parts) == 0 && !lut_costs.empty())
- lut_costs.push_back(lut_costs.back());
- else if (GetSize(parts) == 1)
- lut_costs.push_back(atoi(parts.at(0).c_str()));
- else if (GetSize(parts) == 2)
- while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str()))
- lut_costs.push_back(atoi(parts.at(1).c_str()));
- else
- log_cmd_error("Invalid -luts syntax.\n");
- }
+ luts_arg = args[++argidx];
continue;
}
if (arg == "-sop") {
@@ -1614,123 +1623,11 @@ struct AbcPass : public Pass {
continue;
}
if (arg == "-g" && argidx+1 < args.size()) {
- for (auto g : split_tokens(args[++argidx], ",")) {
- vector<string> gate_list;
- bool remove_gates = false;
- if (GetSize(g) > 0 && g[0] == '-') {
- remove_gates = true;
- g = g.substr(1);
- }
- if (g == "AND") goto ok_gate;
- if (g == "NAND") goto ok_gate;
- if (g == "OR") goto ok_gate;
- if (g == "NOR") goto ok_gate;
- if (g == "XOR") goto ok_gate;
- if (g == "XNOR") goto ok_gate;
- if (g == "ANDNOT") goto ok_gate;
- if (g == "ORNOT") goto ok_gate;
- if (g == "MUX") goto ok_gate;
- if (g == "NMUX") goto ok_gate;
- if (g == "AOI3") goto ok_gate;
- if (g == "OAI3") goto ok_gate;
- if (g == "AOI4") goto ok_gate;
- if (g == "OAI4") goto ok_gate;
- if (g == "simple") {
- gate_list.push_back("AND");
- gate_list.push_back("OR");
- gate_list.push_back("XOR");
- gate_list.push_back("MUX");
- goto ok_alias;
- }
- if (g == "cmos2") {
- if (!remove_gates)
- cmos_cost = true;
- gate_list.push_back("NAND");
- gate_list.push_back("NOR");
- goto ok_alias;
- }
- if (g == "cmos3") {
- if (!remove_gates)
- cmos_cost = true;
- gate_list.push_back("NAND");
- gate_list.push_back("NOR");
- gate_list.push_back("AOI3");
- gate_list.push_back("OAI3");
- goto ok_alias;
- }
- if (g == "cmos4") {
- if (!remove_gates)
- cmos_cost = true;
- gate_list.push_back("NAND");
- gate_list.push_back("NOR");
- gate_list.push_back("AOI3");
- gate_list.push_back("OAI3");
- gate_list.push_back("AOI4");
- gate_list.push_back("OAI4");
- goto ok_alias;
- }
- if (g == "cmos") {
- if (!remove_gates)
- cmos_cost = true;
- gate_list.push_back("NAND");
- gate_list.push_back("NOR");
- gate_list.push_back("AOI3");
- gate_list.push_back("OAI3");
- gate_list.push_back("AOI4");
- gate_list.push_back("OAI4");
- gate_list.push_back("NMUX");
- gate_list.push_back("MUX");
- gate_list.push_back("XOR");
- gate_list.push_back("XNOR");
- goto ok_alias;
- }
- if (g == "gates") {
- gate_list.push_back("AND");
- gate_list.push_back("NAND");
- gate_list.push_back("OR");
- gate_list.push_back("NOR");
- gate_list.push_back("XOR");
- gate_list.push_back("XNOR");
- gate_list.push_back("ANDNOT");
- gate_list.push_back("ORNOT");
- goto ok_alias;
- }
- if (g == "aig") {
- gate_list.push_back("AND");
- gate_list.push_back("NAND");
- gate_list.push_back("OR");
- gate_list.push_back("NOR");
- gate_list.push_back("ANDNOT");
- gate_list.push_back("ORNOT");
- goto ok_alias;
- }
- if (g == "all") {
- gate_list.push_back("AND");
- gate_list.push_back("NAND");
- gate_list.push_back("OR");
- gate_list.push_back("NOR");
- gate_list.push_back("XOR");
- gate_list.push_back("XNOR");
- gate_list.push_back("ANDNOT");
- gate_list.push_back("ORNOT");
- gate_list.push_back("AOI3");
- gate_list.push_back("OAI3");
- gate_list.push_back("AOI4");
- gate_list.push_back("OAI4");
- gate_list.push_back("MUX");
- gate_list.push_back("NMUX");
- }
- cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
- ok_gate:
- gate_list.push_back(g);
- ok_alias:
- for (auto gate : gate_list) {
- if (remove_gates)
- enabled_gates.erase(gate);
- else
- enabled_gates.insert(gate);
- }
- }
+ if (g_arg_from_cmd)
+ log_cmd_error("Can only use -g once. Please combine.");
+ g_arg = args[++argidx];
+ g_argidx = argidx;
+ g_arg_from_cmd = true;
continue;
}
if (arg == "-fast") {
@@ -1766,8 +1663,176 @@ struct AbcPass : public Pass {
}
extra_args(args, argidx, design);
+ rewrite_filename(script_file);
+ if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
+ script_file = std::string(pwd) + "/" + script_file;
+ rewrite_filename(liberty_file);
+ if (!liberty_file.empty() && !is_absolute_path(liberty_file))
+ liberty_file = std::string(pwd) + "/" + liberty_file;
+ rewrite_filename(constr_file);
+ if (!constr_file.empty() && !is_absolute_path(constr_file))
+ constr_file = std::string(pwd) + "/" + constr_file;
+
+ // handle -lut argument
+ if (!lut_arg.empty()) {
+ size_t pos = lut_arg.find_first_of(':');
+ int lut_mode = 0, lut_mode2 = 0;
+ if (pos != string::npos) {
+ lut_mode = atoi(lut_arg.substr(0, pos).c_str());
+ lut_mode2 = atoi(lut_arg.substr(pos+1).c_str());
+ } else {
+ lut_mode = atoi(lut_arg.c_str());
+ lut_mode2 = lut_mode;
+ }
+ lut_costs.clear();
+ for (int i = 0; i < lut_mode; i++)
+ lut_costs.push_back(1);
+ for (int i = lut_mode; i < lut_mode2; i++)
+ lut_costs.push_back(2 << (i - lut_mode));
+ }
+ //handle -luts argument
+ if (!luts_arg.empty()){
+ lut_costs.clear();
+ for (auto &tok : split_tokens(luts_arg, ",")) {
+ auto parts = split_tokens(tok, ":");
+ if (GetSize(parts) == 0 && !lut_costs.empty())
+ lut_costs.push_back(lut_costs.back());
+ else if (GetSize(parts) == 1)
+ lut_costs.push_back(atoi(parts.at(0).c_str()));
+ else if (GetSize(parts) == 2)
+ while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str()))
+ lut_costs.push_back(atoi(parts.at(1).c_str()));
+ else
+ log_cmd_error("Invalid -luts syntax.\n");
+ }
+ }
+
+ // handle -g argument
+ if (!g_arg.empty()){
+ for (auto g : split_tokens(g_arg, ",")) {
+ vector<string> gate_list;
+ bool remove_gates = false;
+ if (GetSize(g) > 0 && g[0] == '-') {
+ remove_gates = true;
+ g = g.substr(1);
+ }
+ if (g == "AND") goto ok_gate;
+ if (g == "NAND") goto ok_gate;
+ if (g == "OR") goto ok_gate;
+ if (g == "NOR") goto ok_gate;
+ if (g == "XOR") goto ok_gate;
+ if (g == "XNOR") goto ok_gate;
+ if (g == "ANDNOT") goto ok_gate;
+ if (g == "ORNOT") goto ok_gate;
+ if (g == "MUX") goto ok_gate;
+ if (g == "NMUX") goto ok_gate;
+ if (g == "AOI3") goto ok_gate;
+ if (g == "OAI3") goto ok_gate;
+ if (g == "AOI4") goto ok_gate;
+ if (g == "OAI4") goto ok_gate;
+ if (g == "simple") {
+ gate_list.push_back("AND");
+ gate_list.push_back("OR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("MUX");
+ goto ok_alias;
+ }
+ if (g == "cmos2") {
+ if (!remove_gates)
+ cmos_cost = true;
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ goto ok_alias;
+ }
+ if (g == "cmos3") {
+ if (!remove_gates)
+ cmos_cost = true;
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ goto ok_alias;
+ }
+ if (g == "cmos4") {
+ if (!remove_gates)
+ cmos_cost = true;
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ goto ok_alias;
+ }
+ if (g == "cmos") {
+ if (!remove_gates)
+ cmos_cost = true;
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ gate_list.push_back("NMUX");
+ gate_list.push_back("MUX");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ goto ok_alias;
+ }
+ if (g == "gates") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
+ if (g == "aig") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
+ if (g == "all") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ gate_list.push_back("MUX");
+ gate_list.push_back("NMUX");
+ }
+ if (g_arg_from_cmd)
+ cmd_error(args, g_argidx, stringf("Unsupported gate type: %s", g.c_str()));
+ else
+ log_cmd_error("Unsupported gate type: %s", g.c_str());
+ ok_gate:
+ gate_list.push_back(g);
+ ok_alias:
+ for (auto gate : gate_list) {
+ if (remove_gates)
+ enabled_gates.erase(gate);
+ else
+ enabled_gates.insert(gate);
+ }
+ }
+ }
+
if (!lut_costs.empty() && !liberty_file.empty())
- log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n");
+ log_cmd_error("Got -lut and -liberty! These two options are exclusive.\n");
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 27106cc5d..2568a6cd1 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -22,20 +22,6 @@
// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
// http://www.eecs.berkeley.edu/~alanmi/abc/
-#if 0
-// Based on &flow3 - better QoR but more experimental
-#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \
- "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\
- "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\
- "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
- "&mfs; &ps -l"
-#else
-#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
-#endif
-
-
-#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}"
-
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
@@ -63,22 +49,16 @@ extern "C" int Abc_RealMain(int argc, char *argv[]);
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool markgroups;
int map_autoidx;
-SigMap assign_map;
-RTLIL::Module *module;
-
-bool clk_polarity, en_polarity;
-RTLIL::SigSpec clk_sig, en_sig;
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)
+void handle_loops(RTLIL::Design *design, RTLIL::Module *module)
{
- Pass::call(design, "scc -set_attr abc9_scc_id {}");
+ Pass::call(design, "scc -set_attr abc9_scc_id {} % w:*");
// For every unique SCC found, (arbitrarily) find the first
// cell in the component, and select (and mark) all its output
@@ -94,20 +74,30 @@ void handle_loops(RTLIL::Design *design)
if (cell->output(c.first)) {
SigBit b = c.second.as_bit();
Wire *w = b.wire;
- log_assert(!w->port_input);
- w->port_input = true;
- w = module->wire(stringf("%s.abci", w->name.c_str()));
- if (!w) {
- w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
- w->port_output = true;
+ 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 {
- log_assert(w->port_input);
- log_assert(b.offset < GetSize(w));
+ // 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);
}
- w->set_bool_attribute(ID(abc9_scc_break));
- module->swap_names(b.wire, w);
- c.second = RTLIL::SigBit(w, b.offset);
}
}
}
@@ -243,49 +233,14 @@ 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 /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
+void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file,
+ bool cleanup, vector<int> lut_costs, bool dff_mode, 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
)
{
- module = current_module;
map_autoidx = autoidx++;
- if (clk_str != "$")
- {
- clk_polarity = true;
- clk_sig = RTLIL::SigSpec();
-
- en_polarity = true;
- en_sig = RTLIL::SigSpec();
- }
-
- if (!clk_str.empty() && clk_str != "$")
- {
- if (clk_str.find(',') != std::string::npos) {
- int pos = clk_str.find(',');
- std::string en_str = clk_str.substr(pos+1);
- clk_str = clk_str.substr(0, pos);
- if (en_str[0] == '!') {
- en_polarity = false;
- en_str = en_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
- en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
- }
- if (clk_str[0] == '!') {
- clk_polarity = false;
- clk_str = clk_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
- }
-
- 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] = '_';
@@ -298,13 +253,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (!lut_costs.empty()) {
abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
if (!box_file.empty())
- abc9_script += stringf("read_box -v %s; ", box_file.c_str());
+ abc9_script += stringf("read_box %s; ", box_file.c_str());
}
else
if (!lut_file.empty()) {
abc9_script += stringf("read_lut %s; ", lut_file.c_str());
if (!box_file.empty())
- abc9_script += stringf("read_box -v %s; ", box_file.c_str());
+ abc9_script += stringf("read_box %s; ", box_file.c_str());
}
else
log_abort();
@@ -323,20 +278,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} else
abc9_script += stringf("source %s", script_file.c_str());
} else if (!lut_costs.empty() || !lut_file.empty()) {
- //bool all_luts_cost_same = true;
- //for (int this_cost : lut_costs)
- // if (this_cost != lut_costs.front())
- // all_luts_cost_same = false;
- abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
- //if (all_luts_cost_same && !fast_mode)
- // abc9_script += "; lutpack {S}";
+ abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)
+ : RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
} else
log_abort();
- //if (script_file.empty() && !delay_target.empty())
- // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1))
- // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8);
-
for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos))
abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3);
@@ -346,11 +292,26 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos))
abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3);
- if (nomfs)
- for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
- abc9_script = abc9_script.erase(pos, strlen("&mfs"));
-
- abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
+ std::string C;
+ if (design->scratchpad.count("abc9.if.C"))
+ C = "-C " + design->scratchpad_get_string("abc9.if.C");
+ for (size_t pos = abc9_script.find("{C}"); pos != std::string::npos; pos = abc9_script.find("{C}", pos))
+ abc9_script = abc9_script.substr(0, pos) + C + abc9_script.substr(pos+3);
+
+ std::string R;
+ if (design->scratchpad.count("abc9.if.R"))
+ R = "-R " + design->scratchpad_get_string("abc9.if.R");
+ for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos))
+ abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3);
+
+ abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str());
+ if (design->scratchpad_get_bool("abc9.verify")) {
+ if (dff_mode)
+ abc9_script += "; &verify -s";
+ else
+ abc9_script += "; &verify";
+ }
+ abc9_script += "; time";
abc9_script = add_echos_to_abc9_cmd(abc9_script);
for (size_t i = 0; i+1 < abc9_script.size(); i++)
@@ -361,45 +322,22 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
fprintf(f, "%s\n", abc9_script.c_str());
fclose(f);
- if (dff_mode || !clk_str.empty())
- {
- if (clk_sig.size() == 0)
- log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
- else {
- log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
- if (en_sig.size() != 0)
- log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
- log("\n");
- }
- }
-
- 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)
- {
- design->selection_stack.emplace_back(false);
- RTLIL::Selection& sel = design->selection_stack.back();
- sel.select(module);
-
- handle_loops(design);
+ handle_loops(design, module);
- Pass::call(design, "aigmap");
+ Pass::call(design, "aigmap -select");
- //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()));
- Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
+ int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs");
+ log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+ design->scratchpad_get_int("write_xaiger.num_ands"),
+ design->scratchpad_get_int("write_xaiger.num_wires"),
+ design->scratchpad_get_int("write_xaiger.num_inputs"),
+ count_outputs);
+ if (count_outputs > 0) {
std::string buffer;
std::ifstream ifs;
#if 0
@@ -414,30 +352,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
reader.parse_xaiger();
}
ifs.close();
- Pass::call(design, stringf("write_verilog -noexpr -norename"));
+ Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
design->remove(design->module(ID($__abc9__)));
#endif
- design->selection_stack.pop_back();
-
- // 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;
- RTLIL::Wire *i_wire = module->wire(wire->name.str() + ".abci");
- log_assert(i_wire);
- log_assert(i_wire->port_input);
- i_wire->port_input = false;
- module->connect(i_wire, wire);
- }
- }
- module->fixup_ports();
-
log_header(design, "Executing ABC9.\n");
if (!lut_costs.empty()) {
@@ -483,11 +401,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_assert(!design->module(ID($__abc9__)));
AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
- reader.parse_xaiger(box_lookup);
+ reader.parse_xaiger();
ifs.close();
#if 0
- Pass::call(design, stringf("write_verilog -noexpr -norename"));
+ Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
#endif
log_header(design, "Re-integrating ABC9 results.\n");
@@ -495,43 +413,30 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `$__abc9__'.\n");
- pool<RTLIL::SigBit> output_bits;
- for (auto &it : mapped_mod->wires_) {
- RTLIL::Wire *w = it.second;
- RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
- if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx;
- if (w->port_output) {
- RTLIL::Wire *wire = module->wire(w->name);
- log_assert(wire);
- for (int i = 0; i < GetSize(w); i++)
- output_bits.insert({wire, i});
- }
- }
-
- for (auto &it : module->connections_) {
- auto &signal = it.first;
- auto bits = signal.bits();
- for (auto &b : bits)
- if (output_bits.count(b))
- b = module->addWire(NEW_ID);
- signal = std::move(bits);
- }
+ for (auto w : mapped_mod->wires())
+ module->addWire(remap_name(w->name), GetSize(w));
dict<IdString, bool> abc9_box;
vector<RTLIL::Cell*> boxes;
- for (const auto &it : module->cells_) {
- auto cell = it.second;
- if (cell->type.in(ID($_AND_), ID($_NOT_))) {
+ for (auto cell : module->cells().to_vector()) {
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) {
module->remove(cell);
continue;
}
+ RTLIL::Module* box_module = design->module(cell->type);
auto jt = abc9_box.find(cell->type);
- if (jt == abc9_box.end()) {
- RTLIL::Module* box_module = design->module(cell->type);
+ if (jt == abc9_box.end())
jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first;
+ if (jt->second) {
+ if (box_module->get_bool_attribute("\\abc9_flop")) {
+ if (dff_mode)
+ boxes.emplace_back(cell);
+ else
+ box_module->set_bool_attribute("\\abc9_keep", false);
+ }
+ else
+ boxes.emplace_back(cell);
}
- if (jt->second)
- boxes.emplace_back(cell);
}
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
@@ -540,19 +445,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
std::map<IdString, int> cell_stats;
- for (auto c : mapped_mod->cells())
+ for (auto mapped_cell : mapped_mod->cells())
{
- toposort.node(c->name);
+ toposort.node(mapped_cell->name);
RTLIL::Cell *cell = nullptr;
- if (c->type == ID($_NOT_)) {
- RTLIL::SigBit a_bit = c->getPort(ID::A);
- RTLIL::SigBit y_bit = c->getPort(ID::Y);
- bit_users[a_bit].insert(c->name);
- bit_drivers[y_bit].insert(c->name);
+ if (mapped_cell->type == ID($_NOT_)) {
+ RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
+ RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
+ bit_users[a_bit].insert(mapped_cell->name);
+ bit_drivers[y_bit].insert(mapped_cell->name);
if (!a_bit.wire) {
- c->setPort(ID::Y, module->addWire(NEW_ID));
+ mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
log_assert(wire);
module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
@@ -567,16 +472,16 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
// (TODO: Optimise by not cloning unless will increase depth)
RTLIL::IdString driver_name;
if (GetSize(a_bit.wire) == 1)
- driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
+ driver_name = stringf("$lut%s", a_bit.wire->name.c_str());
else
- driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
+ driver_name = stringf("$lut%s[%d]", a_bit.wire->name.c_str(), a_bit.offset);
driver_lut = mapped_mod->cell(driver_name);
}
if (!driver_lut) {
// If a driver couldn't be found (could be from PI or box CI)
// then implement using a LUT
- cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+ cell = module->addLut(remap_name(stringf("$lut%s", mapped_cell->name.c_str())),
RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
RTLIL::Const::from_string("01"));
@@ -584,44 +489,46 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
cell_stats[ID($lut)]++;
}
else
- not2drivers[c] = driver_lut;
+ not2drivers[mapped_cell] = driver_lut;
continue;
}
else
log_abort();
- if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
continue;
}
- cell_stats[c->type]++;
+ cell_stats[mapped_cell->type]++;
RTLIL::Cell *existing_cell = nullptr;
- if (c->type == ID($lut)) {
- if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
- SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name));
- SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name));
+ if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
+ if (mapped_cell->type == ID($lut) &&
+ GetSize(mapped_cell->getPort(ID::A)) == 1 &&
+ mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
+ SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name));
+ SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name));
module->connect(my_y, my_a);
- if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
log_abort();
continue;
}
- cell = module->addCell(remap_name(c->name), c->type);
+ cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
}
else {
- existing_cell = module->cell(c->name);
+ existing_cell = module->cell(mapped_cell->name);
log_assert(existing_cell);
- cell = module->addCell(remap_name(c->name), c->type);
+ cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
}
- if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
if (existing_cell) {
cell->parameters = existing_cell->parameters;
cell->attributes = existing_cell->attributes;
}
else {
- cell->parameters = c->parameters;
- cell->attributes = c->attributes;
+ cell->parameters = mapped_cell->parameters;
+ cell->attributes = mapped_cell->attributes;
}
- for (auto &conn : c->connections()) {
+
+ RTLIL::Module* box_module = design->module(mapped_cell->type);
+ auto abc9_flop = box_module && box_module->get_bool_attribute("\\abc9_flop");
+ for (auto &conn : mapped_cell->connections()) {
RTLIL::SigSpec newsig;
for (auto c : conn.second.chunks()) {
if (c.width == 0)
@@ -633,15 +540,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
cell->setPort(conn.first, newsig);
- if (cell->input(conn.first)) {
- for (auto i : newsig)
- bit2sinks[i].push_back(cell);
- for (auto i : conn.second)
- bit_users[i].insert(c->name);
+ if (!abc9_flop) {
+ if (cell->input(conn.first)) {
+ for (auto i : newsig)
+ bit2sinks[i].push_back(cell);
+ for (auto i : conn.second)
+ bit_users[i].insert(mapped_cell->name);
+ }
+ if (cell->output(conn.first))
+ for (auto i : conn.second)
+ bit_drivers[i].insert(mapped_cell->name);
}
- if (cell->output(conn.first))
- for (auto i : conn.second)
- bit_drivers[i].insert(c->name);
}
}
@@ -781,6 +690,25 @@ 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);
@@ -803,6 +731,51 @@ clone_lut:
struct Abc9Pass : public Pass {
Abc9Pass() : Pass("abc9", "use ABC9 for technology mapping") { }
+ void on_register() YS_OVERRIDE
+ {
+ RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs";
+ RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -a -v; &mfs";
+ RTLIL::constpad["abc9.script.default.fast"] = "+&if {C} {W} {D} {R} -v";
+ // Based on ABC's &flow
+ RTLIL::constpad["abc9.script.flow"] = "+&scorr; &sweep;" \
+ "&dch -C 500;" \
+ /* Round 1 */ \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ /* Round 2 */ \
+ "&st; &sopb;" \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ /* Round 3 */ \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;";
+ // Based on ABC's &flow2
+ RTLIL::constpad["abc9.script.flow2"] = "+&scorr; &sweep;" \
+ /* Comm1 */ "&synch2 -K 6 -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ "&load; &st; &sopb -R 10 -C 4; " \
+ /* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
+ "&load";
+ // Based on ABC's &flow3
+ RTLIL::constpad["abc9.script.flow3"] = "+&scorr; &sweep;" \
+ "&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&mfs";
+ }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -810,7 +783,7 @@ struct Abc9Pass : public Pass {
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("library to a target architecture. Only fully-selected modules are supported.\n");
log("\n");
log(" -exe <command>\n");
#ifdef ABCEXTERNAL
@@ -830,25 +803,20 @@ struct Abc9Pass : public Pass {
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");
- log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str());
- log("\n");
- log(" for -lut/-luts (different LUT sizes):\n");
- log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
+ log(" for -lut/-luts:\n");
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).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");
- log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str());
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).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");
@@ -870,19 +838,10 @@ struct Abc9Pass : public Pass {
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(" -dff\n");
+ log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
+ log(" domains are marked as such and automatically partitioned by ABC.\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");
@@ -891,11 +850,6 @@ struct Abc9Pass : public Pass {
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");
@@ -903,8 +857,8 @@ struct Abc9Pass : public Pass {
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("design as an XAIGER file with `write_xaiger' and then load that into ABC\n");
+ log("externally if 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");
@@ -914,8 +868,6 @@ struct Abc9Pass : public Pass {
log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
log_push();
- assign_map.clear();
-
#ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL;
#else
@@ -923,11 +875,9 @@ struct Abc9Pass : 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;
+ bool fast_mode = false, dff_mode = false, cleanup = true;
bool show_tempdir = false;
- bool nomfs = false;
vector<int> lut_costs;
- markgroups = false;
#if 0
cleanup = false;
@@ -941,6 +891,29 @@ struct Abc9Pass : public Pass {
#endif
#endif
+ // get arguments from scratchpad first, then override by command arguments
+ std::string lut_arg, luts_arg;
+ exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */);
+ script_file = design->scratchpad_get_string("abc9.script", script_file);
+ if (design->scratchpad.count("abc9.D")) {
+ delay_target = "-D " + design->scratchpad_get_string("abc9.D");
+ }
+ lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg);
+ luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg);
+ fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode);
+ dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
+ cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup);
+ show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir);
+ box_file = design->scratchpad_get_string("abc9.box", box_file);
+ if (design->scratchpad.count("abc9.W")) {
+ wire_delay = "-W " + design->scratchpad_get_string("abc9.W");
+ }
+
+ if (design->scratchpad_get_bool("abc9.debug")) {
+ cleanup = false;
+ show_tempdir = true;
+ }
+
size_t argidx;
char pwd [PATH_MAX];
if (!getcwd(pwd, sizeof(pwd))) {
@@ -955,9 +928,6 @@ struct Abc9Pass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
- rewrite_filename(script_file);
- if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
- script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-D" && argidx+1 < args.size()) {
@@ -969,65 +939,21 @@ struct Abc9Pass : public Pass {
// continue;
//}
if (arg == "-lut" && argidx+1 < args.size()) {
- string arg = args[++argidx];
- size_t pos = arg.find_first_of(':');
- int lut_mode = 0, lut_mode2 = 0;
- if (pos != string::npos) {
- lut_mode = atoi(arg.substr(0, pos).c_str());
- lut_mode2 = atoi(arg.substr(pos+1).c_str());
- } else {
- pos = arg.find_first_of('.');
- if (pos != string::npos) {
- lut_file = arg;
- rewrite_filename(lut_file);
- if (!lut_file.empty() && !is_absolute_path(lut_file))
- lut_file = std::string(pwd) + "/" + lut_file;
- }
- else {
- lut_mode = atoi(arg.c_str());
- lut_mode2 = lut_mode;
- }
- }
- lut_costs.clear();
- for (int i = 0; i < lut_mode; i++)
- lut_costs.push_back(1);
- for (int i = lut_mode; i < lut_mode2; i++)
- lut_costs.push_back(2 << (i - lut_mode));
+ lut_arg = args[++argidx];
continue;
}
if (arg == "-luts" && argidx+1 < args.size()) {
- lut_costs.clear();
- for (auto &tok : split_tokens(args[++argidx], ",")) {
- auto parts = split_tokens(tok, ":");
- if (GetSize(parts) == 0 && !lut_costs.empty())
- lut_costs.push_back(lut_costs.back());
- else if (GetSize(parts) == 1)
- lut_costs.push_back(atoi(parts.at(0).c_str()));
- else if (GetSize(parts) == 2)
- while (GetSize(lut_costs) < atoi(parts.at(0).c_str()))
- lut_costs.push_back(atoi(parts.at(1).c_str()));
- else
- log_cmd_error("Invalid -luts syntax.\n");
- }
+ luts_arg = args[++argidx];
continue;
}
if (arg == "-fast") {
fast_mode = true;
continue;
}
- //if (arg == "-dff") {
- // dff_mode = true;
- // continue;
- //}
- //if (arg == "-clk" && argidx+1 < args.size()) {
- // clk_str = args[++argidx];
- // dff_mode = true;
- // continue;
- //}
- //if (arg == "-keepff") {
- // keepff = true;
- // continue;
- //}
+ if (arg == "-dff") {
+ dff_mode = true;
+ continue;
+ }
if (arg == "-nocleanup") {
cleanup = false;
continue;
@@ -1036,10 +962,6 @@ struct Abc9Pass : public Pass {
show_tempdir = true;
continue;
}
- if (arg == "-markgroups") {
- markgroups = true;
- continue;
- }
if (arg == "-box" && argidx+1 < args.size()) {
box_file = args[++argidx];
continue;
@@ -1048,251 +970,125 @@ struct Abc9Pass : public Pass {
wire_delay = "-W " + args[++argidx];
continue;
}
- if (arg == "-nomfs") {
- nomfs = true;
- continue;
- }
break;
}
extra_args(args, argidx, design);
- // ABC expects a box file for XAIG
- if (box_file.empty())
- box_file = "+/dummy.box";
-
- rewrite_filename(box_file);
- if (!box_file.empty() && !is_absolute_path(box_file))
- box_file = std::string(pwd) + "/" + box_file;
+ rewrite_filename(script_file);
+ if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
+ script_file = std::string(pwd) + "/" + script_file;
- dict<int,IdString> box_lookup;
- for (auto m : design->modules()) {
- auto it = m->attributes.find(ID(abc9_box_id));
- if (it == m->attributes.end())
- continue;
- if (m->name.begins_with("$paramod"))
- continue;
- auto id = it->second.as_int();
- auto r = box_lookup.insert(std::make_pair(id, m->name));
- if (!r.second)
- log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
- log_id(m), id, log_id(r.first->second));
- log_assert(r.second);
-
- RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
- for (auto p : m->ports) {
- auto w = m->wire(p);
- log_assert(w);
- if (w->attributes.count(ID(abc9_carry))) {
- if (w->port_input) {
- if (carry_in)
- log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
- carry_in = w;
- }
- else if (w->port_output) {
- if (carry_out)
- log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
- carry_out = w;
- }
+ // handle -lut / -luts args
+ if (!lut_arg.empty()) {
+ string arg = lut_arg;
+ if (arg.find_first_not_of("0123456789:") == std::string::npos) {
+ size_t pos = arg.find_first_of(':');
+ int lut_mode = 0, lut_mode2 = 0;
+ if (pos != string::npos) {
+ lut_mode = atoi(arg.substr(0, pos).c_str());
+ lut_mode2 = atoi(arg.substr(pos+1).c_str());
+ } else {
+ lut_mode = atoi(arg.c_str());
+ lut_mode2 = lut_mode;
}
+ lut_costs.clear();
+ for (int i = 0; i < lut_mode; i++)
+ lut_costs.push_back(1);
+ for (int i = lut_mode; i < lut_mode2; i++)
+ lut_costs.push_back(2 << (i - lut_mode));
}
- if (carry_in || carry_out) {
- if (carry_in && !carry_out)
- log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m));
- if (!carry_in && carry_out)
- log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m));
- // Make carry_in the last PI, and carry_out the last PO
- // since ABC requires it this way
- auto &ports = m->ports;
- for (auto it = ports.begin(); it != ports.end(); ) {
- RTLIL::Wire* w = m->wire(*it);
- log_assert(w);
- if (w == carry_in || w == carry_out) {
- it = ports.erase(it);
- continue;
- }
- if (w->port_id > carry_in->port_id)
- --w->port_id;
- if (w->port_id > carry_out->port_id)
- --w->port_id;
- log_assert(w->port_input || w->port_output);
- log_assert(ports[w->port_id-1] == w->name);
- ++it;
- }
- ports.push_back(carry_in->name);
- carry_in->port_id = ports.size();
- ports.push_back(carry_out->name);
- carry_out->port_id = ports.size();
+ else {
+ lut_file = arg;
+ rewrite_filename(lut_file);
+ if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+')
+ lut_file = std::string(pwd) + "/" + lut_file;
}
}
-
- for (auto mod : design->selected_modules())
- {
- if (mod->attributes.count(ID(abc9_box_id)))
- continue;
-
- if (mod->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", log_id(mod));
- continue;
+ if (!luts_arg.empty()) {
+ lut_costs.clear();
+ for (auto &tok : split_tokens(luts_arg, ",")) {
+ auto parts = split_tokens(tok, ":");
+ if (GetSize(parts) == 0 && !lut_costs.empty())
+ lut_costs.push_back(lut_costs.back());
+ else if (GetSize(parts) == 1)
+ lut_costs.push_back(atoi(parts.at(0).c_str()));
+ else if (GetSize(parts) == 2)
+ while (GetSize(lut_costs) < atoi(parts.at(0).c_str()))
+ lut_costs.push_back(atoi(parts.at(1).c_str()));
+ else
+ log_cmd_error("Invalid -luts syntax.\n");
}
+ }
+
+ // ABC expects a box file for XAIG
+ if (box_file.empty())
+ box_file = "+/dummy.box";
- assign_map.set(mod);
+ rewrite_filename(box_file);
+ if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
+ box_file = std::string(pwd) + "/" + box_file;
- if (!dff_mode || !clk_str.empty()) {
- 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);
+ SigMap assign_map;
+ CellTypes ct(design);
+ for (auto module : design->selected_modules())
+ {
+ if (module->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(module));
continue;
}
+ log_assert(!module->attributes.count(ID(abc9_box_id)));
- CellTypes ct(design);
-
- std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
- std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
-
- std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
- std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
- std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
-
- typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
- std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
- std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
-
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
-
- for (auto cell : all_cells)
- {
- clkdomain_t key;
-
- for (auto &conn : cell->connections())
- for (auto bit : conn.second) {
- bit = assign_map(bit);
- if (bit.wire != nullptr) {
- cell_to_bit[cell].insert(bit);
- bit_to_cell[bit].insert(cell);
- if (ct.cell_input(cell->type, conn.first)) {
- cell_to_bit_up[cell].insert(bit);
- bit_to_cell_down[bit].insert(cell);
- }
- if (ct.cell_output(cell->type, conn.first)) {
- cell_to_bit_down[cell].insert(bit);
- bit_to_cell_up[bit].insert(cell);
- }
- }
- }
-
- if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
- {
- key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec());
- }
- else
- if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
- {
- bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
- bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
- key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E))));
- }
- else
- continue;
-
- unassigned_cells.erase(cell);
- expand_queue.insert(cell);
- expand_queue_up.insert(cell);
- expand_queue_down.insert(cell);
+ if (!design->selected_whole_module(module))
+ log_error("Can't handle partially selected module %s!\n", log_id(module));
- assigned_cells[key].push_back(cell);
- assigned_cells_reverse[cell] = key;
- }
+ assign_map.set(module);
- while (!expand_queue_up.empty() || !expand_queue_down.empty())
- {
- if (!expand_queue_up.empty())
- {
- RTLIL::Cell *cell = *expand_queue_up.begin();
- clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue_up.erase(cell);
-
- for (auto bit : cell_to_bit_up[cell])
- for (auto c : bit_to_cell_up[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue_up.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- expand_queue.insert(c);
- }
- }
+ typedef SigSpec clkdomain_t;
+ dict<clkdomain_t, int> clk_to_mergeability;
- if (!expand_queue_down.empty())
- {
- RTLIL::Cell *cell = *expand_queue_down.begin();
- clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue_down.erase(cell);
-
- for (auto bit : cell_to_bit_down[cell])
- for (auto c : bit_to_cell_down[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue_up.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- expand_queue.insert(c);
- }
- }
+ if (dff_mode)
+ for (auto cell : module->cells()) {
+ if (cell->type != "$__ABC9_FF_")
+ continue;
- if (expand_queue_up.empty() && expand_queue_down.empty()) {
- expand_queue_up.swap(next_expand_queue_up);
- expand_queue_down.swap(next_expand_queue_down);
+ Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
+ if (abc9_clock_wire == NULL)
+ log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+ SigSpec abc9_clock = assign_map(abc9_clock_wire);
+
+ clkdomain_t key(abc9_clock);
+
+ auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
+ auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second));
+ log_assert(r2.second);
+
+ Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str()));
+ if (abc9_init_wire == NULL)
+ log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+ log_assert(GetSize(abc9_init_wire) == 1);
+ SigSpec abc9_init = assign_map(abc9_init_wire);
+ if (!abc9_init.is_fully_const())
+ log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+ if (abc9_init == State::S1)
+ log_error("'%s.init' in module '%s' has value 1'b1 which is not supported by 'abc9 -dff'.\n", cell->name.c_str(), log_id(module));
+ r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
+ log_assert(r2.second);
}
- }
-
- while (!expand_queue.empty())
- {
- RTLIL::Cell *cell = *expand_queue.begin();
- clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue.erase(cell);
-
- for (auto bit : cell_to_bit.at(cell)) {
- for (auto c : bit_to_cell[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- }
- bit_to_cell[bit].clear();
+ else
+ for (auto cell : module->cells()) {
+ auto inst_module = design->module(cell->type);
+ if (!inst_module || !inst_module->get_bool_attribute("\\abc9_flop"))
+ continue;
+ cell->set_bool_attribute("\\abc9_keep");
}
- if (expand_queue.empty())
- expand_queue.swap(next_expand_queue);
- }
-
- clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
- for (auto cell : unassigned_cells) {
- assigned_cells[key].push_back(cell);
- assigned_cells_reverse[cell] = key;
- }
-
- log_header(design, "Summary of detected clock domains:\n");
- for (auto &it : assigned_cells)
- log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
- std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
- std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
-
- for (auto &it : assigned_cells) {
- clk_polarity = std::get<0>(it.first);
- 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(), "$",
- keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
- box_file, lut_file, wire_delay, box_lookup, nomfs);
- assign_map.set(mod);
- }
+ design->selected_active_module = module->name.str();
+ abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, dff_mode,
+ delay_target, lutin_shared, fast_mode, show_tempdir,
+ box_file, lut_file, wire_delay);
+ design->selected_active_module.clear();
}
- assign_map.clear();
-
log_pop();
}
} Abc9Pass;
diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc
index 246932d81..b9cd68883 100644
--- a/passes/techmap/clkbufmap.cc
+++ b/passes/techmap/clkbufmap.cc
@@ -115,6 +115,8 @@ struct ClkbufmapPass : public Pass {
// Cell type, port name, bit index.
pool<pair<IdString, pair<IdString, int>>> sink_ports;
pool<pair<IdString, pair<IdString, int>>> buf_ports;
+ dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out;
+ dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in;
// Process submodules before module using them.
std::vector<Module *> modules_sorted;
@@ -133,6 +135,14 @@ struct ClkbufmapPass : public Pass {
if (wire->get_bool_attribute("\\clkbuf_sink"))
for (int i = 0; i < GetSize(wire); i++)
sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
+ auto it = wire->attributes.find("\\clkbuf_inv");
+ if (it != wire->attributes.end()) {
+ IdString in_name = RTLIL::escape_id(it->second.decode_string());
+ for (int i = 0; i < GetSize(wire); i++) {
+ inv_ports_out[make_pair(module->name, make_pair(wire->name, i))] = make_pair(in_name, i);
+ inv_ports_in[make_pair(module->name, make_pair(in_name, i))] = make_pair(wire->name, i);
+ }
+ }
}
continue;
}
@@ -157,6 +167,37 @@ struct ClkbufmapPass : public Pass {
if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
buf_wire_bits.insert(sigmap(port.second[i]));
+ // Third, propagate tags through inverters.
+ bool retry = true;
+ while (retry) {
+ retry = false;
+ for (auto cell : module->cells())
+ for (auto port : cell->connections())
+ for (int i = 0; i < port.second.size(); i++) {
+ auto it = inv_ports_out.find(make_pair(cell->type, make_pair(port.first, i)));
+ auto bit = sigmap(port.second[i]);
+ // If output of an inverter is connected to a sink, mark it as buffered,
+ // and request a buffer on the inverter's input instead.
+ if (it != inv_ports_out.end() && !buf_wire_bits.count(bit) && sink_wire_bits.count(bit)) {
+ buf_wire_bits.insert(bit);
+ auto other_bit = sigmap(cell->getPort(it->second.first)[it->second.second]);
+ sink_wire_bits.insert(other_bit);
+ retry = true;
+ }
+ // If input of an inverter is marked as already-buffered,
+ // mark its output already-buffered as well.
+ auto it2 = inv_ports_in.find(make_pair(cell->type, make_pair(port.first, i)));
+ if (it2 != inv_ports_in.end() && buf_wire_bits.count(bit)) {
+ auto other_bit = sigmap(cell->getPort(it2->second.first)[it2->second.second]);
+ if (!buf_wire_bits.count(other_bit)) {
+ buf_wire_bits.insert(other_bit);
+ retry = true;
+ }
+ }
+
+ }
+ };
+
// Collect all driven bits.
for (auto cell : module->cells())
for (auto port : cell->connections())
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index c868b9a87..531ac2b99 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -87,11 +87,11 @@ struct IopadmapPass : public Pass {
{
log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
- std::string inpad_celltype, inpad_portname, inpad_portname2;
- std::string outpad_celltype, outpad_portname, outpad_portname2;
- std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2;
- std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3;
- std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4;
+ std::string inpad_celltype, inpad_portname_o, inpad_portname_pad;
+ std::string outpad_celltype, outpad_portname_i, outpad_portname_pad;
+ std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad;
+ std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad;
+ std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad;
std::string widthparam, nameparam;
pool<pair<IdString, IdString>> ignore;
bool flag_bits = false;
@@ -102,35 +102,35 @@ struct IopadmapPass : public Pass {
std::string arg = args[argidx];
if (arg == "-inpad" && argidx+2 < args.size()) {
inpad_celltype = args[++argidx];
- inpad_portname = args[++argidx];
- split_portname_pair(inpad_portname, inpad_portname2);
+ inpad_portname_o = args[++argidx];
+ split_portname_pair(inpad_portname_o, inpad_portname_pad);
continue;
}
if (arg == "-outpad" && argidx+2 < args.size()) {
outpad_celltype = args[++argidx];
- outpad_portname = args[++argidx];
- split_portname_pair(outpad_portname, outpad_portname2);
+ outpad_portname_i = args[++argidx];
+ split_portname_pair(outpad_portname_i, outpad_portname_pad);
continue;
}
if (arg == "-inoutpad" && argidx+2 < args.size()) {
inoutpad_celltype = args[++argidx];
- inoutpad_portname = args[++argidx];
- split_portname_pair(inoutpad_portname, inoutpad_portname2);
+ inoutpad_portname_io = args[++argidx];
+ split_portname_pair(inoutpad_portname_io, inoutpad_portname_pad);
continue;
}
if (arg == "-toutpad" && argidx+2 < args.size()) {
toutpad_celltype = args[++argidx];
- toutpad_portname = args[++argidx];
- split_portname_pair(toutpad_portname, toutpad_portname2);
- split_portname_pair(toutpad_portname2, toutpad_portname3);
+ toutpad_portname_oe = args[++argidx];
+ split_portname_pair(toutpad_portname_oe, toutpad_portname_i);
+ split_portname_pair(toutpad_portname_i, toutpad_portname_pad);
continue;
}
if (arg == "-tinoutpad" && argidx+2 < args.size()) {
tinoutpad_celltype = args[++argidx];
- tinoutpad_portname = args[++argidx];
- split_portname_pair(tinoutpad_portname, tinoutpad_portname2);
- split_portname_pair(tinoutpad_portname2, tinoutpad_portname3);
- split_portname_pair(tinoutpad_portname3, tinoutpad_portname4);
+ tinoutpad_portname_oe = args[++argidx];
+ split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o);
+ split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i);
+ split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad);
continue;
}
if (arg == "-ignore" && argidx+2 < args.size()) {
@@ -161,16 +161,16 @@ struct IopadmapPass : public Pass {
}
extra_args(args, argidx, design);
- if (!inpad_portname2.empty())
- ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2)));
- if (!outpad_portname2.empty())
- ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2)));
- if (!inoutpad_portname2.empty())
- ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2)));
- if (!toutpad_portname3.empty())
- ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3)));
- if (!tinoutpad_portname4.empty())
- ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4)));
+ if (!inpad_portname_pad.empty())
+ ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname_pad)));
+ if (!outpad_portname_pad.empty())
+ ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname_pad)));
+ if (!inoutpad_portname_pad.empty())
+ ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname_pad)));
+ if (!toutpad_portname_pad.empty())
+ ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname_pad)));
+ if (!tinoutpad_portname_pad.empty())
+ ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname_pad)));
for (auto module : design->modules())
if (module->get_blackbox_attribute())
@@ -180,148 +180,130 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
- dict<IdString, pool<int>> skip_wires;
pool<SigBit> skip_wire_bits;
- SigMap sigmap(module);
+ dict<Wire *, dict<int, pair<Cell *, IdString>>> rewrite_bits;
for (auto cell : module->cells())
for (auto port : cell->connections())
if (ignore.count(make_pair(cell->type, port.first)))
- for (auto bit : sigmap(port.second))
+ for (auto bit : port.second)
skip_wire_bits.insert(bit);
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
- dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
- pool<pair<IdString, IdString>> norewrites;
- SigMap rewrites;
+ dict<SigBit, Cell *> tbuf_bits;
+ pool<SigBit> driven_bits;
+ // Gather tristate buffers and always-on drivers.
for (auto cell : module->cells())
if (cell->type == ID($_TBUF_)) {
- SigBit bit = sigmap(cell->getPort(ID::Y).as_bit());
- tbuf_bits[bit].first = cell->name;
+ SigBit bit = cell->getPort(ID::Y).as_bit();
+ tbuf_bits[bit] = cell;
+ } else {
+ for (auto port : cell->connections())
+ if (!cell->known() || cell->output(port.first))
+ for (auto bit : port.second)
+ driven_bits.insert(bit);
}
- for (auto cell : module->cells())
- for (auto port : cell->connections())
- for (auto bit : sigmap(port.second))
- if (tbuf_bits.count(bit))
- tbuf_bits.at(bit).second.insert(cell->name);
+ // If a wire is a target of an assignment, it is driven, unless the source is 'z.
+ for (auto &conn : module->connections())
+ for (int i = 0; i < GetSize(conn.first); i++) {
+ SigBit dstbit = conn.first[i];
+ SigBit srcbit = conn.second[i];
+ if (!srcbit.wire && srcbit.data == State::Sz)
+ continue;
+ driven_bits.insert(dstbit);
+ }
for (auto wire : module->selected_wires())
{
if (!wire->port_output)
continue;
+ // Don't handle inout ports if we have no suitable buffer type.
+ if (wire->port_input && tinoutpad_celltype.empty())
+ continue;
+
+ // likewise for output ports.
+ if (!wire->port_input && toutpad_celltype.empty())
+ continue;
+
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wire_bit(wire, i);
- SigBit mapped_wire_bit = sigmap(wire_bit);
-
- if (tbuf_bits.count(mapped_wire_bit) == 0)
- continue;
-
- if (skip_wire_bits.count(mapped_wire_bit))
- continue;
-
- auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
- Cell *tbuf_cell = module->cell(tbuf_cache.first);
+ Cell *tbuf_cell = nullptr;
- if (tbuf_cell == nullptr)
+ if (skip_wire_bits.count(wire_bit))
continue;
- SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit();
- SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit();
+ if (tbuf_bits.count(wire_bit))
+ tbuf_cell = tbuf_bits.at(wire_bit);
+
+ SigBit en_sig;
+ SigBit data_sig;
+ bool is_driven = driven_bits.count(wire_bit);
+
+ if (tbuf_cell != nullptr) {
+ // Found a tristate buffer — use it.
+ en_sig = tbuf_cell->getPort(ID(E)).as_bit();
+ data_sig = tbuf_cell->getPort(ID::A).as_bit();
+ } else if (is_driven) {
+ // No tristate buffer, but an always-on driver is present.
+ // If this is an inout port, we're creating a tinoutpad
+ // anyway, just with a constant 1 as enable.
+ if (!wire->port_input)
+ continue;
+ en_sig = SigBit(State::S1);
+ data_sig = wire_bit;
+ } else {
+ // No driver on a wire. Create a tristate pad with always-0
+ // enable.
+ en_sig = SigBit(State::S0);
+ data_sig = SigBit(State::Sx);
+ }
- if (wire->port_input && !tinoutpad_celltype.empty())
+ if (wire->port_input)
{
log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str());
Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(tinoutpad_celltype));
- Wire *owire = module->addWire(NEW_ID);
- cell->setPort(RTLIL::escape_id(tinoutpad_portname), en_sig);
- cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire);
- cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig);
- cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
- for (auto cn : tbuf_cache.second) {
- auto c = module->cell(cn);
- if (c == nullptr)
- continue;
- for (auto port : c->connections()) {
- SigSpec sig = port.second;
- bool newsig = false;
- for (auto &bit : sig)
- if (sigmap(bit) == mapped_wire_bit) {
- bit = owire;
- newsig = true;
- }
- if (newsig)
- c->setPort(port.first, sig);
- }
+ if (tbuf_cell) {
+ module->remove(tbuf_cell);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
+ } else if (is_driven) {
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), wire_bit);
+ } else {
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
}
-
-
- module->remove(tbuf_cell);
- skip_wires[wire->name].insert(i);
-
- norewrites.insert(make_pair(cell->name, RTLIL::escape_id(tinoutpad_portname4)));
- rewrites.add(sigmap(wire_bit), owire);
- continue;
- }
-
- if (!wire->port_input && !toutpad_celltype.empty())
- {
+ skip_wire_bits.insert(wire_bit);
+ if (!tinoutpad_portname_pad.empty())
+ rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
+ } else {
log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str());
Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(toutpad_celltype));
- cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig);
- cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig);
- cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit);
+ cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig);
+ cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
- for (auto cn : tbuf_cache.second) {
- auto c = module->cell(cn);
- if (c == nullptr)
- continue;
- for (auto port : c->connections()) {
- SigSpec sig = port.second;
- bool newsig = false;
- for (auto &bit : sig)
- if (sigmap(bit) == mapped_wire_bit) {
- bit = data_sig;
- newsig = true;
- }
- if (newsig)
- c->setPort(port.first, sig);
- }
+ if (tbuf_cell) {
+ module->remove(tbuf_cell);
+ module->connect(wire_bit, data_sig);
}
-
- module->remove(tbuf_cell);
- skip_wires[wire->name].insert(i);
- continue;
+ skip_wire_bits.insert(wire_bit);
+ if (!toutpad_portname_pad.empty())
+ rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(toutpad_portname_pad));
}
}
}
-
- if (GetSize(norewrites))
- {
- for (auto cell : module->cells())
- for (auto port : cell->connections())
- {
- if (norewrites.count(make_pair(cell->name, port.first)))
- continue;
-
- SigSpec orig_sig = sigmap(port.second);
- SigSpec new_sig = rewrites(orig_sig);
-
- if (orig_sig != new_sig)
- cell->setPort(port.first, new_sig);
- }
- }
}
for (auto wire : module->selected_wires())
@@ -329,17 +311,11 @@ struct IopadmapPass : public Pass {
if (!wire->port_id)
continue;
- std::string celltype, portname, portname2;
+ std::string celltype, portname_int, portname_pad;
pool<int> skip_bit_indices;
- if (skip_wires.count(wire->name)) {
- if (!flag_bits)
- continue;
- skip_bit_indices = skip_wires.at(wire->name);
- }
-
for (int i = 0; i < GetSize(wire); i++)
- if (skip_wire_bits.count(sigmap(SigBit(wire, i))))
+ if (skip_wire_bits.count(SigBit(wire, i)))
skip_bit_indices.insert(i);
if (GetSize(wire) == GetSize(skip_bit_indices))
@@ -351,8 +327,8 @@ struct IopadmapPass : public Pass {
continue;
}
celltype = inpad_celltype;
- portname = inpad_portname;
- portname2 = inpad_portname2;
+ portname_int = inpad_portname_o;
+ portname_pad = inpad_portname_pad;
} else
if (!wire->port_input && wire->port_output) {
if (outpad_celltype.empty()) {
@@ -360,8 +336,8 @@ struct IopadmapPass : public Pass {
continue;
}
celltype = outpad_celltype;
- portname = outpad_portname;
- portname2 = outpad_portname2;
+ portname_int = outpad_portname_i;
+ portname_pad = outpad_portname_pad;
} else
if (wire->port_input && wire->port_output) {
if (inoutpad_celltype.empty()) {
@@ -369,8 +345,8 @@ struct IopadmapPass : public Pass {
continue;
}
celltype = inoutpad_celltype;
- portname = inoutpad_portname;
- portname2 = inoutpad_portname2;
+ portname_int = inoutpad_portname_io;
+ portname_pad = inoutpad_portname_pad;
} else
log_abort();
@@ -381,29 +357,20 @@ struct IopadmapPass : public Pass {
log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str());
- RTLIL::Wire *new_wire = NULL;
- if (!portname2.empty()) {
- new_wire = module->addWire(NEW_ID, wire);
- module->swap_names(new_wire, wire);
- wire->attributes.clear();
- }
-
if (flag_bits)
{
for (int i = 0; i < wire->width; i++)
{
- if (skip_bit_indices.count(i)) {
- if (wire->port_output)
- module->connect(SigSpec(new_wire, i), SigSpec(wire, i));
- else
- module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
+ if (skip_bit_indices.count(i))
continue;
- }
+
+ SigBit wire_bit(wire, i);
RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
- cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i));
- if (!portname2.empty())
- cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire, i));
+ cell->setPort(RTLIL::escape_id(portname_int), wire_bit);
+
+ if (!portname_pad.empty())
+ rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(portname_pad));
if (!widthparam.empty())
cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
if (!nameparam.empty())
@@ -414,9 +381,15 @@ struct IopadmapPass : public Pass {
else
{
RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
- cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire));
- if (!portname2.empty())
- cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire));
+ cell->setPort(RTLIL::escape_id(portname_int), RTLIL::SigSpec(wire));
+
+ if (!portname_pad.empty()) {
+ RTLIL::Wire *new_wire = NULL;
+ new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(new_wire, wire);
+ wire->attributes.clear();
+ cell->setPort(RTLIL::escape_id(portname_pad), RTLIL::SigSpec(new_wire));
+ }
if (!widthparam.empty())
cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
if (!nameparam.empty())
@@ -424,6 +397,32 @@ struct IopadmapPass : public Pass {
cell->attributes[ID::keep] = RTLIL::Const(1);
}
+ if (!rewrite_bits.count(wire)) {
+ wire->port_id = 0;
+ wire->port_input = false;
+ wire->port_output = false;
+ }
+ }
+
+ for (auto &it : rewrite_bits) {
+ RTLIL::Wire *wire = it.first;
+ RTLIL::Wire *new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(new_wire, wire);
+ wire->attributes.clear();
+ for (int i = 0; i < wire->width; i++)
+ {
+ SigBit wire_bit(wire, i);
+ if (!it.second.count(i)) {
+ if (wire->port_output)
+ module->connect(SigSpec(new_wire, i), SigSpec(wire, i));
+ else
+ module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
+ } else {
+ auto &new_conn = it.second.at(i);
+ new_conn.first->setPort(new_conn.second, RTLIL::SigSpec(new_wire, i));
+ }
+ }
+
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;