summaryrefslogtreecommitdiff
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/check.cc2
-rw-r--r--passes/cmds/connwrappers.cc2
-rw-r--r--passes/cmds/cover.cc2
-rw-r--r--passes/cmds/plugin.cc8
-rw-r--r--passes/cmds/qwp.cc32
-rw-r--r--passes/cmds/scc.cc8
-rw-r--r--passes/cmds/select.cc42
-rw-r--r--passes/cmds/setattr.cc6
-rw-r--r--passes/cmds/setundef.cc94
-rw-r--r--passes/cmds/show.cc18
-rw-r--r--passes/cmds/splice.cc2
-rw-r--r--passes/cmds/splitnets.cc2
-rw-r--r--passes/cmds/stat.cc2
-rw-r--r--passes/cmds/tee.cc10
-rw-r--r--passes/cmds/torder.cc2
-rw-r--r--passes/equiv/equiv_induct.cc2
-rw-r--r--passes/equiv/equiv_make.cc2
-rw-r--r--passes/equiv/equiv_mark.cc2
-rw-r--r--passes/equiv/equiv_miter.cc2
-rw-r--r--passes/equiv/equiv_purge.cc2
-rw-r--r--passes/equiv/equiv_remove.cc2
-rw-r--r--passes/equiv/equiv_simple.cc2
-rw-r--r--passes/equiv/equiv_status.cc2
-rw-r--r--passes/equiv/equiv_struct.cc2
-rw-r--r--passes/fsm/fsm.cc2
-rw-r--r--passes/fsm/fsm_detect.cc139
-rw-r--r--passes/fsm/fsm_expand.cc2
-rw-r--r--passes/fsm/fsm_export.cc2
-rw-r--r--passes/fsm/fsm_extract.cc9
-rw-r--r--passes/fsm/fsm_info.cc2
-rw-r--r--passes/fsm/fsm_map.cc2
-rw-r--r--passes/fsm/fsm_opt.cc2
-rw-r--r--passes/fsm/fsm_recode.cc2
-rw-r--r--passes/hierarchy/hierarchy.cc20
-rw-r--r--passes/hierarchy/singleton.cc2
-rw-r--r--passes/hierarchy/submod.cc6
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc15
-rw-r--r--passes/memory/memory_bram.cc7
-rw-r--r--passes/memory/memory_collect.cc18
-rw-r--r--passes/memory/memory_dff.cc2
-rw-r--r--passes/memory/memory_map.cc2
-rw-r--r--passes/memory/memory_memx.cc92
-rw-r--r--passes/memory/memory_share.cc51
-rw-r--r--passes/memory/memory_unpack.cc2
-rw-r--r--passes/opt/Makefile.inc4
-rw-r--r--passes/opt/opt.cc52
-rw-r--r--passes/opt/opt_clean.cc5
-rw-r--r--passes/opt/opt_expr.cc (renamed from passes/opt/opt_const.cc)216
-rw-r--r--passes/opt/opt_merge.cc (renamed from passes/opt/opt_share.cc)70
-rw-r--r--passes/opt/opt_muxtree.cc4
-rw-r--r--passes/opt/opt_reduce.cc2
-rw-r--r--passes/opt/opt_rmdff.cc123
-rw-r--r--passes/opt/share.cc55
-rw-r--r--passes/opt/wreduce.cc31
-rw-r--r--passes/proc/proc.cc16
-rw-r--r--passes/proc/proc_arst.cc2
-rw-r--r--passes/proc/proc_clean.cc2
-rw-r--r--passes/proc/proc_dff.cc2
-rw-r--r--passes/proc/proc_dlatch.cc147
-rw-r--r--passes/proc/proc_init.cc31
-rw-r--r--passes/proc/proc_mux.cc53
-rw-r--r--passes/proc/proc_rmdead.cc6
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/assertpmux.cc240
-rw-r--r--passes/sat/eval.cc2
-rw-r--r--passes/sat/expose.cc2
-rw-r--r--passes/sat/freduce.cc2
-rw-r--r--passes/sat/miter.cc12
-rw-r--r--passes/sat/sat.cc217
-rw-r--r--passes/techmap/Makefile.inc8
-rw-r--r--passes/techmap/abc.cc216
-rw-r--r--passes/techmap/aigmap.cc2
-rw-r--r--passes/techmap/alumacc.cc2
-rw-r--r--passes/techmap/attrmap.cc250
-rw-r--r--passes/techmap/attrmvcp.cc139
-rw-r--r--passes/techmap/deminout.cc116
-rw-r--r--passes/techmap/dff2dffe.cc2
-rw-r--r--passes/techmap/dffinit.cc2
-rw-r--r--passes/techmap/dfflibmap.cc26
-rw-r--r--passes/techmap/dffsr2dff.cc2
-rw-r--r--passes/techmap/extract.cc10
-rw-r--r--passes/techmap/hilomap.cc2
-rw-r--r--passes/techmap/insbuf.cc94
-rw-r--r--passes/techmap/iopadmap.cc168
-rw-r--r--passes/techmap/lut2mux.cc2
-rw-r--r--passes/techmap/maccmap.cc2
-rw-r--r--passes/techmap/muxcover.cc2
-rw-r--r--passes/techmap/nlutmap.cc20
-rw-r--r--passes/techmap/pmuxtree.cc2
-rw-r--r--passes/techmap/shregmap.cc584
-rw-r--r--passes/techmap/simplemap.cc33
-rw-r--r--passes/techmap/techmap.cc48
-rw-r--r--passes/techmap/tribuf.cc2
-rw-r--r--passes/tests/test_autotb.cc63
-rw-r--r--passes/tests/test_cell.cc171
96 files changed, 3338 insertions, 557 deletions
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index 2ad84838..b3622cb1 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -68,7 +68,7 @@ struct CheckPass : public Pass {
}
extra_args(args, argidx, design);
- log_header("Executing CHECK pass (checking for obvious problems).\n");
+ log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
for (auto module : design->selected_whole_modules_warn())
{
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index 7828dce1..c9ab226d 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -198,7 +198,7 @@ struct ConnwrappersPass : public Pass {
}
extra_args(args, argidx, design);
- log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
+ log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 5644066a..1475475c 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -124,7 +124,7 @@ struct CoverPass : public Pass {
extra_args(args, argidx, design);
if (do_log) {
- log_header("Printing code coverage counters.\n");
+ log_header(design, "Printing code coverage counters.\n");
log("\n");
}
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index e2d80d9b..828c671d 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -31,19 +31,23 @@ std::map<std::string, std::string> loaded_plugin_aliases;
#ifdef YOSYS_ENABLE_PLUGINS
void load_plugin(std::string filename, std::vector<std::string> aliases)
{
+ std::string orig_filename = filename;
+
if (filename.find('/') == std::string::npos)
filename = "./" + filename;
if (!loaded_plugins.count(filename)) {
void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl == NULL && orig_filename.find('/') == std::string::npos)
+ hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
if (hdl == NULL)
log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
- loaded_plugins[filename] = hdl;
+ loaded_plugins[orig_filename] = hdl;
Pass::init_register();
}
for (auto &alias : aliases)
- loaded_plugin_aliases[alias] = filename;
+ loaded_plugin_aliases[alias] = orig_filename;
}
#else
void load_plugin(std::string, std::vector<std::string>)
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 8ec815a7..1b800b6d 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -40,6 +40,7 @@ struct QwpConfig
{
bool ltr;
bool alpha;
+ bool verbose;
double grid;
std::ofstream dump_file;
@@ -47,6 +48,7 @@ struct QwpConfig
QwpConfig() {
ltr = false;
alpha = false;
+ verbose = false;
grid = 1.0 / 16;
}
};
@@ -211,10 +213,16 @@ struct QwpWorker
//
// M := [AA Ay]
+ if (config.verbose)
+ log("> System size: %d^2\n", GetSize(nodes));
+
// Row major order
int N = GetSize(nodes), N1 = N+1;
vector<double> M(N * N1);
+ if (config.verbose)
+ log("> Edge constraints: %d\n", GetSize(edges));
+
// Edge constraints:
// A[i,:] := [ 0 0 .... 0 weight 0 ... 0 -weight 0 ... 0 0], y[i] := 0
//
@@ -232,6 +240,9 @@ struct QwpWorker
M[idx2 + idx1*N1] += -weight * weight;
}
+ if (config.verbose)
+ log("> Node constraints: %d\n", GetSize(nodes));
+
// Node constraints:
// A[i,:] := [ 0 0 .... 0 weight 0 ... 0 0], y[i] := weight * pos
//
@@ -263,6 +274,9 @@ struct QwpWorker
}
#endif
+ if (config.verbose)
+ log("> Solving\n");
+
// Solve "AA*x = Ay"
// (least squares fit for "A*x = y")
//
@@ -277,6 +291,9 @@ struct QwpWorker
// gaussian elimination
for (int i = 0; i < N; i++)
{
+ if (config.verbose && ((i+1) % (N/15)) == 0)
+ log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
+
// find best row
int best_row = queue.front();
int best_row_queue_idx = 0;
@@ -312,6 +329,9 @@ struct QwpWorker
}
}
+ if (config.verbose)
+ log("> Solved\n");
+
log_assert(queue.empty());
log_assert(GetSize(pivot_cache) == N);
@@ -334,6 +354,9 @@ struct QwpWorker
}
#endif
+ if (config.verbose)
+ log("> Update nodes\n");
+
// update node positions
for (int i = 0; i < N; i++)
{
@@ -778,6 +801,9 @@ struct QwpPass : public Pass {
log(" -dump <html_file_name>\n");
log(" Dump a protocol of the placement algorithm to the html file.\n");
log("\n");
+ log(" -v\n");
+ log(" Verbose solver output for profiling or debugging\n");
+ log("\n");
log("Note: This implementation of a quadratic wirelength placer uses exact\n");
log("dense matrix operations. It is only a toy-placer for small circuits.\n");
log("\n");
@@ -787,7 +813,7 @@ struct QwpPass : public Pass {
QwpConfig config;
xorshift32_state = 123456789;
- log_header("Executing QWP pass (quadratic wirelength placer).\n");
+ log_header(design, "Executing QWP pass (quadratic wirelength placer).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -799,6 +825,10 @@ struct QwpPass : public Pass {
config.alpha = true;
continue;
}
+ if (args[argidx] == "-v") {
+ config.verbose = true;
+ continue;
+ }
if (args[argidx] == "-grid" && argidx+1 < args.size()) {
config.grid = 1.0 / atoi(args[++argidx].c_str());
continue;
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index 532026f2..bb6d7447 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -181,10 +181,10 @@ struct SccWorker
cell2scc[cell] = sccList.size();
scc.insert(cell);
sccList.push_back(scc);
- workQueue.erase(cell);
log("\n");
- } else
- run(cell, 0, maxDepth);
+ }
+
+ run(cell, 0, maxDepth);
}
log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
@@ -264,7 +264,7 @@ struct SccPass : public Pass {
int maxDepth = -1;
int expect = -1;
- log_header("Executing SCC pass (detecting logic loops).\n");
+ log_header(design, "Executing SCC pass (detecting logic loops).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 3e64dd84..d2e1a2e2 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -952,7 +952,7 @@ struct SelectPass : public Pass {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
- log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n");
+ log(" select [ <assert_option> ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
log("\n");
@@ -988,6 +988,14 @@ struct SelectPass : public Pass {
log(" do not modify the current selection. instead assert that the given\n");
log(" selection contains exactly N objects.\n");
log("\n");
+ log(" -assert-max N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains less than or exactly N objects.\n");
+ log("\n");
+ log(" -assert-min N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains at least N objects.\n");
+ log("\n");
log(" -list\n");
log(" list all objects in the current selection\n");
log("\n");
@@ -1168,6 +1176,8 @@ struct SelectPass : public Pass {
bool assert_none = false;
bool assert_any = false;
int assert_count = -1;
+ int assert_max = -1;
+ int assert_min = -1;
std::string write_file, read_file;
std::string set_name, sel_str;
@@ -1197,6 +1207,14 @@ struct SelectPass : public Pass {
assert_count = atoi(args[++argidx].c_str());
continue;
}
+ if (arg == "-assert-max" && argidx+1 < args.size()) {
+ assert_max = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (arg == "-assert-min" && argidx+1 < args.size()) {
+ assert_min = atoi(args[++argidx].c_str());
+ continue;
+ }
if (arg == "-clear") {
clear_mode = true;
continue;
@@ -1273,14 +1291,14 @@ struct SelectPass : public Pass {
if (none_mode && args.size() != 2)
log_cmd_error("Option -none can not be combined with any other options.\n");
- if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) > 1)
- log_cmd_error("Options -add, -del, -assert-none, -assert-any or -assert-count can not be combined.\n");
+ if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) + (assert_max >= 0) + (assert_min >= 0) > 1)
+ log_cmd_error("Options -add, -del, -assert-none, -assert-any, assert-count, -assert-max or -assert-min can not be combined.\n");
- if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
- log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any or -assert-count.\n");
+ if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any, assert-count, -assert-max, or -assert-min.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any or -assert-count.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1385,7 +1403,7 @@ struct SelectPass : public Pass {
return;
}
- if (assert_count >= 0)
+ if (assert_count >= 0 || assert_max >= 0 || assert_min >= 0)
{
int total_count = 0;
if (work_stack.size() == 0)
@@ -1407,9 +1425,15 @@ struct SelectPass : public Pass {
if (sel->selected_member(mod_it.first, it.first))
total_count++;
}
- if (assert_count != total_count)
+ if (assert_count >= 0 && assert_count != total_count)
log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n",
total_count, assert_count, sel_str.c_str());
+ if (assert_max >= 0 && assert_max < total_count)
+ log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n",
+ total_count, assert_max, sel_str.c_str());
+ if (assert_min >= 0 && assert_min > total_count)
+ log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n",
+ total_count, assert_min, sel_str.c_str());
return;
}
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 75c738b6..9b05ae32 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -215,6 +215,12 @@ struct ChparamPass : public Pass {
}
break;
}
+
+ for (int i = argidx; i < GetSize(args); i++)
+ if (design->module("$abstract\\" + args[i]) != nullptr &&
+ design->module(RTLIL::escape_id(args[i])) == nullptr)
+ args[i] = "$abstract\\" + args[i];
+
extra_args(args, argidx, design);
do_setunset(new_parameters, setunset_list);
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 9ca2e874..26b2eb87 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -79,11 +79,15 @@ struct SetundefPass : public Pass {
log(" replace with random bits using the specified integer als seed\n");
log(" value for the random number generator.\n");
log("\n");
+ log(" -init\n");
+ log(" also create/update init values for flip-flops\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
bool got_value = false;
bool undriven_mode = false;
+ bool init_mode = false;
SetundefWorker worker;
size_t argidx;
@@ -103,6 +107,10 @@ struct SetundefPass : public Pass {
worker.next_bit_mode = 1;
continue;
}
+ if (args[argidx] == "-init") {
+ init_mode = true;
+ continue;
+ }
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
worker.next_bit_mode = 2;
@@ -118,12 +126,8 @@ struct SetundefPass : public Pass {
if (!got_value)
log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = mod_it.second;
- if (!design->selected(module))
- continue;
-
if (undriven_mode)
{
if (!module->processes.empty())
@@ -151,6 +155,86 @@ struct SetundefPass : public Pass {
}
}
+ if (init_mode)
+ {
+ SigMap sigmap(module);
+ pool<SigBit> ffbits;
+ pool<Wire*> initwires;
+
+ pool<IdString> fftypes;
+ fftypes.insert("$dff");
+ fftypes.insert("$dffe");
+ fftypes.insert("$dffsr");
+ fftypes.insert("$adff");
+
+ std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
+
+ for (auto c1 : list_np)
+ fftypes.insert(stringf("$_DFF_%c_", c1));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ fftypes.insert(stringf("$_DFFE_%c%c_", c1, c2));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_01)
+ fftypes.insert(stringf("$_DFF_%c%c%c_", c1, c2, c3));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_np)
+ fftypes.insert(stringf("$_DFFSR_%c%c%c_", c1, c2, c3));
+
+ for (auto cell : module->cells())
+ {
+ if (!fftypes.count(cell->type))
+ continue;
+
+ for (auto bit : sigmap(cell->getPort("\\Q")))
+ ffbits.insert(bit);
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!wire->attributes.count("\\init"))
+ continue;
+
+ for (auto bit : sigmap(wire))
+ ffbits.erase(bit);
+
+ initwires.insert(wire);
+ }
+
+ for (int wire_types = 0; wire_types < 2; wire_types++)
+ for (auto wire : module->wires())
+ {
+ if (wire->name[0] == (wire_types ? '\\' : '$'))
+ next_wire:
+ continue;
+
+ for (auto bit : sigmap(wire))
+ if (!ffbits.count(bit))
+ goto next_wire;
+
+ for (auto bit : sigmap(wire))
+ ffbits.erase(bit);
+
+ initwires.insert(wire);
+ }
+
+ for (auto wire : initwires)
+ {
+ Const &initval = wire->attributes["\\init"];
+
+ for (int i = 0; i < GetSize(wire); i++)
+ if (GetSize(initval) <= i)
+ initval.bits.push_back(worker.next_bit());
+ else if (initval.bits[i] == State::Sx)
+ initval.bits[i] = worker.next_bit();
+ }
+ }
+
module->rewrite_sigspecs(worker);
}
}
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 3b03d680..3a3939a8 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -582,8 +582,9 @@ struct ShowPass : public Pass {
log(" Run the specified command with the graphics file as parameter.\n");
log("\n");
log(" -format <format>\n");
- log(" Generate a graphics file in the specified format.\n");
- log(" Usually <format> is 'svg' or 'ps'.\n");
+ log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
+ log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
+ log(" to generate files in other formats (this calls the 'dot' command).\n");
log("\n");
log(" -lib <verilog_or_ilang_file>\n");
log(" Use the specified library file for determining whether cell ports are\n");
@@ -646,12 +647,13 @@ struct ShowPass : public Pass {
log("unless another prefix is specified using -prefix <prefix>.\n");
log("\n");
log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
- log("to 'show.dot' in the current directory and new viewer is launched.\n");
+ log("to 'show.dot' in the current directory and new viewer is launched each time\n");
+ log("the 'show' command is executed.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Generating Graphviz representation of design.\n");
+ log_header(design, "Generating Graphviz representation of design.\n");
log_push();
std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
@@ -759,7 +761,7 @@ struct ShowPass : public Pass {
}
extra_args(args, argidx, design);
- if (format != "ps") {
+ if (format != "ps" && format != "dot") {
int modcount = 0;
for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox"))
@@ -770,7 +772,7 @@ struct ShowPass : public Pass {
modcount++;
}
if (modcount > 1)
- log_cmd_error("For formats different than 'ps' only one module must be selected.\n");
+ log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
}
for (auto filename : libfiles) {
@@ -784,7 +786,7 @@ struct ShowPass : public Pass {
}
if (libs.size() > 0)
- log_header("Continuing show pass.\n");
+ log_header(design, "Continuing show pass.\n");
std::string dot_file = stringf("%s.dot", prefix.c_str());
std::string out_file = stringf("%s.%s", prefix.c_str(), format.empty() ? "svg" : format.c_str());
@@ -806,7 +808,7 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s -o '%s.new' '%s' && mv '%s.new' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str());
+ std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 2556fb74..7418ec4d 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -341,7 +341,7 @@ struct SplicePass : public Pass {
if (!ports.empty() && !no_ports.empty())
log_cmd_error("The options -port and -no_port are exclusive!\n");
- log_header("Executing SPLICE pass (creating cells for signal splicing).\n");
+ log_header(design, "Executing SPLICE pass (creating cells for signal splicing).\n");
for (auto &mod_it : design->modules_)
{
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 0d7892d7..14eeb066 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -109,7 +109,7 @@ struct SplitnetsPass : public Pass {
bool flag_driver = false;
std::string format = "[]:";
- log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n");
+ log_header(design, "Executing SPLITNETS pass (splitting up multi-bit signals).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 048933fc..362a0edf 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -232,7 +232,7 @@ struct StatPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Printing statistics.\n");
+ log_header(design, "Printing statistics.\n");
bool width_mode = false;
RTLIL::Module *top_mod = NULL;
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index a0484090..3db2dbf0 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -45,10 +45,14 @@ struct TeePass : public Pass {
log(" -a logfile\n");
log(" Write output to this file, append if exists.\n");
log("\n");
+ log(" +INT, -INT\n");
+ log(" Add/subract INT from the -v setting for this command.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::vector<FILE*> backup_log_files, files_to_close;
+ int backup_log_verbose_level = log_verbose_level;
backup_log_files = log_files;
size_t argidx;
@@ -70,6 +74,10 @@ struct TeePass : public Pass {
files_to_close.push_back(f);
continue;
}
+ if (GetSize(args[argidx]) >= 2 && (args[argidx][0] == '-' || args[argidx][0] == '+') && args[argidx][1] >= '0' && args[argidx][1] <= '9') {
+ log_verbose_level += atoi(args[argidx].c_str());
+ continue;
+ }
break;
}
@@ -85,6 +93,8 @@ struct TeePass : public Pass {
for (auto cf : files_to_close)
fclose(cf);
+
+ log_verbose_level = backup_log_verbose_level;
log_files = backup_log_files;
}
} TeePass;
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
index 50317c02..56223610 100644
--- a/passes/cmds/torder.cc
+++ b/passes/cmds/torder.cc
@@ -48,7 +48,7 @@ struct TorderPass : public Pass {
bool noautostop = false;
dict<IdString, pool<IdString>> stop_db;
- log_header("Executing TORDER pass (print cells in topological order).\n");
+ log_header(design, "Executing TORDER pass (print cells in topological order).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index cdb951ec..c958c3de 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -198,7 +198,7 @@ struct EquivInductPass : public Pass {
bool model_undef = false;
int max_seq = 4;
- log_header("Executing EQUIV_INDUCT pass.\n");
+ log_header(design, "Executing EQUIV_INDUCT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 8b063c54..40ca4262 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -464,7 +464,7 @@ struct EquivMakePass : public Pass {
worker.read_blacklists();
worker.read_encfiles();
- log_header("Executing EQUIV_MAKE pass (creating equiv checking module).\n");
+ log_header(design, "Executing EQUIV_MAKE pass (creating equiv checking module).\n");
worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2]));
worker.run();
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
index 3e9819d1..22c50176 100644
--- a/passes/equiv/equiv_mark.cc
+++ b/passes/equiv/equiv_mark.cc
@@ -218,7 +218,7 @@ struct EquivMarkPass : public Pass {
}
virtual void execute(std::vector<std::string> args, Design *design)
{
- log_header("Executing EQUIV_MARK pass.\n");
+ log_header(design, "Executing EQUIV_MARK pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index 982176c4..eb2e5a17 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -333,7 +333,7 @@ struct EquivMiterPass : public Pass {
found_two_modules:
log_cmd_error("Exactly one module must be selected for 'equiv_miter'!\n");
- log_header("Executing EQUIV_MITER pass.\n");
+ log_header(design, "Executing EQUIV_MITER pass.\n");
worker.miter_module = design->addModule(worker.miter_name);
worker.run();
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
index f4141ad4..163b1009 100644
--- a/passes/equiv/equiv_purge.cc
+++ b/passes/equiv/equiv_purge.cc
@@ -189,7 +189,7 @@ struct EquivPurgePass : public Pass {
}
virtual void execute(std::vector<std::string> args, Design *design)
{
- log_header("Executing EQUIV_PURGE pass.\n");
+ log_header(design, "Executing EQUIV_PURGE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
index b5c383b6..770497a5 100644
--- a/passes/equiv/equiv_remove.cc
+++ b/passes/equiv/equiv_remove.cc
@@ -46,7 +46,7 @@ struct EquivRemovePass : public Pass {
bool mode_gate = false;
int remove_count = 0;
- log_header("Executing EQUIV_REMOVE pass.\n");
+ log_header(design, "Executing EQUIV_REMOVE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index fa22dc62..49963ed6 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -277,7 +277,7 @@ struct EquivSimplePass : public Pass {
int success_counter = 0;
int max_seq = 1;
- log_header("Executing EQUIV_SIMPLE pass.\n");
+ log_header(design, "Executing EQUIV_SIMPLE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
index 8a2f5e05..7b9230b3 100644
--- a/passes/equiv/equiv_status.cc
+++ b/passes/equiv/equiv_status.cc
@@ -41,7 +41,7 @@ struct EquivStatusPass : public Pass {
bool assert_mode = false;
int unproven_count = 0;
- log_header("Executing EQUIV_STATUS pass.\n");
+ log_header(design, "Executing EQUIV_STATUS pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index 2c85d2d3..c4ced6a7 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -321,7 +321,7 @@ struct EquivStructPass : public Pass {
bool mode_fwd = false;
int max_iter = -1;
- log_header("Executing EQUIV_STRUCT pass.\n");
+ log_header(design, "Executing EQUIV_STRUCT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 3f5564fc..3b537ecd 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -76,7 +76,7 @@ struct FsmPass : public Pass {
std::string encfile_opt;
std::string encoding_opt;
- log_header("Executing FSM pass (extract and optimize FSM).\n");
+ log_header(design, "Executing FSM pass (extract and optimize FSM).\n");
log_push();
size_t argidx;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 740113e3..6a560f16 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -36,18 +36,21 @@ static SigPool sig_at_port;
static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor)
{
- if (sig_at_port.check_any(assign_map(sig)))
- return false;
-
- if (sig.is_fully_const() || old_sig == sig)
+ if (sig.is_fully_const() || old_sig == sig) {
return true;
+ }
+
+ if (sig_at_port.check_any(assign_map(sig))) {
+ return false;
+ }
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
for (auto &cellport : cellport_list)
{
- if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y")
+ if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") {
return false;
+ }
if (recursion_monitor.count(cellport.first)) {
log_warning("logic loop in mux tree at signal %s in module %s.\n",
@@ -110,28 +113,134 @@ static bool check_state_users(RTLIL::SigSpec sig)
static void detect_fsm(RTLIL::Wire *wire)
{
- if (wire->attributes.count("\\init") > 0)
- return;
- if (wire->attributes.count("\\fsm_encoding") > 0 || wire->width <= 1)
+ bool has_fsm_encoding_attr = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() != "none";
+ bool has_fsm_encoding_none = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() == "none";
+ bool has_init_attr = wire->attributes.count("\\init") > 0;
+ bool is_module_port = sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire)));
+ bool looks_like_state_reg = false, looks_like_good_state_reg = false;
+ bool is_self_resetting = false;
+
+ if (has_fsm_encoding_none)
return;
- if (sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire))))
+
+ if (wire->width <= 1) {
+ if (has_fsm_encoding_attr) {
+ log_warning("Removing fsm_encoding attribute from 1-bit net: %s.%s\n", log_id(wire->module), log_id(wire));
+ wire->attributes.erase("\\fsm_encoding");
+ }
return;
+ }
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(RTLIL::SigSpec(wire), cellport_list);
- for (auto &cellport : cellport_list) {
+
+ for (auto &cellport : cellport_list)
+ {
if ((cellport.first->type != "$dff" && cellport.first->type != "$adff") || cellport.second != "\\Q")
continue;
+
muxtree_cells.clear();
pool<Cell*> recursion_monitor;
RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q"));
RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D"));
- if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d, recursion_monitor) && check_state_users(sig_q)) {
- log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str());
- wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
- return;
+
+ if (sig_q != assign_map(wire))
+ continue;
+
+ looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor);
+ looks_like_good_state_reg = check_state_users(sig_q);
+
+ if (!looks_like_state_reg)
+ break;
+
+ ConstEval ce(wire->module);
+
+ std::set<sig2driver_entry_t> cellport_list;
+ sig2user.find(sig_q, cellport_list);
+
+ for (auto &cellport : cellport_list)
+ {
+ RTLIL::Cell *cell = cellport.first;
+ bool set_output = false, clr_output = false;
+
+ if (cell->type == "$ne")
+ set_output = true;
+
+ if (cell->type == "$eq")
+ clr_output = true;
+
+ if (!set_output && !clr_output) {
+ clr_output = true;
+ for (auto &port_it : cell->connections())
+ if (port_it.first != "\\A" || port_it.first != "\\Y")
+ clr_output = false;
+ }
+
+ if (set_output || clr_output) {
+ for (auto &port_it : cell->connections())
+ if (cell->output(port_it.first)) {
+ SigSpec sig = assign_map(port_it.second);
+ Const val(set_output ? State::S1 : State::S0, GetSize(sig));
+ ce.set(sig, val);
+ }
+ }
+ }
+
+ SigSpec sig_y = sig_d, sig_undef;
+ if (ce.eval(sig_y, sig_undef))
+ is_self_resetting = true;
+ }
+
+ if (has_fsm_encoding_attr)
+ {
+ vector<string> warnings;
+
+ if (is_module_port)
+ warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n");
+
+ if (!looks_like_good_state_reg)
+ warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n");
+
+ if (has_init_attr)
+ warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!");
+
+ if (!looks_like_state_reg)
+ warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n");
+
+ if (is_self_resetting)
+ warnings.push_back("FSM seems to be self-resetting. Possible simulation-synthesis mismatch!\n");
+
+ if (!warnings.empty()) {
+ string warnmsg = stringf("Regarding the user-specified fsm_encoding attribute on %s.%s:\n", log_id(wire->module), log_id(wire));
+ for (auto w : warnings) warnmsg += " " + w;
+ log_warning("%s", warnmsg.c_str());
+ } else {
+ log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
}
}
+ else
+ if (looks_like_state_reg && looks_like_good_state_reg && !has_init_attr && !is_module_port && !is_self_resetting)
+ {
+ log("Found FSM state register %s.%s.\n", log_id(wire->module), log_id(wire));
+ wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
+ }
+ else
+ if (looks_like_state_reg)
+ {
+ log("Not marking %s.%s as FSM state register:\n", log_id(wire->module), log_id(wire));
+
+ if (is_module_port)
+ log(" Register is connected to module port.\n");
+
+ if (!looks_like_good_state_reg)
+ log(" Users of register don't seem to benefit from recoding.\n");
+
+ if (has_init_attr)
+ log(" Register has an initialization value.");
+
+ if (is_self_resetting)
+ log(" Circuit seems to be self-resetting.\n");
+ }
}
struct FsmDetectPass : public Pass {
@@ -154,7 +263,7 @@ struct FsmDetectPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_DETECT pass (finding FSMs in design).\n");
+ log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n");
extra_args(args, 1, design);
CellTypes ct;
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index 43c9a792..3ded3f37 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -258,7 +258,7 @@ struct FsmExpandPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
+ log_header(design, "Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index 0eff2884..1cbfcfae 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -152,7 +152,7 @@ struct FsmExportPass : public Pass {
bool flag_origenc = false;
size_t argidx;
- log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
+ log_header(design, "Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
for (argidx = 1; argidx < args.size(); argidx++) {
arg = args[argidx];
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index d61ac568..8a4ee3f2 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -92,12 +92,15 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef())
do {
+ SigSpec new_reset_state;
if (sig_aa.is_fully_def())
- *reset_state = sig_aa.as_const();
+ new_reset_state = sig_aa.as_const();
else if (sig_bb.is_fully_def())
- *reset_state = sig_bb.as_const();
+ new_reset_state = sig_bb.as_const();
else
break;
+ new_reset_state.extend_u0(GetSize(*reset_state));
+ *reset_state = new_reset_state.as_const();
log(" found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state));
} while (0);
@@ -416,7 +419,7 @@ struct FsmExtractPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_EXTRACT pass (extracting FSM from design).\n");
+ log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n");
extra_args(args, 1, design);
CellTypes ct;
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 20db82c1..2cc1a7d5 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -43,7 +43,7 @@ struct FsmInfoPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
+ log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index 574b9a20..5b32ed59 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -335,7 +335,7 @@ struct FsmMapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
+ log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index a7cc95ff..5b1da44f 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -336,7 +336,7 @@ struct FsmOptPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n");
+ log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index a4b45295..5102d833 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -157,7 +157,7 @@ struct FsmRecodePass : public Pass {
FILE *encfile = NULL;
std::string default_encoding;
- log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
+ log_header(design, "Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index fcc30d17..4d1e3987 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -261,7 +261,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
return did_something;
}
-void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
+void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent)
{
if (used.count(mod) > 0)
return;
@@ -287,7 +287,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTL
void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
{
- std::set<RTLIL::Module*> used;
+ std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
hierarchy_worker(design, used, top, 0);
std::vector<RTLIL::Module*> del_modules;
@@ -297,8 +297,6 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
int del_counter = 0;
for (auto mod : del_modules) {
- if (mod->name.substr(0, 9) == "$abstract")
- continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
@@ -324,10 +322,12 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
{
if (db.count(module) == 0) {
+ int score = 0;
db[module] = 0;
for (auto cell : module->cells())
if (design->module(cell->type))
- db[module] = max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
+ db[module] = score;
}
return db.at(module);
}
@@ -398,7 +398,7 @@ struct HierarchyPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HIERARCHY pass (managing design hierarchy).\n");
+ log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
bool purge_lib = false;
@@ -508,7 +508,7 @@ struct HierarchyPass : public Pass {
top_mod = mod_it.second;
if (top_mod == nullptr && auto_top_mode) {
- log_header("Finding top of design hierarchy..\n");
+ log_header(design, "Finding top of design hierarchy..\n");
dict<Module*, int> db;
for (Module *mod : design->selected_modules()) {
int score = find_top_mod_score(design, mod, db);
@@ -525,9 +525,9 @@ struct HierarchyPass : public Pass {
{
did_something = false;
- std::set<RTLIL::Module*> used_modules;
+ std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules;
if (top_mod != NULL) {
- log_header("Analyzing design hierarchy..\n");
+ log_header(design, "Analyzing design hierarchy..\n");
hierarchy_worker(design, used_modules, top_mod, 0);
} else {
for (auto mod : design->modules())
@@ -541,7 +541,7 @@ struct HierarchyPass : public Pass {
}
if (top_mod != NULL) {
- log_header("Analyzing design hierarchy..\n");
+ log_header(design, "Analyzing design hierarchy..\n");
hierarchy_clean(design, top_mod, purge_lib);
}
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/singleton.cc
index 5715c0eb..03c365fb 100644
--- a/passes/hierarchy/singleton.cc
+++ b/passes/hierarchy/singleton.cc
@@ -43,7 +43,7 @@ struct SingletonPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SINGLETON pass (creating singleton modules).\n");
+ log_header(design, "Executing SINGLETON pass (creating singleton modules).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index d4e8c96c..9f312f82 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -298,7 +298,7 @@ struct SubmodPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
+ log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
std::string opt_name;
@@ -321,7 +321,7 @@ struct SubmodPass : public Pass {
if (opt_name.empty())
{
Pass::call(design, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
+ log_header(design, "Continuing SUBMOD pass.\n");
std::set<RTLIL::IdString> handled_modules;
@@ -356,7 +356,7 @@ struct SubmodPass : public Pass {
log("Nothing selected -> do nothing.\n");
else {
Pass::call_on_module(design, module, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
+ log_header(design, "Continuing SUBMOD pass.\n");
SubmodWorker worker(design, module, copy_mode, opt_name);
}
}
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index aeff225d..ad359c01 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -6,4 +6,5 @@ OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
+OBJS += passes/memory/memory_memx.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 4e74d1a4..947d598b 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -31,14 +31,15 @@ struct MemoryPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory [-nomap] [-nordff] [-bram <bram_rules>] [selection]\n");
+ log(" memory [-nomap] [-nordff] [-memx] [-bram <bram_rules>] [selection]\n");
log("\n");
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
- log(" memory_dff [-nordff]\n");
+ log(" memory_dff [-nordff] (-memx implies -nordff)\n");
log(" opt_clean\n");
log(" memory_share\n");
log(" opt_clean\n");
+ log(" memory_memx (when called with -memx)\n");
log(" memory_collect\n");
log(" memory_bram -rules <bram_rules> (when called with -bram)\n");
log(" memory_map (skipped if called with -nomap)\n");
@@ -51,9 +52,10 @@ struct MemoryPass : public Pass {
{
bool flag_nomap = false;
bool flag_nordff = false;
+ bool flag_memx = false;
string memory_bram_opts;
- log_header("Executing MEMORY pass.\n");
+ log_header(design, "Executing MEMORY pass.\n");
log_push();
size_t argidx;
@@ -66,6 +68,11 @@ struct MemoryPass : public Pass {
flag_nordff = true;
continue;
}
+ if (args[argidx] == "-memx") {
+ flag_nordff = true;
+ flag_memx = true;
+ continue;
+ }
if (argidx+1 < args.size() && args[argidx] == "-bram") {
memory_bram_opts += " -rules " + args[++argidx];
continue;
@@ -77,6 +84,8 @@ struct MemoryPass : public Pass {
Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff");
Pass::call(design, "opt_clean");
Pass::call(design, "memory_share");
+ if (flag_memx)
+ Pass::call(design, "memory_memx");
Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index f2d9b584..a7f9cf38 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -656,6 +656,9 @@ grow_read_ports:;
bool transp = rd_transp[cell_port_i] == State::S1;
SigBit clksig = rd_clk[cell_port_i];
+ if (wr_ports == 0)
+ transp = false;
+
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
@@ -826,7 +829,7 @@ grow_read_ports:;
State padding = State::Sx;
for (int j = 0; j < bram.dbits; j++)
if (init_offset+i < GetSize(initdata) && init_shift+j < GetSize(initdata[init_offset+i]))
- padding = initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j];
+ initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j];
else
initparam[i*bram.dbits+j] = padding;
}
@@ -1211,7 +1214,7 @@ struct MemoryBramPass : public Pass {
{
rules_t rules;
- log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
+ log_header(design, "Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 5c0acb3e..ab66e3fb 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -37,8 +37,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
- int addr_bits = 0;
-
Const init_data(State::Sx, memory->size * memory->width);
SigMap sigmap(module);
@@ -59,16 +57,28 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
SigSpec sig_rd_data;
SigSpec sig_rd_en;
+ int addr_bits = 0;
std::vector<Cell*> memcells;
for (auto &cell_it : module->cells_) {
Cell *cell = cell_it.second;
if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) {
- addr_bits = max(addr_bits, cell->getParam("\\ABITS").as_int());
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ for (int i = 0; i < GetSize(addr); i++)
+ if (addr[i] != State::S0)
+ addr_bits = std::max(addr_bits, i+1);
memcells.push_back(cell);
}
}
+ if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size)
+ memory->size = 1 << addr_bits;
+
+ if (memory->start_offset >= 0)
+ addr_bits = std::min(addr_bits, ceil_log2(memory->size + memory->start_offset));
+
+ addr_bits = std::max(addr_bits, 1);
+
if (memcells.empty()) {
log(" no cells found. removing memory.\n");
return nullptr;
@@ -247,7 +257,7 @@ struct MemoryCollectPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n");
+ log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index beb2016a..40691d16 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -283,7 +283,7 @@ struct MemoryDffPass : public Pass {
{
bool flag_wr_only = false;
- log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
+ log_header(design, "Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index 0b8ccb36..bffeec85 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -363,7 +363,7 @@ struct MemoryMapPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
+ log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
for (auto mod : design->selected_modules())
MemoryMapWorker(design, mod);
diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc
new file mode 100644
index 00000000..2b02e249
--- /dev/null
+++ b/passes/memory/memory_memx.cc
@@ -0,0 +1,92 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/log.h"
+#include <sstream>
+#include <set>
+#include <stdlib.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct MemoryMemxPass : public Pass {
+ MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_memx [selection]\n");
+ log("\n");
+ log("This pass adds additional circuitry that emulates the Verilog simulation\n");
+ log("behavior for out-of-bounds memory reads and writes.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> mem_port_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type.in("$memrd", "$memwr"))
+ mem_port_cells.push_back(cell);
+
+ for (auto cell : mem_port_cells)
+ {
+ IdString memid = cell->getParam("\\MEMID").decode_string();
+ RTLIL::Memory *mem = module->memories.at(memid);
+
+ int lowest_addr = mem->start_offset;
+ int highest_addr = mem->start_offset + mem->size - 1;
+
+ SigSpec addr = cell->getPort("\\ADDR");
+ addr.extend_u0(32);
+
+ SigSpec addr_ok = module->Nex(NEW_ID, module->ReduceXor(NEW_ID, addr), module->ReduceXor(NEW_ID, {addr, State::S1}));
+ if (lowest_addr != 0)
+ addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Ge(NEW_ID, addr, lowest_addr));
+ addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Le(NEW_ID, addr, highest_addr));
+
+ if (cell->type == "$memrd")
+ {
+ if (cell->getParam("\\CLK_ENABLE").as_bool())
+ log_error("Cell %s.%s (%s) has an enabled clock. Clocked $memrd cells are not supported by memory_memx!\n",
+ log_id(module), log_id(cell), log_id(cell->type));
+
+ SigSpec rdata = cell->getPort("\\DATA");
+ Wire *raw_rdata = module->addWire(NEW_ID, GetSize(rdata));
+ module->addMux(NEW_ID, SigSpec(State::Sx, GetSize(rdata)), raw_rdata, addr_ok, rdata);
+ cell->setPort("\\DATA", raw_rdata);
+ }
+
+ if (cell->type == "$memwr")
+ {
+ SigSpec en = cell->getPort("\\EN");
+ en = module->And(NEW_ID, en, addr_ok.repeat(GetSize(en)));
+ cell->setPort("\\EN", en);
+ }
+ }
+ }
+ }
+} MemoryMemxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 3a6fd0b4..ca09ac52 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -43,7 +43,7 @@ struct MemoryShareWorker
CellTypes cone_ct;
std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>> sig_to_mux;
- std::map<std::set<std::map<RTLIL::SigBit, bool>>, RTLIL::SigBit> conditions_logic_cache;
+ std::map<pair<std::set<std::map<SigBit, bool>>, SigBit>, SigBit> conditions_logic_cache;
// -----------------------------------------------------------------
@@ -109,10 +109,12 @@ struct MemoryShareWorker
return false;
}
- RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, int &created_conditions)
+ RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, SigBit olden, int &created_conditions)
{
- if (conditions_logic_cache.count(conditions))
- return conditions_logic_cache.at(conditions);
+ auto key = make_pair(conditions, olden);
+
+ if (conditions_logic_cache.count(key))
+ return conditions_logic_cache.at(key);
RTLIL::SigSpec terms;
for (auto &cond : conditions) {
@@ -125,13 +127,16 @@ struct MemoryShareWorker
created_conditions++;
}
- if (terms.size() == 0)
+ if (olden.wire != nullptr || olden != State::S1)
+ terms.append(olden);
+
+ if (GetSize(terms) == 0)
terms = State::S1;
- if (terms.size() > 1)
+ if (GetSize(terms) > 1)
terms = module->ReduceAnd(NEW_ID, terms);
- return conditions_logic_cache[conditions] = terms;
+ return conditions_logic_cache[key] = terms;
}
void translate_rd_feedback_to_en(std::string memid, std::vector<RTLIL::Cell*> &rd_ports, std::vector<RTLIL::Cell*> &wr_ports)
@@ -140,15 +145,14 @@ struct MemoryShareWorker
std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map;
std::set<RTLIL::SigBit> non_feedback_nets;
- for (auto wire_it : module->wires_)
- if (wire_it.second->port_output) {
- std::vector<RTLIL::SigBit> bits = RTLIL::SigSpec(wire_it.second);
+ for (auto wire : module->wires())
+ if (wire->port_output) {
+ std::vector<RTLIL::SigBit> bits = sigmap(wire);
non_feedback_nets.insert(bits.begin(), bits.end());
}
- for (auto cell_it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = cell_it.second;
bool ignore_data_port = false;
if (cell->type == "$mux" || cell->type == "$pmux")
@@ -173,7 +177,7 @@ struct MemoryShareWorker
cell->parameters.at("\\MEMID").decode_string() == memid)
ignore_data_port = true;
- for (auto conn : cell_it.second->connections())
+ for (auto conn : cell->connections())
{
if (ignore_data_port && conn.first == "\\DATA")
continue;
@@ -240,13 +244,8 @@ struct MemoryShareWorker
std::map<RTLIL::SigBit, bool> state;
std::set<std::map<RTLIL::SigBit, bool>> conditions;
- if (cell_en[i].wire != NULL) {
- state[cell_en[i]] = false;
- conditions.insert(state);
- }
-
find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions);
- cell_en[i] = conditions_to_logic(conditions, created_conditions);
+ cell_en[i] = conditions_to_logic(conditions, cell_en[i], created_conditions);
}
if (created_conditions) {
@@ -620,6 +619,12 @@ struct MemoryShareWorker
RTLIL::SigBit this_en_active = module->ReduceOr(NEW_ID, this_en);
+ if (GetSize(last_addr) < GetSize(this_addr))
+ last_addr.extend_u0(GetSize(this_addr));
+ else
+ this_addr.extend_u0(GetSize(last_addr));
+
+ wr_ports[i]->setParam("\\ABITS", GetSize(this_addr));
wr_ports[i]->setPort("\\ADDR", module->Mux(NEW_ID, last_addr, this_addr, this_en_active));
wr_ports[i]->setPort("\\DATA", module->Mux(NEW_ID, last_data, this_data, this_en_active));
@@ -666,10 +671,8 @@ struct MemoryShareWorker
std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex;
sigmap_xmux = sigmap;
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
-
if (cell->type == "$memrd")
memindex[cell->parameters.at("\\MEMID").decode_string()].first.push_back(cell);
@@ -746,11 +749,11 @@ struct MemorySharePass : public Pass {
log("\n");
log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
- log("optimizations) such as opt_share.\n");
+ log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
+ log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules())
MemoryShareWorker(design, module);
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 60724da7..a0fc31b5 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -138,7 +138,7 @@ struct MemoryUnpackPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
+ log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 43defb78..a8b1537b 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -1,11 +1,11 @@
OBJS += passes/opt/opt.o
-OBJS += passes/opt/opt_share.o
+OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_muxtree.o
OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
-OBJS += passes/opt/opt_const.o
+OBJS += passes/opt/opt_expr.o
ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index f5389d8e..13ea5469 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -37,23 +37,23 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
- log(" opt_share [-share_all] -nomux\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_merge [-share_all] -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n");
- log(" opt_share [-share_all]\n");
+ log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
log("\n");
log("When called with -fast the following script is used instead:\n");
log("\n");
log(" do\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
- log(" opt_share [-share_all]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
log(" while <changed design in opt_rmdff>\n");
@@ -66,12 +66,12 @@ struct OptPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string opt_clean_args;
- std::string opt_const_args;
+ std::string opt_expr_args;
std::string opt_reduce_args;
- std::string opt_share_args;
+ std::string opt_merge_args;
bool fast_mode = false;
- log_header("Executing OPT pass (performing simple optimizations).\n");
+ log_header(design, "Executing OPT pass (performing simple optimizations).\n");
log_push();
size_t argidx;
@@ -81,37 +81,37 @@ struct OptPass : public Pass {
continue;
}
if (args[argidx] == "-mux_undef") {
- opt_const_args += " -mux_undef";
+ opt_expr_args += " -mux_undef";
continue;
}
if (args[argidx] == "-mux_bool") {
- opt_const_args += " -mux_bool";
+ opt_expr_args += " -mux_bool";
continue;
}
if (args[argidx] == "-undriven") {
- opt_const_args += " -undriven";
+ opt_expr_args += " -undriven";
continue;
}
if (args[argidx] == "-clkinv") {
- opt_const_args += " -clkinv";
+ opt_expr_args += " -clkinv";
continue;
}
if (args[argidx] == "-fine") {
- opt_const_args += " -fine";
+ opt_expr_args += " -fine";
opt_reduce_args += " -fine";
continue;
}
if (args[argidx] == "-full") {
- opt_const_args += " -full";
+ opt_expr_args += " -full";
opt_reduce_args += " -full";
continue;
}
if (args[argidx] == "-keepdc") {
- opt_const_args += " -keepdc";
+ opt_expr_args += " -keepdc";
continue;
}
if (args[argidx] == "-share_all") {
- opt_share_args += " -share_all";
+ opt_merge_args += " -share_all";
continue;
}
if (args[argidx] == "-fast") {
@@ -125,32 +125,32 @@ struct OptPass : public Pass {
if (fast_mode)
{
while (1) {
- Pass::call(design, "opt_const" + opt_const_args);
- Pass::call(design, "opt_share" + opt_share_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
+ Pass::call(design, "opt_merge" + opt_merge_args);
design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_rmdff");
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
Pass::call(design, "opt_clean" + opt_clean_args);
- log_header("Rerunning OPT passes. (Removed registers in this run.)\n");
+ log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
}
Pass::call(design, "opt_clean" + opt_clean_args);
}
else
{
- Pass::call(design, "opt_const" + opt_const_args);
- Pass::call(design, "opt_share -nomux" + opt_share_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
+ Pass::call(design, "opt_merge -nomux" + opt_merge_args);
while (1) {
design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_muxtree");
Pass::call(design, "opt_reduce" + opt_reduce_args);
- Pass::call(design, "opt_share" + opt_share_args);
+ Pass::call(design, "opt_merge" + opt_merge_args);
Pass::call(design, "opt_rmdff");
Pass::call(design, "opt_clean" + opt_clean_args);
- Pass::call(design, "opt_const" + opt_const_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
- log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ log_header(design, "Rerunning OPT passes. (Maybe there is more to do..)\n");
}
}
@@ -158,7 +158,7 @@ struct OptPass : public Pass {
design->sort();
design->check();
- log_header(fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
+ log_header(design, fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 175e8e11..6600ffa2 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -156,6 +156,9 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (w1->port_input != w2->port_input)
return w2->port_input;
+ if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output))
+ return !(w2->port_input && w2->port_output);
+
if (w1->name[0] == '\\' && w2->name[0] == '\\') {
if (regs.check_any(s1) != regs.check_any(s2))
return regs.check_any(s2);
@@ -380,7 +383,7 @@ struct OptCleanPass : public Pass {
{
bool purge_mode = false;
- log_header("Executing OPT_CLEAN pass (remove unused cells and wires).\n");
+ log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n");
log_push();
size_t argidx;
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_expr.cc
index 0fcacf0a..b62eae28 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_expr.cc
@@ -179,7 +179,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
log("\n");
}
- cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
+ cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
module->remove(cell);
did_something = true;
@@ -304,7 +304,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : cells.sorted)
{
-#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
+#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
if (clkinv)
@@ -342,6 +342,68 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map);
}
+ bool detect_const_and = false;
+ bool detect_const_or = false;
+
+ if (cell->type.in("$reduce_and", "$_AND_"))
+ detect_const_and = true;
+
+ if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ detect_const_and = true;
+
+ if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
+ detect_const_or = true;
+
+ if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ detect_const_or = true;
+
+ if (detect_const_and || detect_const_or)
+ {
+ pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
+ bool found_zero = false, found_one = false, found_inv = false;
+
+ if (cell->hasPort("\\B")) {
+ vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
+ input_bits.insert(more_bits.begin(), more_bits.end());
+ }
+
+ for (auto bit : input_bits) {
+ if (bit == State::S0)
+ found_zero = true;
+ if (bit == State::S1)
+ found_one = true;
+ if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
+ found_inv = true;
+ }
+
+ if (detect_const_and && (found_zero || found_inv)) {
+ cover("opt.opt_expr.const_and");
+ replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0);
+ goto next_cell;
+ }
+
+ if (detect_const_or && (found_one || found_inv)) {
+ cover("opt.opt_expr.const_or");
+ replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
+ goto next_cell;
+ }
+ }
+
+ if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
+ GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1)
+ {
+ if (cell->type == "$reduce_xnor") {
+ cover("opt.opt_expr.reduce_xnor_not");
+ log("Replacing %s cell `%s' in module `%s' with $not cell.\n",
+ log_id(cell->type), log_id(cell->name), log_id(module));
+ cell->type = "$not";
+ } else {
+ cover("opt.opt_expr.unary_buffer");
+ replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
+ }
+ goto next_cell;
+ }
+
if (do_fine)
{
if (cell->type == "$not" || cell->type == "$pos" ||
@@ -366,7 +428,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
- cover("opt.opt_const.fine.$reduce_and");
+ cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
@@ -392,7 +454,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
- cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
+ cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
@@ -418,7 +480,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
- cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str());
+ cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b);
@@ -428,18 +490,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) {
- cover("opt.opt_const.one_high");
- replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1);
- goto next_cell;
- }
-
- if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) {
- cover("opt.opt_const.one_low");
- replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0);
- goto next_cell;
- }
-
if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
@@ -462,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (0) {
found_the_x_bit:
- cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
@@ -475,13 +525,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
- cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
+ cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
goto next_cell;
}
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
- cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
+ cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B"));
@@ -564,7 +614,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
if (input.match("10 ")) {
- cover("opt.opt_const.mux_to_inv");
+ cover("opt.opt_expr.mux_to_inv");
cell->type = "$_NOT_";
cell->setPort("\\A", input.extract(0, 1));
cell->unsetPort("\\B");
@@ -599,7 +649,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log_assert(GetSize(a) == GetSize(b));
for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
- cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
@@ -612,7 +662,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a.size() == 0) {
- cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
@@ -620,7 +670,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a.size() < a.size() || new_b.size() < b.size()) {
- cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b);
cell->parameters["\\A_WIDTH"] = new_a.size();
@@ -635,7 +685,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
if (a.is_fully_const() && !b.is_fully_const()) {
- cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
cell->setPort("\\A", b);
cell->setPort("\\B", a);
std::swap(a, b);
@@ -646,7 +696,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec input = b;
ACTION_DO("\\Y", cell->getPort("\\A"));
} else {
- cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not";
cell->parameters.erase("\\B_WIDTH");
@@ -661,7 +711,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$eq" || cell->type == "$ne") &&
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{
- cover_list("opt.opt_const.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
@@ -699,7 +749,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
sig_y[i] = sig_a[GetSize(sig_a)-1];
}
- cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
+ cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
@@ -760,9 +810,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_a || identity_wrt_b)
{
if (identity_wrt_a)
- cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
if (identity_wrt_b)
- cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
@@ -786,14 +836,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
- cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
goto next_cell;
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
- cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B");
@@ -812,7 +862,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
- cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S");
@@ -832,7 +882,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
- cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S");
@@ -856,7 +906,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
int width = cell->getPort("\\A").size();
if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
cell->getPort("\\S").is_fully_undef()) {
- cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
goto next_cell;
}
@@ -875,17 +925,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
new_s = new_s.extract(0, new_s.size()-1);
}
if (new_s.size() == 0) {
- cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
- cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
goto next_cell;
}
if (cell->getPort("\\S").size() != new_s.size()) {
- cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a);
@@ -911,7 +961,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters["\\A_SIGNED"].as_bool(), false, \
cell->parameters["\\Y_WIDTH"].as_int())); \
- cover("opt.opt_const.const.$" #_t); \
+ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
goto next_cell; \
} \
@@ -926,7 +976,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters["\\A_SIGNED"].as_bool(), \
cell->parameters["\\B_SIGNED"].as_bool(), \
cell->parameters["\\Y_WIDTH"].as_int())); \
- cover("opt.opt_const.const.$" #_t); \
+ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
goto next_cell; \
} \
@@ -1002,7 +1052,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == 0)
{
- cover("opt.opt_const.mul_shift.zero");
+ cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str());
@@ -1018,9 +1068,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == (1 << i))
{
if (swapped_ab)
- cover("opt.opt_const.mul_shift.swapped");
+ cover("opt.opt_expr.mul_shift.swapped");
else
- cover("opt.opt_const.mul_shift.unswapped");
+ cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i);
@@ -1048,6 +1098,75 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ if (!keepdc && cell->type.in("$div", "$mod"))
+ {
+ bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ if (sig_b.is_fully_def() && sig_b.size() <= 32)
+ {
+ int b_val = sig_b.as_int();
+
+ if (b_val == 0)
+ {
+ cover("opt.opt_expr.divmod_zero");
+
+ log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
+ cell->name.c_str(), module->name.c_str());
+
+ module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
+ if (b_val == (1 << i))
+ {
+ if (cell->type == "$div")
+ {
+ cover("opt.opt_expr.div_shift");
+
+ log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ b_val, cell->name.c_str(), module->name.c_str(), i);
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
+
+ while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
+ new_b.pop_back();
+
+ cell->type = "$shr";
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
+ cell->parameters["\\B_SIGNED"] = false;
+ cell->setPort("\\B", new_b);
+ cell->check();
+ }
+ else
+ {
+ cover("opt.opt_expr.mod_mask");
+
+ log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
+ b_val, cell->name.c_str(), module->name.c_str());
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
+
+ if (b_signed)
+ new_b.push_back(State::S0);
+
+ cell->type = "$and";
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
+ cell->setPort("\\B", new_b);
+ cell->check();
+ }
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
+ }
+
next_cell:;
#undef ACTION_DO
#undef ACTION_DO_Y
@@ -1056,15 +1175,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
-struct OptConstPass : public Pass {
- OptConstPass() : Pass("opt_const", "perform const folding") { }
+struct OptExprPass : public Pass {
+ OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_const [options] [selection]\n");
+ log(" opt_expr [options] [selection]\n");
log("\n");
log("This pass performs const folding on internal cell types with constant inputs.\n");
+ log("It also performs some simple expression rewritring.\n");
log("\n");
log(" -mux_undef\n");
log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
@@ -1100,7 +1220,7 @@ struct OptConstPass : public Pass {
bool do_fine = false;
bool keepdc = false;
- log_header("Executing OPT_CONST pass (perform const folding).\n");
+ log_header(design, "Executing OPT_EXPR pass (perform const folding).\n");
log_push();
size_t argidx;
@@ -1158,6 +1278,6 @@ struct OptConstPass : public Pass {
log_pop();
}
-} OptConstPass;
+} OptExprPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_merge.cc
index 46752e43..97989d27 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_merge.cc
@@ -31,7 +31,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct OptShareWorker
+struct OptMergeWorker
{
RTLIL::Design *design;
RTLIL::Module *module;
@@ -45,6 +45,29 @@ struct OptShareWorker
dict<const RTLIL::Cell*, std::string> cell_hash_cache;
#endif
+ static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
+ {
+ SigSpec sig_s = conn.at("\\S");
+ SigSpec sig_b = conn.at("\\B");
+
+ int s_width = GetSize(sig_s);
+ int width = GetSize(sig_b) / s_width;
+
+ vector<pair<SigBit, SigSpec>> sb_pairs;
+ for (int i = 0; i < s_width; i++)
+ sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
+
+ std::sort(sb_pairs.begin(), sb_pairs.end());
+
+ conn["\\S"] = SigSpec();
+ conn["\\B"] = SigSpec();
+
+ for (auto &it : sb_pairs) {
+ conn["\\S"].append(it.first);
+ conn["\\B"].append(it.second);
+ }
+ }
+
#ifdef USE_CELL_HASH_CACHE
std::string int_to_hash_string(unsigned int v)
{
@@ -91,25 +114,40 @@ struct OptShareWorker
assign_map.apply(alt_conn.at("\\A"));
alt_conn.at("\\A").sort_and_unify();
conn = &alt_conn;
+ } else
+ if (cell->type == "$pmux") {
+ alt_conn = *conn;
+ assign_map.apply(alt_conn.at("\\A"));
+ assign_map.apply(alt_conn.at("\\B"));
+ assign_map.apply(alt_conn.at("\\S"));
+ sort_pmux_conn(alt_conn);
+ conn = &alt_conn;
}
+ vector<string> hash_conn_strings;
+
for (auto &it : *conn) {
if (cell->output(it.first))
continue;
RTLIL::SigSpec sig = it.second;
assign_map.apply(sig);
- hash_string += "C " + it.first.str() + "=";
+ string s = "C " + it.first.str() + "=";
for (auto &chunk : sig.chunks()) {
if (chunk.wire)
- hash_string += "{" + chunk.wire->name.str() + " " +
+ s += "{" + chunk.wire->name.str() + " " +
int_to_hash_string(chunk.offset) + " " +
int_to_hash_string(chunk.width) + "}";
else
- hash_string += RTLIL::Const(chunk.data).as_string();
+ s += RTLIL::Const(chunk.data).as_string();
}
- hash_string += "\n";
+ hash_conn_strings.push_back(s + "\n");
}
+ std::sort(hash_conn_strings.begin(), hash_conn_strings.end());
+
+ for (auto it : hash_conn_strings)
+ hash_string += it;
+
cell_hash_cache[cell] = sha1(hash_string);
return cell_hash_cache[cell];
}
@@ -171,6 +209,10 @@ struct OptShareWorker
if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") {
conn1["\\A"].sort_and_unify();
conn2["\\A"].sort_and_unify();
+ } else
+ if (cell1->type == "$pmux") {
+ sort_pmux_conn(conn1);
+ sort_pmux_conn(conn2);
}
if (conn1 != conn2) {
@@ -212,14 +254,14 @@ struct OptShareWorker
}
struct CompareCells {
- OptShareWorker *that;
- CompareCells(OptShareWorker *that) : that(that) {}
+ OptMergeWorker *that;
+ CompareCells(OptMergeWorker *that) : that(that) {}
bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const {
return that->compare_cells(cell1, cell2);
}
};
- OptShareWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) :
+ OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) :
design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
{
total_count = 0;
@@ -286,13 +328,13 @@ struct OptShareWorker
}
};
-struct OptSharePass : public Pass {
- OptSharePass() : Pass("opt_share", "consolidate identical cells") { }
+struct OptMergePass : public Pass {
+ OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_share [options] [selection]\n");
+ log(" opt_merge [options] [selection]\n");
log("\n");
log("This pass identifies cells with identical type and input signals. Such cells\n");
log("are then merged to one cell.\n");
@@ -306,7 +348,7 @@ struct OptSharePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing OPT_SHARE pass (detect identical cells).\n");
+ log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");
bool mode_nomux = false;
bool mode_share_all = false;
@@ -328,7 +370,7 @@ struct OptSharePass : public Pass {
int total_count = 0;
for (auto module : design->selected_modules()) {
- OptShareWorker worker(design, module, mode_nomux, mode_share_all);
+ OptMergeWorker worker(design, module, mode_nomux, mode_share_all);
total_count += worker.total_count;
}
@@ -336,6 +378,6 @@ struct OptSharePass : public Pass {
design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count);
}
-} OptSharePass;
+} OptMergePass;
PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 905a0162..f5ddc2af 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -68,7 +68,7 @@ struct OptMuxtreeWorker
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
{
- log("Running muxtree optimizier on module %s..\n", module->name.c_str());
+ log("Running muxtree optimizer on module %s..\n", module->name.c_str());
log(" Creating internal representation of mux trees.\n");
@@ -464,7 +464,7 @@ struct OptMuxtreePass : public Pass {
}
virtual void execute(vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
+ log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
int total_count = 0;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index 98b7b2e1..eb9d02ad 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -354,7 +354,7 @@ struct OptReducePass : public Pass {
{
bool do_fine = false;
- log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
+ log_header(design, "Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index e1b184af..fa954afa 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -60,7 +60,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
return false;
delete_dlatch:
- log("Removing %s (%s) from module %s.\n", dlatch->name.c_str(), dlatch->type.c_str(), mod->name.c_str());
+ log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
remove_init_attr(dlatch->getPort("\\Q"));
mod->remove(dlatch);
return true;
@@ -170,7 +170,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
return false;
delete_dff:
- log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str());
+ log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
remove_init_attr(dff->getPort("\\Q"));
mod->remove(dff);
return true;
@@ -190,73 +190,116 @@ struct OptRmdffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- int total_count = 0;
- log_header("Executing OPT_RMDFF pass (remove dff with constant values).\n");
+ int total_count = 0, total_initdrv = 0;
+ log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- if (!design->selected(mod_it.second))
- continue;
-
- assign_map.set(mod_it.second);
- dff_init_map.set(mod_it.second);
- for (auto &it : mod_it.second->wires_)
- if (it.second->attributes.count("\\init") != 0) {
- dff_init_map.add(it.second, it.second->attributes.at("\\init"));
- for (int i = 0; i < GetSize(it.second); i++) {
- SigBit wire_bit(it.second, i), mapped_bit = assign_map(wire_bit);
- if (mapped_bit.wire)
+ pool<SigBit> driven_bits;
+ dict<SigBit, State> init_bits;
+
+ assign_map.set(module);
+ dff_init_map.set(module);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") != 0) {
+ Const initval = wire->attributes.at("\\init");
+ dff_init_map.add(wire, initval);
+ for (int i = 0; i < GetSize(wire); i++) {
+ SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
+ if (mapped_bit.wire) {
init_attributes[mapped_bit].insert(wire_bit);
+ if (i < GetSize(initval))
+ init_bits[mapped_bit] = initval[i];
+ }
}
}
+
+ if (wire->port_input) {
+ for (auto bit : assign_map(wire))
+ driven_bits.insert(bit);
+ }
+ }
mux_drivers.clear();
std::vector<RTLIL::IdString> dff_list;
std::vector<RTLIL::IdString> dlatch_list;
- for (auto &it : mod_it.second->cells_) {
- if (it.second->type == "$mux" || it.second->type == "$pmux") {
- if (it.second->getPort("\\A").size() == it.second->getPort("\\B").size())
- mux_drivers.insert(assign_map(it.second->getPort("\\Y")), it.second);
+ for (auto cell : module->cells())
+ {
+ for (auto &conn : cell->connections())
+ if (cell->output(conn.first) || !cell->known())
+ for (auto bit : assign_map(conn.second))
+ driven_bits.insert(bit);
+
+ if (cell->type == "$mux" || cell->type == "$pmux") {
+ if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
+ mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
continue;
}
- if (!design->selected(mod_it.second, it.second))
+
+ if (!design->selected(module, cell))
continue;
- if (it.second->type == "$_DFF_N_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_P_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NN0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NN1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NP0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NP1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PN0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PN1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PP0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PP1_") dff_list.push_back(it.first);
- if (it.second->type == "$dff") dff_list.push_back(it.first);
- if (it.second->type == "$adff") dff_list.push_back(it.first);
- if (it.second->type == "$dlatch") dlatch_list.push_back(it.first);
+
+ if (cell->type.in("$_DFF_N_", "$_DFF_P_",
+ "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+ "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
+ "$dff", "$adff"))
+ dff_list.push_back(cell->name);
+
+ if (cell->type == "$dlatch")
+ dlatch_list.push_back(cell->name);
}
for (auto &id : dff_list) {
- if (mod_it.second->cells_.count(id) > 0 &&
- handle_dff(mod_it.second, mod_it.second->cells_[id]))
+ if (module->cell(id) != nullptr &&
+ handle_dff(module, module->cells_[id]))
total_count++;
}
for (auto &id : dlatch_list) {
- if (mod_it.second->cells_.count(id) > 0 &&
- handle_dlatch(mod_it.second, mod_it.second->cells_[id]))
+ if (module->cell(id) != nullptr &&
+ handle_dlatch(module, module->cells_[id]))
total_count++;
}
+
+ SigSpec const_init_sigs;
+
+ for (auto bit : init_bits)
+ if (!driven_bits.count(bit.first))
+ const_init_sigs.append(bit.first);
+
+ const_init_sigs.sort_and_unify();
+
+ for (SigSpec sig : const_init_sigs.chunks())
+ {
+ Const val;
+
+ for (auto bit : sig)
+ val.bits.push_back(init_bits.at(bit));
+
+ log("Promoting init spec %s = %s to constant driver in module %s.\n",
+ log_signal(sig), log_signal(val), log_id(module));
+
+ module->connect(sig, val);
+ remove_init_attr(sig);
+ total_initdrv++;
+ }
}
assign_map.clear();
mux_drivers.clear();
- if (total_count)
+ if (total_count || total_initdrv)
design->scratchpad_set_bool("opt.did_something", true);
- log("Replaced %d DFF cells.\n", total_count);
+
+ if (total_initdrv)
+ log("Promoted %d init specs to constant drivers.\n", total_initdrv);
+
+ if (total_count)
+ log("Replaced %d DFF cells.\n", total_count);
}
} OptRmdffPass;
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 1d9b1006..22914eaa 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -793,10 +793,59 @@ struct ShareWorker
return true;
}
- void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */)
+ void optimize_activation_patterns(pool<ssc_pair_t> &patterns)
{
// TODO: Remove patterns that are contained in other patterns
- // TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
+
+ dict<SigSpec, pool<Const>> db;
+ bool did_something = false;
+
+ for (auto const &p : patterns)
+ {
+ auto &sig = p.first;
+ auto &val = p.second;
+ int len = GetSize(sig);
+
+ for (int i = 0; i < len; i++)
+ {
+ auto otherval = val;
+
+ if (otherval.bits[i] == State::S0)
+ otherval.bits[i] = State::S1;
+ else if (otherval.bits[i] == State::S1)
+ otherval.bits[i] = State::S0;
+ else
+ continue;
+
+ if (db[sig].count(otherval))
+ {
+ auto newsig = sig;
+ newsig.remove(i);
+
+ auto newval = val;
+ newval.bits.erase(newval.bits.begin() + i);
+
+ db[newsig].insert(newval);
+ db[sig].erase(otherval);
+
+ did_something = true;
+ goto next_pattern;
+ }
+ }
+
+ db[sig].insert(val);
+ next_pattern:;
+ }
+
+ if (!did_something)
+ return;
+
+ patterns.clear();
+ for (auto &it : db)
+ for (auto &val : it.second)
+ patterns.insert(make_pair(it.first, val));
+
+ optimize_activation_patterns(patterns);
}
const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
@@ -1451,7 +1500,7 @@ struct SharePass : public Pass {
config.generic_other_ops.insert("$alu");
config.generic_other_ops.insert("$macc");
- log_header("Executing SHARE pass (SAT-based resource sharing).\n");
+ log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 4f08da67..07503fbb 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -366,15 +366,26 @@ struct WreducePass : public Pass {
log(" assign y = a + b + c + 1;\n");
log(" endmodule\n");
log("\n");
+ log("Options:\n");
+ log("\n");
+ log(" -memx\n");
+ log(" Do not change the width of memory address ports. Use this options in\n");
+ log(" flows that use the 'memory_memx' pass.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, Design *design)
{
WreduceConfig config;
+ bool opt_memx = false;
- log_header("Executing WREDUCE pass (reducing word size of cells).\n");
+ log_header(design, "Executing WREDUCE pass (reducing word size of cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-memx") {
+ opt_memx = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -385,6 +396,7 @@ struct WreducePass : public Pass {
continue;
for (auto c : module->selected_cells())
+ {
if (c->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) {
@@ -396,6 +408,23 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig)));
}
}
+ if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
+ IdString memid = c->getParam("\\MEMID").decode_string();
+ RTLIL::Memory *mem = module->memories.at(memid);
+ if (mem->start_offset >= 0) {
+ int cur_addrbits = c->getParam("\\ABITS").as_int();
+ int max_addrbits = ceil_log2(mem->start_offset + mem->size);
+ if (cur_addrbits > max_addrbits) {
+ log("Removed top %d address bits (of %d) from memory %s port %s.%s (%s).\n",
+ cur_addrbits-max_addrbits, cur_addrbits,
+ c->type == "$memrd" ? "read" : c->type == "$memwr" ? "write" : "init",
+ log_id(module), log_id(c), log_id(memid));
+ c->setParam("\\ABITS", max_addrbits);
+ c->setPort("\\ADDR", c->getPort("\\ADDR").extract(0, max_addrbits));
+ }
+ }
+ }
+ }
WreduceWorker worker(&config, module);
worker.run();
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index 577ff6bf..d5366f26 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -52,12 +52,17 @@ struct ProcPass : public Pass {
log(" -global_arst [!]<netname>\n");
log(" This option is passed through to proc_arst.\n");
log("\n");
+ log(" -ifx\n");
+ log(" This option is passed through to proc_mux. proc_rmdead is not\n");
+ log(" executed in -ifx mode.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string global_arst;
+ bool ifxmode = false;
- log_header("Executing PROC pass (convert processes to netlists).\n");
+ log_header(design, "Executing PROC pass (convert processes to netlists).\n");
log_push();
size_t argidx;
@@ -67,18 +72,23 @@ struct ProcPass : public Pass {
global_arst = args[++argidx];
continue;
}
+ if (args[argidx] == "-ifx") {
+ ifxmode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
Pass::call(design, "proc_clean");
- Pass::call(design, "proc_rmdead");
+ if (!ifxmode)
+ Pass::call(design, "proc_rmdead");
Pass::call(design, "proc_init");
if (global_arst.empty())
Pass::call(design, "proc_arst");
else
Pass::call(design, "proc_arst -global_arst " + global_arst);
- Pass::call(design, "proc_mux");
+ Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
Pass::call(design, "proc_clean");
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 1da23728..216b00dd 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -226,7 +226,7 @@ struct ProcArstPass : public Pass {
std::string global_arst;
bool global_arst_neg = false;
- log_header("Executing PROC_ARST pass (detect async resets in processes).\n");
+ log_header(design, "Executing PROC_ARST pass (detect async resets in processes).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 35801951..7dbabc21 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -156,7 +156,7 @@ struct ProcCleanPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
int total_count = 0;
- log_header("Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
+ log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 63713139..f532990c 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -369,7 +369,7 @@ struct ProcDffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n");
+ log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index e37d81dd..6621afd3 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -33,6 +33,8 @@ struct proc_dlatch_db_t
Module *module;
SigMap sigmap;
+ pool<Cell*> generated_dlatches;
+ dict<Cell*, vector<SigBit>> mux_srcbits;
dict<SigBit, pair<Cell*, int>> mux_drivers;
dict<SigBit, int> sigusers;
@@ -40,10 +42,24 @@ struct proc_dlatch_db_t
{
for (auto cell : module->cells())
{
- if (cell->type.in("$mux", "$pmux")) {
+ if (cell->type.in("$mux", "$pmux"))
+ {
auto sig_y = sigmap(cell->getPort("\\Y"));
for (int i = 0; i < GetSize(sig_y); i++)
mux_drivers[sig_y[i]] = pair<Cell*, int>(cell, i);
+
+ pool<SigBit> mux_srcbits_pool;
+ for (auto bit : sigmap(cell->getPort("\\A")))
+ mux_srcbits_pool.insert(bit);
+ for (auto bit : sigmap(cell->getPort("\\B")))
+ mux_srcbits_pool.insert(bit);
+
+ vector<SigBit> mux_srcbits_vec;
+ for (auto bit : mux_srcbits_pool)
+ if (bit.wire != nullptr)
+ mux_srcbits_vec.push_back(bit);
+
+ mux_srcbits[cell].swap(mux_srcbits_vec);
}
for (auto &conn : cell->connections())
@@ -58,6 +74,42 @@ struct proc_dlatch_db_t
sigusers[bit]++;
}
+ bool quickcheck(const SigSpec &haystack, const SigSpec &needle)
+ {
+ pool<SigBit> haystack_bits = sigmap(haystack).to_sigbit_pool();
+ pool<SigBit> needle_bits = sigmap(needle).to_sigbit_pool();
+
+ pool<Cell*> cells_queue, cells_visited;
+ pool<SigBit> bits_queue, bits_visited;
+
+ bits_queue = haystack_bits;
+ while (!bits_queue.empty())
+ {
+ for (auto &bit : bits_queue) {
+ auto it = mux_drivers.find(bit);
+ if (it != mux_drivers.end())
+ if (!cells_visited.count(it->second.first))
+ cells_queue.insert(it->second.first);
+ bits_visited.insert(bit);
+ }
+
+ bits_queue.clear();
+
+ for (auto c : cells_queue) {
+ for (auto bit : mux_srcbits[c]) {
+ if (needle_bits.count(bit))
+ return true;
+ if (!bits_visited.count(bit))
+ bits_queue.insert(bit);
+ }
+ }
+
+ cells_queue.clear();
+ }
+
+ return false;
+ }
+
struct rule_node_t
{
// a node is true if "signal" equals "match" and [any
@@ -202,6 +254,84 @@ struct proc_dlatch_db_t
rules_sig[n] = and_bits[0];
return and_bits[0];
}
+
+ void fixup_mux(Cell *cell)
+ {
+ SigSpec sig_a = cell->getPort("\\A");
+ SigSpec sig_b = cell->getPort("\\B");
+ SigSpec sig_s = cell->getPort("\\S");
+ SigSpec sig_any_valid_b;
+
+ SigSpec sig_new_b, sig_new_s;
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ SigSpec b = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
+ if (!b.is_fully_undef()) {
+ sig_any_valid_b = b;
+ sig_new_b.append(b);
+ sig_new_s.append(sig_s[i]);
+ }
+ }
+
+ if (sig_new_s.empty()) {
+ sig_new_b = sig_a;
+ sig_new_s = State::S0;
+ }
+
+ if (sig_a.is_fully_undef() && !sig_any_valid_b.empty())
+ cell->setPort("\\A", sig_any_valid_b);
+
+ if (GetSize(sig_new_s) == 1) {
+ cell->type = "$mux";
+ cell->unsetParam("\\S_WIDTH");
+ } else {
+ cell->type = "$pmux";
+ cell->setParam("\\S_WIDTH", GetSize(sig_new_s));
+ }
+
+ cell->setPort("\\B", sig_new_b);
+ cell->setPort("\\S", sig_new_s);
+ }
+
+ void fixup_muxes()
+ {
+ pool<Cell*> visited, queue;
+ dict<Cell*, pool<SigBit>> upstream_cell2net;
+ dict<SigBit, pool<Cell*>> upstream_net2cell;
+
+ CellTypes ct;
+ ct.setup_internals();
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections()) {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_cell2net[cell].insert(bit);
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_net2cell[bit].insert(cell);
+ }
+
+ queue = generated_dlatches;
+ while (!queue.empty())
+ {
+ pool<Cell*> next_queue;
+
+ for (auto cell : queue) {
+ if (cell->type.in("$mux", "$pmux"))
+ fixup_mux(cell);
+ for (auto bit : upstream_cell2net[cell])
+ for (auto cell : upstream_net2cell[bit])
+ next_queue.insert(cell);
+ visited.insert(cell);
+ }
+
+ queue.clear();
+ for (auto cell : next_queue) {
+ if (!visited.count(cell) && ct.cell_known(cell->type))
+ queue.insert(cell);
+ }
+ }
+ }
};
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
@@ -218,9 +348,17 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
continue;
}
- for (auto ss : sr->actions) {
+ for (auto ss : sr->actions)
+ {
db.sigmap.apply(ss.first);
db.sigmap.apply(ss.second);
+
+ if (!db.quickcheck(ss.second, ss.first)) {
+ nolatches_bits.first.append(ss.first);
+ nolatches_bits.second.append(ss.second);
+ continue;
+ }
+
for (int i = 0; i < GetSize(ss.first); i++)
latches_out_in[ss.first[i]] = ss.second[i];
}
@@ -268,6 +406,8 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
SigSpec rhs = latches_bits.second.extract(offset, width);
Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ db.generated_dlatches.insert(cell);
+
log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
}
@@ -292,7 +432,7 @@ struct ProcDlatchPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_DLATCH pass (convert process syncs to latches).\n");
+ log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
extra_args(args, 1, design);
@@ -301,6 +441,7 @@ struct ProcDlatchPass : public Pass {
for (auto &proc_it : module->processes)
if (design->selected(module, proc_it.second))
proc_dlatch(db, proc_it.second);
+ db.fixup_muxes();
}
}
} ProcDlatchPass;
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index 633d4e58..0c8fb83d 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -61,13 +61,28 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
int offset = 0;
- for (auto &lhs_c : lhs.chunks()) {
- if (lhs_c.wire != NULL) {
- RTLIL::SigSpec value = rhs.extract(offset, lhs_c.width);
- if (value.size() != lhs_c.wire->width)
- log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs_c), log_signal(value));
- log(" Setting init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(value));
- lhs_c.wire->attributes["\\init"] = value.as_const();
+ for (auto &lhs_c : lhs.chunks())
+ {
+ if (lhs_c.wire != nullptr)
+ {
+ SigSpec valuesig = rhs.extract(offset, lhs_c.width);
+ if (!valuesig.is_fully_const())
+ log_cmd_error("Non-const initialization value: %s = %s\n", log_signal(lhs_c), log_signal(valuesig));
+
+ Const value = valuesig.as_const();
+ Const &wireinit = lhs_c.wire->attributes["\\init"];
+
+ while (GetSize(wireinit.bits) < lhs_c.wire->width)
+ wireinit.bits.push_back(State::Sx);
+
+ for (int i = 0; i < lhs_c.width; i++) {
+ auto &initbit = wireinit.bits[i + lhs_c.offset];
+ if (initbit != State::Sx && initbit != value[i])
+ log_cmd_error("Conflicting initialization values for %s.\n", log_signal(lhs_c));
+ initbit = value[i];
+ }
+
+ log(" Set init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(wireinit));
}
offset += lhs_c.width;
}
@@ -100,7 +115,7 @@ struct ProcInitPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_INIT pass (extract init attributes).\n");
+ log_header(design, "Executing PROC_INIT pass (extract init attributes).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 943e8c56..57e131ca 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -143,7 +143,7 @@ struct SnippetSwCache
}
};
-RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, bool ifxmode)
{
std::stringstream sstr;
sstr << "$procmux$" << (autoidx++);
@@ -164,14 +164,14 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
if (comp.size() == 0)
return RTLIL::SigSpec();
- if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1))
+ if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1) && !ifxmode)
{
mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig));
}
else
{
// create compare cell
- RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq");
+ RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq");
eq_cell->attributes = sw->attributes;
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
@@ -211,7 +211,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(ctrl_wire);
}
-RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
{
log_assert(when_signal.size() == else_signal.size());
@@ -223,7 +223,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return when_signal;
// compare results
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
if (ctrl_sig.size() == 0)
return when_signal;
log_assert(ctrl_sig.size() == 1);
@@ -245,12 +245,15 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(result_wire);
}
-void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
+void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
{
log_assert(last_mux_cell != NULL);
log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+ if (when_signal == last_mux_cell->getPort("\\A"))
+ return;
+
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
log_assert(ctrl_sig.size() == 1);
last_mux_cell->type = "$pmux";
@@ -266,7 +269,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
}
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
- RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+ RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{
RTLIL::SigSpec result = defval;
@@ -329,7 +332,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
for (auto pat : cs2->compare)
if (!pat.is_fully_const())
extra_group_for_next_case = true;
- else
+ else if (!ifxmode)
pool.take(pat);
}
}
@@ -340,18 +343,18 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
for (size_t i = 0; i < sw->cases.size(); i++) {
int case_idx = sw->cases.size() - i - 1;
RTLIL::CaseRule *cs2 = sw->cases[case_idx];
- RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val);
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode);
if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
- append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw);
+ append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
else
- result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw);
+ result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
}
}
return result;
}
-void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
{
log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
@@ -372,7 +375,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
log("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig));
- RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()), ifxmode);
mod->connect(RTLIL::SigSig(sig, value));
}
}
@@ -383,23 +386,37 @@ struct ProcMuxPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" proc_mux [selection]\n");
+ log(" proc_mux [options] [selection]\n");
log("\n");
log("This pass converts the decision trees in processes (originating from if-else\n");
log("and case statements) to trees of multiplexer cells.\n");
log("\n");
+ log(" -ifx\n");
+ log(" Use Verilog simulation behavior with respect to undef values in\n");
+ log(" 'case' expressions and 'if' conditions.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
+ bool ifxmode = false;
+ log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
- extra_args(args, 1, design);
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-ifx") {
+ ifxmode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
for (auto mod : design->modules())
if (design->selected(mod))
for (auto &proc_it : mod->processes)
if (design->selected(mod, proc_it.second))
- proc_mux(mod, proc_it.second);
+ proc_mux(mod, proc_it.second, ifxmode);
}
} ProcMuxPass;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index f60d4b30..5672fb47 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -51,8 +51,8 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
counter++;
continue;
}
- if (pool.empty())
- sw->cases[i]->compare.clear();
+ // if (pool.empty())
+ // sw->cases[i]->compare.clear();
}
for (auto switch_it : sw->cases[i]->switches)
@@ -76,7 +76,7 @@ struct ProcRmdeadPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
+ log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
extra_args(args, 1, design);
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 4fa6bf0d..0c5f6fc6 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -4,4 +4,5 @@ OBJS += passes/sat/freduce.o
OBJS += passes/sat/eval.o
OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
+OBJS += passes/sat/assertpmux.o
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
new file mode 100644
index 00000000..63a90767
--- /dev/null
+++ b/passes/sat/assertpmux.cc
@@ -0,0 +1,240 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct AssertpmuxWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ bool flag_noinit;
+ bool flag_always;
+
+ // get<0> ... mux cell
+ // get<1> ... mux port index
+ // get<2> ... mux bit index
+ dict<SigBit, pool<tuple<Cell*, int, int>>> sigbit_muxusers;
+
+ dict<SigBit, SigBit> sigbit_actsignals;
+ dict<SigSpec, SigBit> sigspec_actsignals;
+ dict<tuple<Cell*, int>, SigBit> muxport_actsignal;
+
+ AssertpmuxWorker(Module *module, bool flag_noinit, bool flag_always) :
+ module(module), sigmap(module), flag_noinit(flag_noinit), flag_always(flag_always)
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ sigbit_actsignals[bit] = State::S1;
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in("$mux", "$pmux"))
+ {
+ int width = cell->getParam("\\WIDTH").as_int();
+ int numports = cell->type == "$mux" ? 2 : cell->getParam("\\S_WIDTH").as_int() + 1;
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+
+ for (int i = 0; i < numports; i++) {
+ SigSpec bits = i == 0 ? sig_a : sig_b.extract(width*(i-1), width);
+ for (int k = 0; k < width; k++) {
+ tuple<Cell*, int, int> muxuser(cell, i, k);
+ sigbit_muxusers[bits[k]].insert(muxuser);
+ }
+ }
+ }
+ else
+ {
+ for (auto &conn : cell->connections()) {
+ if (!cell->known() || cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_actsignals[bit] = State::S1;
+ }
+ }
+ }
+ }
+
+ SigBit get_bit_activation(SigBit bit)
+ {
+ sigmap.apply(bit);
+
+ if (sigbit_actsignals.count(bit) == 0)
+ {
+ SigSpec output;
+
+ for (auto muxuser : sigbit_muxusers.at(bit))
+ {
+ Cell *cell = std::get<0>(muxuser);
+ int portidx = std::get<1>(muxuser);
+ int bitidx = std::get<2>(muxuser);
+
+ tuple<Cell*, int> muxport(cell, portidx);
+
+ if (muxport_actsignal.count(muxport) == 0) {
+ if (portidx == 0)
+ muxport_actsignal[muxport] = module->LogicNot(NEW_ID, cell->getPort("\\S"));
+ else
+ muxport_actsignal[muxport] = cell->getPort("\\S")[portidx-1];
+ }
+
+ output.append(module->LogicAnd(NEW_ID, muxport_actsignal.at(muxport), get_bit_activation(cell->getPort("\\Y")[bitidx])));
+ }
+
+ output.sort_and_unify();
+
+ if (GetSize(output) == 0)
+ output = State::S0;
+ else if (GetSize(output) > 1)
+ output = module->ReduceOr(NEW_ID, output);
+
+ sigbit_actsignals[bit] = output.as_bit();
+ }
+
+ return sigbit_actsignals.at(bit);
+ }
+
+ SigBit get_activation(SigSpec sig)
+ {
+ sigmap.apply(sig);
+ sig.sort_and_unify();
+
+ if (sigspec_actsignals.count(sig) == 0)
+ {
+ SigSpec output;
+
+ for (auto bit : sig)
+ output.append(get_bit_activation(bit));
+
+ output.sort_and_unify();
+
+ if (GetSize(output) == 0)
+ output = State::S0;
+ else if (GetSize(output) > 1)
+ output = module->ReduceOr(NEW_ID, output);
+
+ sigspec_actsignals[sig] = output.as_bit();
+ }
+
+ return sigspec_actsignals.at(sig);
+ }
+
+ void run(Cell *pmux)
+ {
+ log("Adding assert for $pmux cell %s.%s.\n", log_id(module), log_id(pmux));
+
+ int swidth = pmux->getParam("\\S_WIDTH").as_int();
+ int cntbits = ceil_log2(swidth+1);
+
+ SigSpec sel = pmux->getPort("\\S");
+ SigSpec cnt(State::S0, cntbits);
+
+ for (int i = 0; i < swidth; i++)
+ cnt = module->Add(NEW_ID, cnt, sel[i]);
+
+ SigSpec assert_a = module->Le(NEW_ID, cnt, SigSpec(1, cntbits));
+ SigSpec assert_en;
+
+ if (flag_noinit)
+ assert_en.append(module->LogicNot(NEW_ID, module->Initstate(NEW_ID)));
+
+ if (!flag_always)
+ assert_en.append(get_activation(pmux->getPort("\\Y")));
+
+ if (GetSize(assert_en) == 0)
+ assert_en = State::S1;
+
+ if (GetSize(assert_en) == 2)
+ assert_en = module->LogicAnd(NEW_ID, assert_en[0], assert_en[1]);
+
+ Cell *assert_cell = module->addAssert(NEW_ID, assert_a, assert_en);
+
+ if (pmux->attributes.count("\\src") != 0)
+ assert_cell->attributes["\\src"] = pmux->attributes.at("\\src");
+ }
+};
+
+struct AssertpmuxPass : public Pass {
+ AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" assertpmux [options] [selection]\n");
+ log("\n");
+ log("This command adds asserts to the design that assert that all parallel muxes\n");
+ log("($pmux cells) have a maximum of one of their inputs enable at any time.\n");
+ log("\n");
+ log(" -noinit\n");
+ log(" do not enforce the pmux condition during the init state\n");
+ log("\n");
+ log(" -always\n");
+ log(" usually the $pmux condition is only checked when the $pmux output\n");
+ log(" is used be the mux tree it drives. this option will deactivate this\n");
+ log(" additional constrained and check the $pmux condition always.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool flag_noinit = false;
+ bool flag_always = false;
+
+ log_header(design, "Executing ASSERTPMUX pass (add asserts for $pmux cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-noinit") {
+ flag_noinit = true;
+ continue;
+ }
+ if (args[argidx] == "-always") {
+ flag_always = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ AssertpmuxWorker worker(module, flag_noinit, flag_always);
+ vector<Cell*> pmux_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$pmux")
+ pmux_cells.push_back(cell);
+
+ for (auto cell : pmux_cells)
+ worker.run(cell);
+ }
+
+ }
+} AssertpmuxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 614a1bd3..09f69cc5 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -389,7 +389,7 @@ struct EvalPass : public Pass {
std::vector<std::string> shows, tables;
bool set_undef = false;
- log_header("Executing EVAL pass (evaluate the circuit given an input).\n");
+ log_header(design, "Executing EVAL pass (evaluate the circuit given an input).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index ebdf2ed5..9427547f 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -262,7 +262,7 @@ struct ExposePass : public Pass {
bool flag_evert_dff = false;
std::string sep = ".";
- log_header("Executing EXPOSE pass (exposing internal signals as outputs).\n");
+ log_header(design, "Executing EXPOSE pass (exposing internal signals as outputs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 373b8048..77263f6a 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -798,7 +798,7 @@ struct FreducePass : public Pass {
inv_mode = false;
dump_prefix = std::string();
- log_header("Executing FREDUCE pass (perform functional reduction).\n");
+ log_header(design, "Executing FREDUCE pass (perform functional reduction).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 682299ef..4854e19b 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -32,7 +32,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
bool flag_make_assert = false;
bool flag_flatten = false;
- log_header("Executing MITER pass (creating miter circuit).\n");
+ log_header(design, "Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;");
+ Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
log_pop();
}
}
@@ -264,7 +264,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
bool flag_make_outputs = false;
bool flag_flatten = false;
- log_header("Executing MITER pass (creating miter circuit).\n");
+ log_header(design, "Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -327,7 +327,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, module, "opt_const -keepdc -undriven;;");
+ Pass::call_on_module(design, module, "opt_expr -keepdc -undriven;;");
log_pop();
}
}
@@ -361,7 +361,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
log("\n");
log(" miter -assert [options] module [miter_name]\n");
@@ -375,7 +375,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index 2e9c6d2f..a6ac7afd 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -90,106 +90,16 @@ struct SatHelper
log_cmd_error("Bit %d of %s is undef but option -enable_undef is missing!\n", int(i), log_signal(sig));
}
- void setup_init()
- {
- log ("\nSetting up initial state:\n");
-
- RTLIL::SigSpec big_lhs, big_rhs;
-
- for (auto &it : module->wires_)
- {
- if (it.second->attributes.count("\\init") == 0)
- continue;
-
- RTLIL::SigSpec lhs = sigmap(it.second);
- RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
- log_assert(lhs.size() == rhs.size());
-
- RTLIL::SigSpec removed_bits;
- for (int i = 0; i < lhs.size(); i++) {
- RTLIL::SigSpec bit = lhs.extract(i, 1);
- if (!satgen.initial_state.check_all(bit)) {
- removed_bits.append(bit);
- lhs.remove(i, 1);
- rhs.remove(i, 1);
- i--;
- }
- }
-
- if (removed_bits.size())
- log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
-
- if (lhs.size()) {
- log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
- }
- }
-
- for (auto &s : sets_init)
- {
- RTLIL::SigSpec lhs, rhs;
-
- if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first))
- log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str());
- if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second))
- log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str());
- show_signal_pool.add(sigmap(lhs));
- show_signal_pool.add(sigmap(rhs));
-
- if (lhs.size() != rhs.size())
- log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
-
- log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
- }
-
- if (!satgen.initial_state.check_all(big_lhs)) {
- RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
- log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
- }
-
- if (set_init_def) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
- ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
- }
-
- if (set_init_undef) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- rem.remove(big_lhs);
- big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
- }
-
- if (set_init_zero) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- rem.remove(big_lhs);
- big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
- }
-
- if (big_lhs.size() == 0) {
- log("No constraints for initial state found.\n\n");
- return;
- }
-
- log("Final constraint equation: %s = %s\n\n", log_signal(big_lhs), log_signal(big_rhs));
- check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez->assume(satgen.signals_eq(big_lhs, big_rhs, 1));
- }
-
- void setup(int timestep = -1)
+ void setup(int timestep = -1, bool initstate = false)
{
if (timestep > 0)
log ("\nSetting up time step %d:\n", timestep);
else
log ("\nSetting up SAT problem:\n");
+ if (initstate)
+ satgen.setInitState(timestep);
+
if (timestep > max_timestep)
max_timestep = timestep;
@@ -341,6 +251,97 @@ struct SatHelper
log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
ez->assume(satgen.importAssumes(timestep));
}
+
+ if (initstate)
+ {
+ RTLIL::SigSpec big_lhs, big_rhs;
+
+ for (auto &it : module->wires_)
+ {
+ if (it.second->attributes.count("\\init") == 0)
+ continue;
+
+ RTLIL::SigSpec lhs = sigmap(it.second);
+ RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
+ log_assert(lhs.size() == rhs.size());
+
+ RTLIL::SigSpec removed_bits;
+ for (int i = 0; i < lhs.size(); i++) {
+ RTLIL::SigSpec bit = lhs.extract(i, 1);
+ if (!satgen.initial_state.check_all(bit)) {
+ removed_bits.append(bit);
+ lhs.remove(i, 1);
+ rhs.remove(i, 1);
+ i--;
+ }
+ }
+
+ if (removed_bits.size())
+ log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
+
+ if (lhs.size()) {
+ log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
+ }
+
+ for (auto &s : sets_init)
+ {
+ RTLIL::SigSpec lhs, rhs;
+
+ if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first))
+ log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str());
+ if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second))
+ log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str());
+ show_signal_pool.add(sigmap(lhs));
+ show_signal_pool.add(sigmap(rhs));
+
+ if (lhs.size() != rhs.size())
+ log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
+
+ log("Import init set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
+
+ if (!satgen.initial_state.check_all(big_lhs)) {
+ RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
+ log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
+ }
+
+ if (set_init_def) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
+ }
+
+ if (set_init_undef) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ rem.remove(big_lhs);
+ big_lhs.append(rem);
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
+ }
+
+ if (set_init_zero) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ rem.remove(big_lhs);
+ big_lhs.append(rem);
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
+ }
+
+ if (big_lhs.size() == 0) {
+ log("No constraints for initial state found.\n\n");
+ return;
+ }
+
+ log("Final init constraint equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs));
+ check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
+ }
}
int setup_proof(int timestep = -1)
@@ -630,11 +631,11 @@ struct SatHelper
"---------------------------------------------------------------------------------------------------";
if (last_timestep == -2) {
log(max_timestep > 0 ? " Time " : " ");
- log("%-*s %10s %10s %*s\n", maxModelName+10, "Signal Name", "Dec", "Hex", maxModelWidth+5, "Bin");
+ log("%-*s %11s %9s %*s\n", maxModelName+5, "Signal Name", "Dec", "Hex", maxModelWidth+3, "Bin");
}
log(max_timestep > 0 ? " ---- " : " ");
- log("%*.*s %10.10s %10.10s %*.*s\n", maxModelName+10, maxModelName+10,
- hline, hline, hline, maxModelWidth+5, maxModelWidth+5, hline);
+ log("%*.*s %11.11s %9.9s %*.*s\n", maxModelName+5, maxModelName+5,
+ hline, hline, hline, maxModelWidth+3, maxModelWidth+3, hline);
last_timestep = info.timestep;
}
@@ -647,9 +648,9 @@ struct SatHelper
log(" ");
if (info.width <= 32 && !found_undef)
- log("%-*s %10d %10x %*s\n", maxModelName+10, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+5, value.as_string().c_str());
+ log("%-*s %11d %9x %*s\n", maxModelName+5, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+3, value.as_string().c_str());
else
- log("%-*s %10s %10s %*s\n", maxModelName+10, info.description.c_str(), "--", "--", maxModelWidth+5, value.as_string().c_str());
+ log("%-*s %11s %9s %*s\n", maxModelName+5, info.description.c_str(), "--", "--", maxModelWidth+3, value.as_string().c_str());
}
if (last_timestep == -2)
@@ -1073,7 +1074,7 @@ struct SatPass : public Pass {
int tempinduct_skip = 0, stepsize = 1;
std::string vcd_file_name, json_file_name, cnf_file_name;
- log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
+ log_header(design, "Executing SAT pass (solving SAT problems in the circuit).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -1377,7 +1378,6 @@ struct SatPass : public Pass {
SatHelper basecase(design, module, enable_undef);
SatHelper inductstep(design, module, enable_undef);
- bool basecase_setup_init = true;
basecase.sets = sets;
basecase.set_assumes = set_assumes;
@@ -1403,7 +1403,7 @@ struct SatPass : public Pass {
for (int timestep = 1; timestep <= seq_len; timestep++)
if (!tempinduct_inductonly)
- basecase.setup(timestep);
+ basecase.setup(timestep, timestep == 1);
inductstep.sets = sets;
inductstep.set_assumes = set_assumes;
@@ -1436,15 +1436,10 @@ struct SatPass : public Pass {
if (!tempinduct_inductonly)
{
- basecase.setup(seq_len + inductlen);
+ basecase.setup(seq_len + inductlen, seq_len + inductlen == 1);
int property = basecase.setup_proof(seq_len + inductlen);
basecase.generate_model();
- if (basecase_setup_init) {
- basecase.setup_init();
- basecase_setup_init = false;
- }
-
if (inductlen > 1)
basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
@@ -1452,6 +1447,7 @@ struct SatPass : public Pass {
{
log("\n[base case %d] Solving problem with %d variables and %d clauses..\n",
inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+ log_flush();
if (basecase.solve(basecase.ez->NOT(property))) {
log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
@@ -1522,6 +1518,7 @@ struct SatPass : public Pass {
log("\n[induction step %d] Solving problem with %d variables and %d clauses..\n",
inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+ log_flush();
if (!inductstep.solve(inductstep.ez->NOT(property))) {
if (inductstep.gotTimeout)
@@ -1599,14 +1596,13 @@ struct SatPass : public Pass {
} else {
std::vector<int> prove_bits;
for (int timestep = 1; timestep <= seq_len; timestep++) {
- sathelper.setup(timestep);
+ sathelper.setup(timestep, timestep == 1);
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
if (timestep > prove_skip)
prove_bits.push_back(sathelper.setup_proof(timestep));
}
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
sathelper.ez->assume(sathelper.ez->NOT(sathelper.ez->expression(ezSAT::OpAnd, prove_bits)));
- sathelper.setup_init();
}
sathelper.generate_model();
@@ -1628,6 +1624,7 @@ struct SatPass : public Pass {
rerun_solver:
log("\nSolving problem with %d variables and %d clauses..\n",
sathelper.ez->numCnfVariables(), sathelper.ez->numCnfClauses());
+ log_flush();
if (sathelper.solve())
{
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 8112516c..b5024fa9 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -7,6 +7,9 @@ OBJS += passes/techmap/libparse.o
ifeq ($(ENABLE_ABC),1)
OBJS += passes/techmap/abc.o
+ifneq ($(ABCEXTERNAL),)
+passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
+endif
endif
ifneq ($(SMALL),1)
@@ -23,6 +26,11 @@ OBJS += passes/techmap/tribuf.o
OBJS += passes/techmap/lut2mux.o
OBJS += passes/techmap/nlutmap.o
OBJS += passes/techmap/dffsr2dff.o
+OBJS += passes/techmap/shregmap.o
+OBJS += passes/techmap/deminout.o
+OBJS += passes/techmap/insbuf.o
+OBJS += passes/techmap/attrmvcp.o
+OBJS += passes/techmap/attrmap.o
endif
GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 7da26602..cc79296c 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -29,15 +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; scorr; ifraig; retime {D}; strash; dch -f; map {D}"
-#define ABC_COMMAND_CTR "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; scorr; ifraig; retime; strash; dch -f; if"
-#define ABC_COMMAND_DFL "strash; scorr; ifraig; retime; strash; dch -f; map"
-
-#define ABC_FAST_COMMAND_LIB "retime {D}; map {D}"
-#define ABC_FAST_COMMAND_CTR "retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime; if"
-#define ABC_FAST_COMMAND_DFL "retime; map"
+#define ABC_COMMAND_LIB "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}"
+#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs"
+#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map"
+
+#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}"
+#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "retime -o; if"
+#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "retime -o; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -593,7 +595,8 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir)
+ bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode,
+ const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
{
module = current_module;
map_autoidx = autoidx++;
@@ -616,7 +619,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
tempdir_name = make_temp_dir(tempdir_name);
- log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
+ log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
@@ -642,16 +645,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_script += script_file[i];
} else
abc_script += stringf("source %s", script_file.c_str());
- } else if (!lut_costs.empty())
+ } else if (!lut_costs.empty()) {
+ bool all_luts_cost_same = true;
+ for (int this_cost : lut_costs)
+ if (this_cost != lut_costs.front())
+ all_luts_cost_same = false;
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
- else if (!liberty_file.empty())
+ if (all_luts_cost_same && !fast_mode)
+ abc_script += "; lutpack";
+ } else if (!liberty_file.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
+ else if (sop_mode)
+ abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
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);
+ for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3);
+
+ for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
+
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -828,7 +845,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (count_output > 0)
{
- log_header("Executing ABC.\n");
+ log_header(design, "Executing ABC.\n");
buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
@@ -892,13 +909,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
- bool builtin_lib = liberty_file.empty() && script_file.empty() && lut_costs.empty();
+ bool builtin_lib = liberty_file.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
- parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_");
+ parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
ifs.close();
- log_header("Re-integrating ABC results.\n");
+ log_header(design, "Re-integrating ABC results.\n");
RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `netlist'.\n");
@@ -910,10 +927,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
}
std::map<std::string, int> cell_stats;
- if (builtin_lib)
+ for (auto c : mapped_mod->cells())
{
- for (auto &it : mapped_mod->cells_) {
- RTLIL::Cell *c = it.second;
+ if (builtin_lib)
+ {
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\ZERO" || c->type == "\\ONE") {
RTLIL::SigSig conn;
@@ -1052,60 +1069,57 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, cell);
continue;
}
- log_abort();
}
- }
- else
- {
- for (auto &it : mapped_mod->cells_)
- {
- RTLIL::Cell *c = it.second;
- cell_stats[RTLIL::unescape_id(c->type)]++;
- if (c->type == "\\_const0_" || c->type == "\\_const1_") {
- RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
- module->connect(conn);
- continue;
- }
- if (c->type == "\\_dff_") {
- log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
- } else {
- log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
- }
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
- design->select(module, cell);
- continue;
- }
- if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
- SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
- SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
- module->connect(my_y, my_a);
- continue;
+
+ cell_stats[RTLIL::unescape_id(c->type)]++;
+
+ if (c->type == "\\_const0_" || c->type == "\\_const1_") {
+ RTLIL::SigSig conn;
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
+ module->connect(conn);
+ continue;
+ }
+
+ if (c->type == "\\_dff_") {
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
}
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->parameters = c->parameters;
- for (auto &conn : c->connections()) {
- RTLIL::SigSpec newsig;
- for (auto &c : conn.second.chunks()) {
- if (c.width == 0)
- continue;
- log_assert(c.width == 1);
- newsig.append(module->wires_[remap_name(c.wire->name)]);
- }
- cell->setPort(conn.first, newsig);
- }
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
+ cell->setPort("\\C", clk_sig);
design->select(module, cell);
+ continue;
+ }
+
+ if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
+ SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
+ SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+ module->connect(my_y, my_a);
+ continue;
+ }
+
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+ cell->parameters = c->parameters;
+ for (auto &conn : c->connections()) {
+ RTLIL::SigSpec newsig;
+ for (auto &c : conn.second.chunks()) {
+ if (c.width == 0)
+ continue;
+ log_assert(c.width == 1);
+ newsig.append(module->wires_[remap_name(c.wire->name)]);
+ }
+ cell->setPort(conn.first, newsig);
}
+ design->select(module, cell);
}
for (auto conn : mapped_mod->connections()) {
@@ -1167,7 +1181,11 @@ struct AbcPass : public Pass {
log("library to a target architecture.\n");
log("\n");
log(" -exe <command>\n");
- log(" use the specified command name instead of \"yosys-abc\" to execute ABC.\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");
@@ -1186,9 +1204,15 @@ struct AbcPass : public Pass {
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
- log(" for -lut:\n");
+ log(" for -lut/-luts (only one LUT size):\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str());
+ log("\n");
+ log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
log("\n");
+ log(" for -sop:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_SOP).c_str());
+ log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
log("\n");
@@ -1202,9 +1226,12 @@ struct AbcPass : public Pass {
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
- log(" for -lut:\n");
+ log(" for -lut/-luts:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n");
+ log(" for -sop:\n");
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP).c_str());
+ log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
log("\n");
@@ -1227,6 +1254,14 @@ struct AbcPass : public Pass {
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("\n");
+ log(" -I <num>\n");
+ log(" maximum number of SOP inputs.\n");
+ log(" (replaces {I} in the default scripts above)\n");
+ log("\n");
+ log(" -P <num>\n");
+ log(" maximum number of SOP products.\n");
+ log(" (replaces {P} in the default scripts above)\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -1240,6 +1275,9 @@ struct AbcPass : public Pass {
log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
log(" 2, 3, .. inputs.\n");
log("\n");
+ log(" -sop\n");
+ log(" map to sum-of-product cells and inverters\n");
+ log("\n");
// log(" -mux4, -mux8, -mux16\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n");
// log(" (ignored when used with -liberty or -lut)\n");
@@ -1286,13 +1324,18 @@ struct AbcPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ABC pass (technology mapping using ABC).\n");
+ log_header(design, "Executing ABC pass (technology mapping using ABC).\n");
log_push();
+#ifdef ABCEXTERNAL
+ std::string exe_file = ABCEXTERNAL;
+#else
std::string exe_file = proc_self_dirname() + "yosys-abc";
- std::string script_file, liberty_file, constr_file, clk_str, delay_target;
+#endif
+ std::string script_file, liberty_file, constr_file, clk_str;
+ std::string delay_target, sop_inputs, sop_products;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
- bool show_tempdir = false;
+ bool show_tempdir = false, sop_mode = false;
vector<int> lut_costs;
markgroups = false;
@@ -1302,9 +1345,11 @@ struct AbcPass : public Pass {
enabled_gates.clear();
#ifdef _WIN32
+#ifndef ABCEXTERNAL
if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
exe_file = proc_self_dirname() + "..\\yosys-abc";
#endif
+#endif
size_t argidx;
char pwd [PATH_MAX];
@@ -1340,6 +1385,14 @@ struct AbcPass : public Pass {
delay_target = "-D " + args[++argidx];
continue;
}
+ if (arg == "-I" && argidx+1 < args.size()) {
+ sop_inputs = "-I " + args[++argidx];
+ continue;
+ }
+ if (arg == "-P" && argidx+1 < args.size()) {
+ sop_products = "-P " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
@@ -1374,6 +1427,10 @@ struct AbcPass : public Pass {
}
continue;
}
+ if (arg == "-sop") {
+ sop_mode = true;
+ continue;
+ }
if (arg == "-mux4") {
map_mux4 = true;
continue;
@@ -1447,7 +1504,8 @@ struct AbcPass : public Pass {
if (mod->processes.size() > 0)
log("Skipping module %s as it contains processes.\n", log_id(mod));
else if (!dff_mode || !clk_str.empty())
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
else
{
assign_map.set(mod);
@@ -1580,7 +1638,7 @@ struct AbcPass : public Pass {
assigned_cells_reverse[cell] = key;
}
- log_header("Summary of detected clock domains:\n");
+ 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)),
@@ -1591,8 +1649,8 @@ struct AbcPass : 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));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs,
- !clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir);
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode);
assign_map.set(mod);
}
}
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index db1c731e..b9ac7ade 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -41,7 +41,7 @@ struct AigmapPass : public Pass {
{
bool nand_mode = false;
- log_header("Executing AIGMAP pass (map logic to AIG).\n");
+ log_header(design, "Executing AIGMAP pass (map logic to AIG).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 3c7ff4b9..9f6dd02d 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -544,7 +544,7 @@ struct AlumaccPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
+ log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
new file mode 100644
index 00000000..f715b63e
--- /dev/null
+++ b/passes/techmap/attrmap.cc
@@ -0,0 +1,250 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+Const make_value(string &value)
+{
+ if (GetSize(value) >= 2 && value.front() == '"' && value.back() == '"')
+ return Const(value.substr(1, GetSize(value)-2));
+
+ SigSpec sig;
+ SigSpec::parse(sig, nullptr, value);
+ return sig.as_const();
+}
+
+bool match_name(string &name, IdString &id, bool ignore_case=false)
+{
+ string str1 = RTLIL::escape_id(name);
+ string str2 = id.str();
+
+ if (ignore_case)
+ return !strcasecmp(str1.c_str(), str2.c_str());
+
+ return str1 == str2;
+}
+
+bool match_value(string &value, Const &val, bool ignore_case=false)
+{
+ if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') {
+ string str1 = value.substr(1, GetSize(value)-2);
+ string str2 = val.decode_string();
+ return !strcasecmp(str1.c_str(), str2.c_str());
+ }
+
+ return make_value(value) == val;
+}
+
+struct AttrmapAction {
+ virtual ~AttrmapAction() { }
+ virtual bool apply(IdString &id, Const &val) = 0;
+};
+
+struct AttrmapTocase : AttrmapAction {
+ string name;
+ virtual bool apply(IdString &id, Const&) {
+ if (match_name(name, id, true))
+ id = RTLIL::escape_id(name);
+ return true;
+ }
+};
+
+struct AttrmapRename : AttrmapAction {
+ string old_name, new_name;
+ virtual bool apply(IdString &id, Const&) {
+ if (match_name(old_name, id))
+ id = RTLIL::escape_id(new_name);
+ return true;
+ }
+};
+
+struct AttrmapMap : AttrmapAction {
+ bool imap;
+ string old_name, new_name;
+ string old_value, new_value;
+ virtual bool apply(IdString &id, Const &val) {
+ if (match_name(old_name, id) && match_value(old_value, val, true)) {
+ id = RTLIL::escape_id(new_name);
+ val = make_value(new_value);
+ }
+ return true;
+ }
+};
+
+struct AttrmapRemove : AttrmapAction {
+ string name, value;
+ virtual bool apply(IdString &id, Const &val) {
+ return !(match_name(name, id) && match_value(value, val));
+ }
+};
+
+void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actions, dict<RTLIL::IdString, RTLIL::Const> &attributes)
+{
+ dict<RTLIL::IdString, RTLIL::Const> new_attributes;
+
+ for (auto attr : attributes)
+ {
+ auto new_attr = attr;
+ for (auto &action : actions)
+ if (!action->apply(new_attr.first, new_attr.second))
+ goto delete_this_attr;
+
+ if (new_attr != attr)
+ log("Changed attribute on %s: %s=%s -> %s=%s\n", objname.c_str(),
+ log_id(attr.first), log_const(attr.second), log_id(new_attr.first), log_const(new_attr.second));
+
+ new_attributes[new_attr.first] = new_attr.second;
+
+ if (0)
+ delete_this_attr:
+ log("Removed attribute on %s: %s=%s\n", objname.c_str(), log_id(attr.first), log_const(attr.second));
+ }
+
+ attributes.swap(new_attributes);
+}
+
+struct AttrmapPass : public Pass {
+ AttrmapPass() : Pass("attrmap", "renaming attributes") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" attrmap [options] [selection]\n");
+ log("\n");
+ log("This command renames attributes and/or mapps key/value pairs to\n");
+ log("other key/value pairs.\n");
+ log("\n");
+ log(" -tocase <name>\n");
+ log(" Match attribute names case-insensitively and set it to the specified\n");
+ log(" name.\n");
+ log("\n");
+ log(" -rename <old_name> <new_name>\n");
+ log(" Rename attributes as specified\n");
+ log("\n");
+ log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
+ log(" Map key/value pairs as indicated.\n");
+ log("\n");
+ log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n");
+ log(" Like -map, but use case-insensitive match for <old_value> when\n");
+ log(" it is a string value.\n");
+ log("\n");
+ log(" -remove <name>=<value>\n");
+ log(" Remove attributes matching this pattern.\n");
+ log("\n");
+ log(" -modattr\n");
+ log(" Operate on module attributes instead of attributes on wires and cells.\n");
+ log("\n");
+ log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n");
+ log("\n");
+ log(" attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n");
+ log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
+
+ bool modattr_mode = false;
+ vector<std::unique_ptr<AttrmapAction>> actions;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-tocase" && argidx+1 < args.size()) {
+ auto action = new AttrmapTocase;
+ action->name = args[++argidx];
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-rename" && argidx+2 < args.size()) {
+ auto action = new AttrmapRename;
+ action->old_name = args[++argidx];
+ action->new_name = args[++argidx];
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) {
+ string arg1 = args[++argidx];
+ string arg2 = args[++argidx];
+ string val1, val2;
+ size_t p = arg1.find("=");
+ if (p != string::npos) {
+ val1 = arg1.substr(p+1);
+ arg1 = arg1.substr(0, p);
+ }
+ p = arg2.find("=");
+ if (p != string::npos) {
+ val2 = arg2.substr(p+1);
+ arg2 = arg2.substr(0, p);
+ }
+ auto action = new AttrmapMap;
+ action->imap = (arg == "-map");
+ action->old_name = arg1;
+ action->new_name = arg2;
+ action->old_value = val1;
+ action->new_value = val2;
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-remove" && argidx+1 < args.size()) {
+ string arg1 = args[++argidx], val1;
+ size_t p = arg1.find("=");
+ if (p != string::npos) {
+ val1 = arg1.substr(p+1);
+ arg1 = arg1.substr(0, p);
+ }
+ auto action = new AttrmapRemove;
+ action->name = arg1;
+ action->value = val1;
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-modattr") {
+ modattr_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (modattr_mode)
+ {
+ for (auto module : design->selected_whole_modules())
+ attrmap_apply(stringf("%s", log_id(module)), actions, module->attributes);
+ }
+ else
+ {
+ for (auto module : design->selected_modules())
+ {
+ for (auto wire : module->selected_wires())
+ attrmap_apply(stringf("%s.%s", log_id(module), log_id(wire)), actions, wire->attributes);
+
+ for (auto cell : module->selected_cells())
+ attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes);
+ }
+ }
+ }
+} AttrmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
new file mode 100644
index 00000000..50eaf61d
--- /dev/null
+++ b/passes/techmap/attrmvcp.cc
@@ -0,0 +1,139 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct AttrmvcpPass : public Pass {
+ AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" attrmvcp [options] [selection]\n");
+ log("\n");
+ log("Move or copy attributes on wires to the cells driving them.\n");
+ log("\n");
+ log(" -copy\n");
+ log(" By default, attributes are moved. This will only add\n");
+ log(" the attribute to the cell, without removing it from\n");
+ log(" the wire.\n");
+ log("\n");
+ log(" -purge\n");
+ log(" If no selected cell consumes the attribute, then it is\n");
+ log(" left on the wire by default. This option will cause the\n");
+ log(" attribute to be removed from the wire, even if no selected\n");
+ log(" cell takes it.\n");
+ log("\n");
+ log(" -driven\n");
+ log(" By default, attriburtes are moved to the cell driving the\n");
+ log(" wire. With this option set it will be moved to the cell\n");
+ log(" driven by the wire instead.\n");
+ log("\n");
+ log(" -attr <attrname>\n");
+ log(" Move or copy this attribute. This option can be used\n");
+ log(" multiple times.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n");
+
+ bool copy_mode = false;
+ bool driven_mode = false;
+ bool purge_mode = false;
+ pool<IdString> attrnames;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-copy") {
+ copy_mode = true;
+ continue;
+ }
+ if (arg == "-driven") {
+ driven_mode = true;
+ continue;
+ }
+ if (arg == "-purge") {
+ purge_mode = true;
+ continue;
+ }
+ if (arg == "-attr" && argidx+1 < args.size()) {
+ attrnames.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ dict<SigBit, pool<Cell*>> net2cells;
+ SigMap sigmap(module);
+
+ for (auto cell : module->selected_cells())
+ for (auto &conn : cell->connections())
+ if (driven_mode) {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ net2cells[bit].insert(cell);
+ } else {
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ net2cells[bit].insert(cell);
+ }
+
+ for (auto wire : module->selected_wires())
+ {
+ dict<IdString, Const> new_attributes;
+
+ for (auto attr : wire->attributes)
+ {
+ bool did_something = false;
+
+ if (!attrnames.count(attr.first)) {
+ new_attributes[attr.first] = attr.second;
+ continue;
+ }
+
+ for (auto bit : sigmap(wire))
+ if (net2cells.count(bit))
+ for (auto cell : net2cells.at(bit)) {
+ log("Moving attribute %s=%s from %s.%s to %s.%s.\n", log_id(attr.first), log_const(attr.second),
+ log_id(module), log_id(wire), log_id(module), log_id(cell));
+ cell->attributes[attr.first] = attr.second;
+ did_something = true;
+ }
+
+ if (!purge_mode && !did_something)
+ new_attributes[attr.first] = attr.second;
+ }
+
+ if (!copy_mode)
+ wire->attributes.swap(new_attributes);
+ }
+ }
+ }
+} AttrmvcpPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
new file mode 100644
index 00000000..ed4e4576
--- /dev/null
+++ b/passes/techmap/deminout.cc
@@ -0,0 +1,116 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DeminoutPass : public Pass {
+ DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" deminout [options] [selection]\n");
+ log("\n");
+ log("\"Demote\" inout ports to input or output ports, if possible.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-bits") {
+ // flag_bits = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ bool keep_running = true;
+
+ while (keep_running)
+ {
+ keep_running = false;
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ pool<SigBit> bits_written, bits_used, bits_inout;
+ dict<SigBit, int> bits_numports;
+
+ for (auto wire : module->wires())
+ if (wire->port_id)
+ for (auto bit : sigmap(wire))
+ bits_numports[bit]++;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ {
+ bool cellport_out = cell->output(conn.first) || !cell->known();
+ bool cellport_in = cell->input(conn.first) || !cell->known();
+
+ if (cellport_out && cellport_in)
+ for (auto bit : sigmap(conn.second))
+ bits_inout.insert(bit);
+
+ if (cellport_out)
+ for (auto bit : sigmap(conn.second))
+ bits_written.insert(bit);
+
+ if (cellport_in)
+ for (auto bit : sigmap(conn.second))
+ bits_used.insert(bit);
+ }
+
+ for (auto wire : module->selected_wires())
+ if (wire->port_input && wire->port_output)
+ {
+ bool new_input = false;
+ bool new_output = false;
+
+ for (auto bit : sigmap(wire))
+ {
+ if (bits_numports[bit] > 1 || bits_inout.count(bit))
+ new_input = true, new_output = true;
+
+ if (bits_written.count(bit))
+ new_output = true;
+ else if (bits_used.count(bit))
+ new_input = true;
+ }
+
+ if (new_input != new_output) {
+ log("Demoting inout port %s.%s to %s.\n", log_id(module), log_id(wire), new_input ? "input" : "output");
+ wire->port_input = new_input;
+ wire->port_output = new_output;
+ keep_running = true;
+ }
+ }
+ }
+ }
+ }
+} DeminoutPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 51bfaade..1b8920bb 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -285,7 +285,7 @@ struct Dff2dffePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
+ log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
bool unmap_mode = false;
dict<IdString, IdString> direct_dict;
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index e0273f43..d737b342 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -41,7 +41,7 @@ struct DffinitPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFINIT pass (set INIT param on FF cells).\n");
+ log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
dict<IdString, dict<IdString, IdString>> ff_types;
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 4d7a1a70..c8104fb7 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -108,6 +108,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
+ bool best_cell_noninv = false;
double best_cell_area = 0;
if (ast->id != "library")
@@ -155,6 +156,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
int num_pins = 0;
bool found_output = false;
+ bool found_noninv_output = false;
for (auto pin : cell->children)
{
if (pin->id != "pin" || pin->args.size() != 1)
@@ -175,10 +177,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
value.erase(pos, 1);
if (value == ff->args[0]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ if (cell_next_pol)
+ found_noninv_output = true;
found_output = true;
} else
if (value == ff->args[1]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
+ if (!cell_next_pol)
+ found_noninv_output = true;
found_output = true;
}
}
@@ -187,7 +193,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && num_pins > best_cell_pins))
+ if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
@@ -196,12 +202,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
best_cell = cell;
best_cell_pins = num_pins;
best_cell_area = area;
+ best_cell_noninv = found_noninv_output;
best_cell_ports.swap(this_cell_ports);
continue_cell_loop:;
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
+ best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
cell_mappings[cell_type].cell_name = cell_type;
cell_mappings[cell_type].ports["C"] = 'C';
@@ -221,6 +229,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
+ bool best_cell_noninv = false;
double best_cell_area = 0;
if (ast->id != "library")
@@ -260,6 +269,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
int num_pins = 0;
bool found_output = false;
+ bool found_noninv_output = false;
for (auto pin : cell->children)
{
if (pin->id != "pin" || pin->args.size() != 1)
@@ -280,10 +290,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
value.erase(pos, 1);
if (value == ff->args[0]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ if (cell_next_pol)
+ found_noninv_output = true;
found_output = true;
} else
if (value == ff->args[1]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
+ if (!cell_next_pol)
+ found_noninv_output = true;
found_output = true;
}
}
@@ -292,7 +306,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && num_pins > best_cell_pins))
+ if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
@@ -301,12 +315,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
best_cell = cell;
best_cell_pins = num_pins;
best_cell_area = area;
+ best_cell_noninv = found_noninv_output;
best_cell_ports.swap(this_cell_ports);
continue_cell_loop:;
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
+ best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
cell_mappings[cell_type].cell_name = cell_type;
cell_mappings[cell_type].ports["C"] = 'C';
@@ -531,7 +547,7 @@ struct DfflibmapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
+ log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
std::string liberty_file;
bool prepare_mode = false;
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
index 8dcbb4ed..0d4d5362 100644
--- a/passes/techmap/dffsr2dff.cc
+++ b/passes/techmap/dffsr2dff.cc
@@ -188,7 +188,7 @@ struct Dffsr2dffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
+ log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index fc73177c..71e29c60 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -442,7 +442,7 @@ struct ExtractPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing EXTRACT pass (map subcircuits to cells).\n");
+ log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n");
log_push();
SubCircuitSolver solver;
@@ -627,7 +627,7 @@ struct ExtractPass : public Pass {
std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
std::vector<RTLIL::Module*> needle_list;
- log_header("Creating graphs for SubCircuit library.\n");
+ log_header(design, "Creating graphs for SubCircuit library.\n");
if (!mine_mode)
for (auto &mod_it : map->modules_) {
@@ -654,7 +654,7 @@ struct ExtractPass : public Pass {
if (!mine_mode)
{
std::vector<SubCircuit::Solver::Result> results;
- log_header("Running solver from SubCircuit library.\n");
+ log_header(design, "Running solver from SubCircuit library.\n");
std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList);
@@ -667,7 +667,7 @@ struct ExtractPass : public Pass {
if (results.size() > 0)
{
- log_header("Substitute SubCircuits with cells.\n");
+ log_header(design, "Substitute SubCircuits with cells.\n");
for (int i = 0; i < int(results.size()); i++) {
auto &result = results[i];
@@ -688,7 +688,7 @@ struct ExtractPass : public Pass {
{
std::vector<SubCircuit::Solver::MineResult> results;
- log_header("Running miner from SubCircuit library.\n");
+ log_header(design, "Running miner from SubCircuit library.\n");
solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod);
map = new RTLIL::Design;
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index a0bd2f9a..82cecac2 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -76,7 +76,7 @@ struct HilomapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HILOMAP pass (mapping to constant drivers).\n");
+ log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n");
hicell_celltype = std::string();
hicell_portname = std::string();
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
new file mode 100644
index 00000000..aa81468d
--- /dev/null
+++ b/passes/techmap/insbuf.cc
@@ -0,0 +1,94 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct InsbufPass : public Pass {
+ InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" insbuf [options] [selection]\n");
+ log("\n");
+ log("Insert buffer cells into the design for directly connected wires.\n");
+ log("\n");
+ log(" -buf <celltype> <in-portname> <out-portname>\n");
+ log(" Use the given cell type instead of $_BUF_. (Notice that the next\n");
+ log(" call to \"clean\" will remove all $_BUF_ in the design.)\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n");
+
+ std::string celltype = "$_BUF_", in_portname = "\\A", out_portname = "\\Y";
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-buf" && argidx+3 < args.size()) {
+ celltype = args[++argidx];
+ in_portname = args[++argidx];
+ out_portname = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ std::vector<RTLIL::SigSig> new_connections;
+
+ for (auto &conn : module->connections())
+ {
+ RTLIL::SigSig new_conn;
+
+ for (int i = 0; i < GetSize(conn.first); i++)
+ {
+ SigBit lhs = conn.first[i];
+ SigBit rhs = conn.second[i];
+
+ if (lhs.wire && !design->selected(module, lhs.wire)) {
+ new_conn.first.append(lhs);
+ new_conn.second.append(rhs);
+ continue;
+ }
+
+ Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(in_portname), rhs);
+ cell->setPort(RTLIL::escape_id(out_portname), lhs);
+ log("Added %s.%s: %s -> %s\n", log_id(module), log_id(cell), log_signal(rhs), log_signal(lhs));
+ }
+
+ if (GetSize(new_conn.first))
+ new_connections.push_back(new_conn);
+ }
+
+ module->new_connections(new_connections);
+ }
+ }
+} InsbufPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 9dab40ca..4acbf7c0 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -17,9 +17,8 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -48,12 +47,23 @@ struct IopadmapPass : public Pass {
log(" Map module input ports to the given cell type with the\n");
log(" given output port name. if a 2nd portname is given, the\n");
log(" signal is passed through the pad call, using the 2nd\n");
- log(" portname as input.\n");
+ log(" portname as the port facing the module port.\n");
log("\n");
log(" -outpad <celltype> <portname>[:<portname>]\n");
log(" -inoutpad <celltype> <portname>[:<portname>]\n");
log(" Similar to -inpad, but for output and inout ports.\n");
log("\n");
+ log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n");
+ log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
+ log(" over the other -outpad cell. The first portname is the enable input\n");
+ log(" of the tristate driver.\n");
+ log("\n");
+ log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n");
+ log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
+ log(" over the other -inoutpad cell. The first portname is the enable input\n");
+ log(" of the tristate driver and the 2nd portname is the internal output\n");
+ log(" buffering the external signal.\n");
+ log("\n");
log(" -widthparam <param_name>\n");
log(" Use the specified parameter name to set the port width.\n");
log("\n");
@@ -65,14 +75,18 @@ struct IopadmapPass : public Pass {
log(" are wider. (the default behavior is to create word-wide\n");
log(" buffers using -widthparam to set the word size on the cell.)\n");
log("\n");
+ log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
+ 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 widthparam, nameparam;
bool flag_bits = false;
@@ -98,6 +112,21 @@ struct IopadmapPass : public Pass {
split_portname_pair(inoutpad_portname, inoutpad_portname2);
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);
+ 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);
+ continue;
+ }
if (arg == "-widthparam" && argidx+1 < args.size()) {
widthparam = args[++argidx];
continue;
@@ -116,12 +145,132 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
+ dict<IdString, pool<int>> skip_wires;
+
+ if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$_TBUF_") {
+ SigBit bit = sigmap(cell->getPort("\\Y").as_bit());
+ tbuf_bits[bit].first = cell->name;
+ }
+
+ 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);
+
+ for (auto wire : module->selected_wires())
+ {
+ if (!wire->port_output)
+ 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;
+
+ auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
+ Cell *tbuf_cell = module->cell(tbuf_cache.first);
+
+ if (tbuf_cell == nullptr)
+ continue;
+
+ SigBit en_sig = tbuf_cell->getPort("\\E").as_bit();
+ SigBit data_sig = tbuf_cell->getPort("\\A").as_bit();
+
+ if (wire->port_input && !tinoutpad_celltype.empty())
+ {
+ 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->attributes["\\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);
+ }
+ }
+
+
+ module->remove(tbuf_cell);
+ skip_wires[wire->name].insert(i);
+ continue;
+ }
+
+ if (!wire->port_input && !toutpad_celltype.empty())
+ {
+ 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->attributes["\\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);
+ }
+ }
+
+ module->remove(tbuf_cell);
+ skip_wires[wire->name].insert(i);
+ continue;
+ }
+ }
+ }
+ }
+
for (auto wire : module->selected_wires())
{
if (!wire->port_id)
continue;
std::string celltype, portname, portname2;
+ pool<int> skip_bit_indices;
+
+ if (skip_wires.count(wire->name)) {
+ if (!flag_bits)
+ continue;
+ skip_bit_indices = skip_wires.at(wire->name);
+ }
if (wire->port_input && !wire->port_output) {
if (inpad_celltype.empty()) {
@@ -163,12 +312,21 @@ struct IopadmapPass : public Pass {
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));
+ continue;
+ }
+
RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i));
if (!portname2.empty())
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index fe55e499..2bb0bd8b 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -67,7 +67,7 @@ struct Lut2muxPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing LUT2MUX pass (mapping to constant drivers).\n");
+ log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index d5b8fe80..32569d07 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -379,7 +379,7 @@ struct MaccmapPass : public Pass {
{
bool unmap_mode = false;
- log_header("Executing MACCMAP pass (map $macc cells).\n");
+ log_header(design, "Executing MACCMAP pass (map $macc cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 514c3365..1dc64958 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -581,7 +581,7 @@ struct MuxcoverPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing MUXCOVER pass (mapping to wider MUXes).\n");
+ log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n");
bool use_mux4 = false;
bool use_mux8 = false;
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 7ece4005..6fcdf82b 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -26,6 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct NlutmapConfig
{
vector<int> luts;
+ bool assert_mode = false;
};
struct NlutmapWorker
@@ -64,7 +65,7 @@ struct NlutmapWorker
{
vector<int> available_luts = config.luts;
- while (!available_luts.empty())
+ while (GetSize(available_luts) > 1)
{
int n_luts = available_luts.back();
int lut_size = GetSize(available_luts);
@@ -84,7 +85,7 @@ struct NlutmapWorker
if (cell->type != "$lut" || mapped_cells.count(cell))
continue;
- if (GetSize(cell->getPort("\\A")) == lut_size)
+ if (GetSize(cell->getPort("\\A")) == lut_size || lut_size == 2)
candidate_ratings[cell] = 0;
for (auto &conn : cell->connections())
@@ -116,6 +117,12 @@ struct NlutmapWorker
available_luts.back() += n_luts;
}
+ if (config.assert_mode) {
+ for (auto cell : module->cells())
+ if (cell->type == "$lut" && !mapped_cells.count(cell))
+ log_error("Insufficient number of LUTs to map all logic cells!\n");
+ }
+
run_abc(0);
}
};
@@ -135,6 +142,9 @@ struct NlutmapPass : public Pass {
log(" The number of LUTs with 1, 2, 3, ... inputs that are\n");
log(" available in the target architecture.\n");
log("\n");
+ log(" -assert\n");
+ log(" Create an error if not all logic can be mapped\n");
+ log("\n");
log("Excess logic that does not fit into the specified LUTs is mapped back\n");
log("to generic logic gates ($_AND_, etc.).\n");
log("\n");
@@ -143,7 +153,7 @@ struct NlutmapPass : public Pass {
{
NlutmapConfig config;
- log_header("Executing NLUTMAP pass (mapping to constant drivers).\n");
+ log_header(design, "Executing NLUTMAP pass (mapping to constant drivers).\n");
log_push();
size_t argidx;
@@ -156,6 +166,10 @@ struct NlutmapPass : public Pass {
config.luts.push_back(atoi(token.c_str()));
continue;
}
+ if (args[argidx] == "-assert") {
+ config.assert_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index 3c12bfd0..c626dbcc 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -78,7 +78,7 @@ struct PmuxtreePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PMUXTREE pass.\n");
+ log_header(design, "Executing PMUXTREE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
new file mode 100644
index 00000000..6936b499
--- /dev/null
+++ b/passes/techmap/shregmap.cc
@@ -0,0 +1,584 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ShregmapTech
+{
+ virtual ~ShregmapTech() { }
+ virtual bool analyze(vector<int> &taps) = 0;
+ virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
+};
+
+struct ShregmapOptions
+{
+ int minlen, maxlen;
+ int keep_before, keep_after;
+ bool zinit, init, params, ffe;
+ dict<IdString, pair<IdString, IdString>> ffcells;
+ ShregmapTech *tech;
+
+ ShregmapOptions()
+ {
+ minlen = 2;
+ maxlen = 0;
+ keep_before = 0;
+ keep_after = 0;
+ zinit = false;
+ init = false;
+ params = false;
+ ffe = false;
+ tech = nullptr;
+ }
+};
+
+struct ShregmapTechGreenpak4 : ShregmapTech
+{
+ bool analyze(vector<int> &taps)
+ {
+ if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
+ taps.clear();
+ return true;
+ }
+
+ if (GetSize(taps) > 2)
+ return false;
+
+ if (taps.back() > 16) return false;
+
+ return true;
+ }
+
+ bool fixup(Cell *cell, dict<int, SigBit> &taps)
+ {
+ auto D = cell->getPort("\\D");
+ auto C = cell->getPort("\\C");
+
+ auto newcell = cell->module->addCell(NEW_ID, "\\GP_SHREG");
+ newcell->setPort("\\nRST", State::S1);
+ newcell->setPort("\\CLK", C);
+ newcell->setPort("\\IN", D);
+
+ int i = 0;
+ for (auto tap : taps) {
+ newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second);
+ newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1);
+ i++;
+ }
+
+ cell->setParam("\\OUTA_INVERT", 0);
+ return false;
+ }
+};
+
+struct ShregmapWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ const ShregmapOptions &opts;
+ int dff_count, shreg_count;
+
+ pool<Cell*> remove_cells;
+ pool<SigBit> remove_init;
+
+ dict<SigBit, bool> sigbit_init;
+ dict<SigBit, Cell*> sigbit_chain_next;
+ dict<SigBit, Cell*> sigbit_chain_prev;
+ pool<SigBit> sigbit_with_non_chain_users;
+ pool<Cell*> chain_start_cells;
+
+ void make_sigbit_chain_next_prev()
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output || wire->get_bool_attribute("\\keep")) {
+ for (auto bit : sigmap(wire))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 && !opts.zinit)
+ sigbit_init[initsig[i]] = false;
+ else if (initval[i] == State::S1)
+ sigbit_init[initsig[i]] = true;
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep"))
+ {
+ IdString d_port = opts.ffcells.at(cell->type).first;
+ IdString q_port = opts.ffcells.at(cell->type).second;
+
+ SigBit d_bit = sigmap(cell->getPort(d_port).as_bit());
+ SigBit q_bit = sigmap(cell->getPort(q_port).as_bit());
+
+ if (opts.init || sigbit_init.count(q_bit) == 0)
+ {
+ if (sigbit_chain_next.count(d_bit)) {
+ sigbit_with_non_chain_users.insert(d_bit);
+ } else
+ sigbit_chain_next[d_bit] = cell;
+
+ sigbit_chain_prev[q_bit] = cell;
+ continue;
+ }
+ }
+
+ for (auto conn : cell->connections())
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+ }
+
+ void find_chain_start_cells()
+ {
+ for (auto it : sigbit_chain_next)
+ {
+ if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first))
+ goto start_cell;
+
+ if (sigbit_chain_prev.count(it.first) != 0)
+ {
+ Cell *c1 = sigbit_chain_prev.at(it.first);
+ Cell *c2 = it.second;
+
+ if (c1->type != c2->type)
+ goto start_cell;
+
+ if (c1->parameters != c2->parameters)
+ goto start_cell;
+
+ IdString d_port = opts.ffcells.at(c1->type).first;
+ IdString q_port = opts.ffcells.at(c1->type).second;
+
+ auto c1_conn = c1->connections();
+ auto c2_conn = c1->connections();
+
+ c1_conn.erase(d_port);
+ c1_conn.erase(q_port);
+
+ c2_conn.erase(d_port);
+ c2_conn.erase(q_port);
+
+ if (c1_conn != c2_conn)
+ goto start_cell;
+
+ continue;
+ }
+
+ start_cell:
+ chain_start_cells.insert(it.second);
+ }
+ }
+
+ vector<Cell*> create_chain(Cell *start_cell)
+ {
+ vector<Cell*> chain;
+
+ Cell *c = start_cell;
+ while (c != nullptr)
+ {
+ chain.push_back(c);
+
+ IdString q_port = opts.ffcells.at(c->type).second;
+ SigBit q_bit = sigmap(c->getPort(q_port).as_bit());
+
+ if (sigbit_chain_next.count(q_bit) == 0)
+ break;
+
+ c = sigbit_chain_next.at(q_bit);
+ if (chain_start_cells.count(c) != 0)
+ break;
+ }
+
+ return chain;
+ }
+
+ void process_chain(vector<Cell*> &chain)
+ {
+ if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after)
+ return;
+
+ int cursor = opts.keep_before;
+ while (cursor < GetSize(chain) - opts.keep_after)
+ {
+ int depth = GetSize(chain) - opts.keep_after - cursor;
+
+ if (opts.maxlen > 0)
+ depth = std::min(opts.maxlen, depth);
+
+ Cell *first_cell = chain[cursor];
+ IdString q_port = opts.ffcells.at(first_cell->type).second;
+ dict<int, SigBit> taps_dict;
+
+ if (opts.tech)
+ {
+ vector<SigBit> qbits;
+ vector<int> taps;
+
+ for (int i = 0; i < depth; i++)
+ {
+ Cell *cell = chain[cursor+i];
+ auto qbit = sigmap(cell->getPort(q_port));
+ qbits.push_back(qbit);
+
+ if (sigbit_with_non_chain_users.count(qbit))
+ taps.push_back(i);
+ }
+
+ while (depth > 0)
+ {
+ if (taps.empty() || taps.back() < depth-1)
+ taps.push_back(depth-1);
+
+ if (opts.tech->analyze(taps))
+ break;
+
+ taps.pop_back();
+ depth--;
+ }
+
+ depth = 0;
+ for (auto tap : taps) {
+ taps_dict[tap] = qbits.at(tap);
+ log_assert(depth < tap+1);
+ depth = tap+1;
+ }
+ }
+
+ if (depth < 2) {
+ cursor++;
+ continue;
+ }
+
+ Cell *last_cell = chain[cursor+depth-1];
+
+ log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n",
+ log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth);
+
+ dff_count += depth;
+ shreg_count += 1;
+
+ string shreg_cell_type_str = "$__SHREG";
+ if (opts.params) {
+ shreg_cell_type_str += "_";
+ } else {
+ if (first_cell->type[1] != '_')
+ shreg_cell_type_str += "_";
+ shreg_cell_type_str += first_cell->type.substr(1);
+ }
+
+ if (opts.init) {
+ vector<State> initval;
+ for (int i = depth-1; i >= 0; i--) {
+ SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
+ if (sigbit_init.count(bit) == 0)
+ initval.push_back(State::Sx);
+ else if (sigbit_init.at(bit))
+ initval.push_back(State::S1);
+ else
+ initval.push_back(State::S0);
+ remove_init.insert(bit);
+ }
+ first_cell->setParam("\\INIT", initval);
+ }
+
+ if (opts.zinit)
+ for (int i = depth-1; i >= 0; i--) {
+ SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
+ remove_init.insert(bit);
+ }
+
+ if (opts.params)
+ {
+ int param_clkpol = -1;
+ int param_enpol = 2;
+
+ if (first_cell->type == "$_DFF_N_") param_clkpol = 0;
+ if (first_cell->type == "$_DFF_P_") param_clkpol = 1;
+
+ if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0;
+ if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1;
+ if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0;
+ if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1;
+
+ log_assert(param_clkpol >= 0);
+ first_cell->setParam("\\CLKPOL", param_clkpol);
+ if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol);
+ }
+
+ first_cell->type = shreg_cell_type_str;
+ first_cell->setPort(q_port, last_cell->getPort(q_port));
+ first_cell->setParam("\\DEPTH", depth);
+
+ if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict))
+ remove_cells.insert(first_cell);
+
+ for (int i = 1; i < depth; i++)
+ remove_cells.insert(chain[cursor+i]);
+ cursor += depth;
+ }
+ }
+
+ void cleanup()
+ {
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec initsig = sigmap(wire);
+ Const &initval = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ if (remove_init.count(initsig[i]))
+ initval[i] = State::Sx;
+
+ if (SigSpec(initval).is_fully_undef())
+ wire->attributes.erase("\\init");
+ }
+
+ remove_cells.clear();
+ sigbit_chain_next.clear();
+ sigbit_chain_prev.clear();
+ chain_start_cells.clear();
+ }
+
+ ShregmapWorker(Module *module, const ShregmapOptions &opts) :
+ module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
+ {
+ make_sigbit_chain_next_prev();
+ find_chain_start_cells();
+
+ for (auto c : chain_start_cells) {
+ vector<Cell*> chain = create_chain(c);
+ process_chain(chain);
+ }
+
+ cleanup();
+ }
+};
+
+struct ShregmapPass : public Pass {
+ ShregmapPass() : Pass("shregmap", "map shift registers") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" shregmap [options] [selection]\n");
+ log("\n");
+ log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register\n");
+ log("primitives. The generated shift register will be of type $__SHREG_DFF_[NP]_ and\n");
+ log("will use the same interface as the original $_DFF_*_ cells. The cell parameter\n");
+ log("'DEPTH' will contain the depth of the shift register. Use a target-specific\n");
+ log("'techmap' map file to convert those cells to the actual target cells.\n");
+ log("\n");
+ log(" -minlen N\n");
+ log(" minimum length of shift register (default = 2)\n");
+ log(" (this is the length after -keep_before and -keep_after)\n");
+ log("\n");
+ log(" -maxlen N\n");
+ log(" maximum length of shift register (default = no limit)\n");
+ log(" larger chains will be mapped to multiple shift register instances\n");
+ log("\n");
+ log(" -keep_before N\n");
+ log(" number of DFFs to keep before the shift register (default = 0)\n");
+ log("\n");
+ log(" -keep_after N\n");
+ log(" number of DFFs to keep after the shift register (default = 0)\n");
+ log("\n");
+ log(" -clkpol pos|neg|any\n");
+ log(" limit match to only positive or negative edge clocks. (default = any)\n");
+ log("\n");
+ log(" -enpol pos|neg|none|any_or_none|any\n");
+ log(" limit match to FFs with the specified enable polarity. (default = none)\n");
+ log("\n");
+ log(" -match <cell_type>[:<d_port_name>:<q_port_name>]\n");
+ log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n");
+ log(" ':<d_port_name>:<q_port_name>' is omitted then 'D' and 'Q' is used\n");
+ log(" by default. E.g. the option '-clkpol pos' is just an alias for\n");
+ log(" '-match $_DFF_P_', which is an alias for '-match $_DFF_P_:D:Q'.\n");
+ log("\n");
+ log(" -params\n");
+ log(" instead of encoding the clock and enable polarity in the cell name by\n");
+ log(" deriving from the original cell name, simply name all generated cells\n");
+ log(" $__SHREG_ and use CLKPOL and ENPOL parameters. An ENPOL value of 2 is\n");
+ log(" used to denote cells without enable input. The ENPOL parameter is\n");
+ log(" omitted when '-enpol none' (or no -enpol option) is passed.\n");
+ log("\n");
+ log(" -zinit\n");
+ log(" assume the shift register is automatically zero-initialized, so it\n");
+ log(" becomes legal to merge zero initialized FFs into the shift register.\n");
+ log("\n");
+ log(" -init\n");
+ log(" map initialized registers to the shift reg, add an INIT parameter to\n");
+ log(" generated cells with the initialization value. (first bit to shift out\n");
+ log(" in LSB position)\n");
+ log("\n");
+ log(" -tech greenpak4\n");
+ log(" map to greenpak4 shift registers.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ShregmapOptions opts;
+ string clkpol, enpol;
+
+ log_header(design, "Executing SHREGMAP pass (map shift registers).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-clkpol" && argidx+1 < args.size()) {
+ clkpol = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-enpol" && argidx+1 < args.size()) {
+ enpol = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-match" && argidx+1 < args.size()) {
+ vector<string> match_args = split_tokens(args[++argidx], ":");
+ if (GetSize(match_args) < 2)
+ match_args.push_back("D");
+ if (GetSize(match_args) < 3)
+ match_args.push_back("Q");
+ IdString id_cell_type(RTLIL::escape_id(match_args[0]));
+ IdString id_d_port_name(RTLIL::escape_id(match_args[1]));
+ IdString id_q_port_name(RTLIL::escape_id(match_args[2]));
+ opts.ffcells[id_cell_type] = make_pair(id_d_port_name, id_q_port_name);
+ continue;
+ }
+ if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
+ opts.minlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-maxlen" && argidx+1 < args.size()) {
+ opts.maxlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-keep_before" && argidx+1 < args.size()) {
+ opts.keep_before = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-keep_after" && argidx+1 < args.size()) {
+ opts.keep_after = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-tech" && argidx+1 < args.size() && opts.tech == nullptr) {
+ string tech = args[++argidx];
+ if (tech == "greenpak4") {
+ clkpol = "pos";
+ opts.zinit = true;
+ opts.tech = new ShregmapTechGreenpak4;
+ } else {
+ argidx--;
+ break;
+ }
+ continue;
+ }
+ if (args[argidx] == "-zinit") {
+ opts.zinit = true;
+ continue;
+ }
+ if (args[argidx] == "-init") {
+ opts.init = true;
+ continue;
+ }
+ if (args[argidx] == "-params") {
+ opts.params = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (opts.zinit && opts.init)
+ log_cmd_error("Options -zinit and -init are exclusive!\n");
+
+ if (opts.ffcells.empty())
+ {
+ bool clk_pos = clkpol == "" || clkpol == "pos" || clkpol == "any";
+ bool clk_neg = clkpol == "" || clkpol == "neg" || clkpol == "any";
+
+ bool en_none = enpol == "" || enpol == "none" || enpol == "any_or_none";
+ bool en_pos = enpol == "pos" || enpol == "any" || enpol == "any_or_none";
+ bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none";
+
+ if (clk_pos && en_none)
+ opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_neg && en_none)
+ opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (clk_pos && en_pos)
+ opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_pos && en_neg)
+ opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (clk_neg && en_pos)
+ opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_neg && en_neg)
+ opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (en_pos || en_neg)
+ opts.ffe = true;
+ }
+ else
+ {
+ if (!clkpol.empty())
+ log_cmd_error("Options -clkpol and -match are exclusive!\n");
+ if (!enpol.empty())
+ log_cmd_error("Options -enpol and -match are exclusive!\n");
+ if (opts.params)
+ log_cmd_error("Options -params and -match are exclusive!\n");
+ }
+
+ int dff_count = 0;
+ int shreg_count = 0;
+
+ for (auto module : design->selected_modules()) {
+ ShregmapWorker worker(module, opts);
+ dff_count += worker.dff_count;
+ shreg_count += worker.shreg_count;
+ }
+
+ log("Converted %d dff cells into %d shift registers.\n", dff_count, shreg_count);
+
+ if (opts.tech != nullptr) {
+ delete opts.tech;
+ opts.tech = nullptr;
+ }
+ }
+} ShregmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index f6ac3964..0fb64734 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -321,6 +321,36 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(cell->getPort("\\Y"), lut_data);
}
+void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ SigSpec ctrl = cell->getPort("\\A");
+ SigSpec table = cell->getParam("\\TABLE");
+
+ int width = cell->getParam("\\WIDTH").as_int();
+ int depth = cell->getParam("\\DEPTH").as_int();
+ table.extend_u0(2 * width * depth);
+
+ SigSpec products;
+
+ for (int i = 0; i < depth; i++) {
+ SigSpec in, pat;
+ for (int j = 0; j < width; j++) {
+ if (table[2*i*width + 2*j + 0] == State::S1) {
+ in.append(ctrl[j]);
+ pat.append(State::S0);
+ }
+ if (table[2*i*width + 2*j + 1] == State::S1) {
+ in.append(ctrl[j]);
+ pat.append(State::S1);
+ }
+ }
+
+ products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1);
+ }
+
+ module->connect(cell->getPort("\\Y"), module->ReduceOr(NEW_ID, products));
+}
+
void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
@@ -498,6 +528,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
mappers["$mux"] = simplemap_mux;
mappers["$tribuf"] = simplemap_tribuf;
mappers["$lut"] = simplemap_lut;
+ mappers["$sop"] = simplemap_sop;
mappers["$slice"] = simplemap_slice;
mappers["$concat"] = simplemap_concat;
mappers["$sr"] = simplemap_sr;
@@ -543,7 +574,7 @@ struct SimplemapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
+ log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 5334ebfa..b2cc492b 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -234,8 +234,10 @@ struct TechmapWorker
tpl_written_bits.insert(bit);
SigMap port_signal_map;
+ SigSig port_signal_assign;
- for (auto &it : cell->connections()) {
+ for (auto &it : cell->connections())
+ {
RTLIL::IdString portname = it.first;
if (positional_ports.count(portname) > 0)
portname = positional_ports.at(portname);
@@ -244,16 +246,22 @@ struct TechmapWorker
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
continue;
}
+
RTLIL::Wire *w = tpl->wires_.at(portname);
- RTLIL::SigSig c;
+ RTLIL::SigSig c, extra_connect;
+
if (w->port_output && !w->port_input) {
c.first = it.second;
c.second = RTLIL::SigSpec(w);
apply_prefix(cell->name.str(), c.second, module);
+ extra_connect.first = c.second;
+ extra_connect.second = c.first;
} else if (!w->port_output && w->port_input) {
c.first = RTLIL::SigSpec(w);
c.second = it.second;
apply_prefix(cell->name.str(), c.first, module);
+ extra_connect.first = c.first;
+ extra_connect.second = c.second;
} else {
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
apply_prefix(cell->name.str(), sig_tpl_pf, module);
@@ -266,28 +274,48 @@ struct TechmapWorker
c.second.append(sig_mod[i]);
}
}
+ extra_connect.first = sig_tpl_pf;
+ extra_connect.second = sig_mod;
}
+
if (c.second.size() > c.first.size())
c.second.remove(c.first.size(), c.second.size() - c.first.size());
+
if (c.second.size() < c.first.size())
c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size()));
+
log_assert(c.first.size() == c.second.size());
- if (flatten_mode) {
+
+ if (flatten_mode)
+ {
// more conservative approach:
// connect internal and external wires
+
if (sigmaps.count(module) == 0)
sigmaps[module].set(module);
+
if (sigmaps.at(module)(c.first).has_const())
log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n",
log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second));
+
module->connect(c);
- } else {
+ }
+ else
+ {
// approach that yields nicer outputs:
// replace internal wires that are connected to external wires
+
if (w->port_output)
port_signal_map.add(c.second, c.first);
else
port_signal_map.add(c.first, c.second);
+
+ for (auto &attr : w->attributes) {
+ if (attr.first == "\\src")
+ continue;
+ module->connect(extra_connect);
+ break;
+ }
}
}
@@ -611,7 +639,7 @@ struct TechmapWorker
if (techmap_cache.count(key) > 0) {
tpl = techmap_cache[key];
} else {
- if (cell->parameters.size() != 0) {
+ if (parameters.size() != 0) {
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name);
log_continue = true;
@@ -779,7 +807,7 @@ struct TechmapWorker
if (recursive_mode) {
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
@@ -790,7 +818,7 @@ struct TechmapWorker
continue;
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
@@ -833,7 +861,7 @@ struct TechmapWorker
}
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
@@ -976,7 +1004,7 @@ struct TechmapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing TECHMAP pass (map to technology primitives).\n");
+ log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
TechmapWorker worker;
@@ -1108,7 +1136,7 @@ struct FlattenPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FLATTEN pass (flatten design).\n");
+ log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
extra_args(args, 1, design);
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index d0564b4e..03629082 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -160,7 +160,7 @@ struct TribufPass : public Pass {
{
TribufConfig config;
- log_header("Executing TRIBUF pass.\n");
+ log_header(design, "Executing TRIBUF pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index bb516fca..cb31056f 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -71,16 +71,21 @@ static std::string idy(std::string str1, std::string str2 = std::string(), std::
return id(str1);
}
-static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
+static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int seed)
{
+ f << stringf("`ifndef outfile\n");
+ f << stringf("\t`define outfile \"/dev/stdout\"\n");
+ f << stringf("`endif\n");
+
f << stringf("module testbench;\n\n");
- f << stringf("integer i;\n\n");
+ f << stringf("integer i;\n");
+ f << stringf("integer file;\n\n");
f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
- f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL)));
+ f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(NULL)));
f << stringf("reg [31:0] xorshift128_t;\n\n");
f << stringf("task xorshift128;\n");
f << stringf("begin\n");
@@ -150,6 +155,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -157,6 +163,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -167,6 +174,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
continue;
f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
}
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -179,6 +187,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("\txorshift128;\n");
f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
}
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -206,61 +215,70 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("task %s;\n", idy(mod->name.str(), "print_status").c_str());
f << stringf("begin\n");
- f << stringf("\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
+ f << stringf("\t$fdisplay(file, \"#OUT# %%b %%b %%b %%t %%d\", {");
if (signal_in.size())
for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
+ header2 += "\"";
header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
+ header1.back()[0] = shorthand;
+ shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
}
else {
f << stringf(" 1'bx");
- header2 += "#";
+ header2 += ", \"#\"";
}
f << stringf(" }, {");
- header2 += " ";
+ header2 += ", \" \"";
if (signal_clk.size()) {
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
+ header2 += "\"";
header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
+ header1.back()[0] = shorthand;
+ shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
}
} else {
f << stringf(" 1'bx");
- header2 += "#";
+ header2 += ", \"#\"";
}
f << stringf(" }, {");
- header2 += " ";
+ header2 += ", \" \"";
if (signal_out.size()) {
for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
+ header2 += "\"";
header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
+ header1.back()[0] = shorthand;
+ shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
}
} else {
f << stringf(" 1'bx");
- header2 += "#";
+ header2 += ", \"#\"";
}
f << stringf(" }, $time, i);\n");
f << stringf("end\n");
@@ -268,17 +286,17 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("task %s;\n", idy(mod->name.str(), "print_header").c_str());
f << stringf("begin\n");
- f << stringf("\t$display(\"#OUT#\");\n");
+ f << stringf("\t$fdisplay(file, \"#OUT#\");\n");
for (auto &hdr : header1)
- f << stringf("\t$display(\"#OUT# %s\");\n", hdr.c_str());
- f << stringf("\t$display(\"#OUT#\");\n");
- f << stringf("\t$display(\"#OUT# %s\");\n", header2.c_str());
+ f << stringf("\t$fdisplay(file, \"#OUT# %s\");\n", hdr.c_str());
+ f << stringf("\t$fdisplay(file, \"#OUT#\");\n");
+ f << stringf("\t$fdisplay(file, {\"#OUT# \"%s});\n", header2.c_str());
f << stringf("end\n");
f << stringf("endtask\n\n");
f << stringf("task %s;\n", idy(mod->name.str(), "test").c_str());
f << stringf("begin\n");
- f << stringf("\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str());
+ f << stringf("\t$fdisplay(file, \"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str());
f << stringf("\t%s;\n", idy(mod->name.str(), "reset").c_str());
f << stringf("\tfor (i=0; i<%d; i=i+1) begin\n", num_iter);
f << stringf("\t\tif (i %% 20 == 0) %s;\n", idy(mod->name.str(), "print_header").c_str());
@@ -293,9 +311,11 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("initial begin\n");
f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
f << stringf("\t// $dumpvars(0, testbench);\n");
+ f << stringf("\tfile = $fopen(`outfile);\n");
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
if (!it->second->get_bool_attribute("\\gentb_skip"))
f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
+ f << stringf("\t$fclose(file);\n");
f << stringf("\t$finish;\n");
f << stringf("end\n\n");
@@ -332,8 +352,9 @@ struct TestAutotbBackend : public Backend {
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
int num_iter = 1000;
+ int seed = 0;
- log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
+ log_header(design, "Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
int argidx;
for (argidx = 1; argidx < GetSize(args); argidx++)
@@ -342,11 +363,15 @@ struct TestAutotbBackend : public Backend {
num_iter = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-seed" && argidx+1 < GetSize(args)) {
+ seed = atoi(args[++argidx].c_str());
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
- autotest(*f, design, num_iter);
+ autotest(*f, design, num_iter, seed);
}
} TestAutotbBackend;
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index a8fcac9b..049c2053 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -21,6 +21,7 @@
#include "kernel/yosys.h"
#include "kernel/satgen.h"
#include "kernel/consteval.h"
+#include "kernel/celledges.h"
#include "kernel/macc.h"
#include <algorithm>
@@ -42,6 +43,32 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
RTLIL::Wire *wire;
+ if (cell_type == "$mux" || cell_type == "$pmux")
+ {
+ int width = 1 + xorshift32(8);
+ int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\B");
+ wire->width = width * swidth;
+ wire->port_input = true;
+ cell->setPort("\\B", wire);
+
+ wire = module->addWire("\\S");
+ wire->width = swidth;
+ wire->port_input = true;
+ cell->setPort("\\S", wire);
+
+ wire = module->addWire("\\Y");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+ }
+
if (cell_type == "$fa")
{
int width = 1 + xorshift32(8);
@@ -164,6 +191,41 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setParam("\\LUT", config.as_const());
}
+ if (cell_type == "$sop")
+ {
+ int width = 1 + xorshift32(8);
+ int depth = 1 + xorshift32(8);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\Y");
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+
+ RTLIL::SigSpec config;
+ for (int i = 0; i < width*depth; i++)
+ switch (xorshift32(3)) {
+ case 0:
+ config.append(RTLIL::S1);
+ config.append(RTLIL::S0);
+ break;
+ case 1:
+ config.append(RTLIL::S0);
+ config.append(RTLIL::S1);
+ break;
+ case 2:
+ config.append(RTLIL::S0);
+ config.append(RTLIL::S0);
+ break;
+ }
+
+ cell->setParam("\\DEPTH", depth);
+ cell->setParam("\\TABLE", config.as_const());
+ }
+
if (cell_type_flags.find('A') != std::string::npos) {
wire = module->addWire("\\A");
wire->width = 1 + xorshift32(8);
@@ -270,6 +332,91 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->check();
}
+static void run_edges_test(RTLIL::Design *design, bool verbose)
+{
+ Module *module = *design->modules().begin();
+ Cell *cell = *module->cells().begin();
+
+ ezSatPtr ezptr;
+ ezSAT &ez = *ezptr.get();
+
+ SigMap sigmap(module);
+ SatGen satgen(&ez, &sigmap);
+
+ FwdCellEdgesDatabase edges_db(sigmap);
+ if (!edges_db.add_edges_from_cell(cell))
+ log_error("Creating edge database failed for this cell!\n");
+
+ dict<SigBit, pool<SigBit>> satgen_db;
+
+ satgen.setContext(&sigmap, "X:");
+ satgen.importCell(cell);
+
+ satgen.setContext(&sigmap, "Y:");
+ satgen.importCell(cell);
+
+ vector<tuple<SigBit, int, int>> input_db, output_db;
+
+ for (auto &conn : cell->connections())
+ {
+ SigSpec bits = sigmap(conn.second);
+
+ satgen.setContext(&sigmap, "X:");
+ std::vector<int> xbits = satgen.importSigSpec(bits);
+
+ satgen.setContext(&sigmap, "Y:");
+ std::vector<int> ybits = satgen.importSigSpec(bits);
+
+ for (int i = 0; i < GetSize(bits); i++)
+ if (cell->input(conn.first))
+ input_db.emplace_back(bits[i], xbits[i], ybits[i]);
+ else
+ output_db.emplace_back(bits[i], xbits[i], ybits[i]);
+ }
+
+ if (verbose)
+ log("\nSAT solving for all edges:\n");
+
+ for (int i = 0; i < GetSize(input_db); i++)
+ {
+ SigBit inbit = std::get<0>(input_db[i]);
+
+ if (verbose)
+ log(" Testing input signal %s:\n", log_signal(inbit));
+
+ vector<int> xinbits, yinbits;
+ for (int k = 0; k < GetSize(input_db); k++)
+ if (k != i) {
+ xinbits.push_back(std::get<1>(input_db[k]));
+ yinbits.push_back(std::get<2>(input_db[k]));
+ }
+
+ int xyinbit_ok = ez.vec_eq(xinbits, yinbits);
+
+ for (int k = 0; k < GetSize(output_db); k++)
+ {
+ SigBit outbit = std::get<0>(output_db[k]);
+ int xoutbit = std::get<1>(output_db[k]);
+ int youtbit = std::get<2>(output_db[k]);
+
+ bool is_edge = ez.solve(xyinbit_ok, ez.XOR(xoutbit, youtbit));
+
+ if (is_edge)
+ satgen_db[inbit].insert(outbit);
+
+ if (verbose) {
+ bool is_ref_edge = edges_db.db.count(inbit) && edges_db.db.at(inbit).count(outbit);
+ log(" %c %s %s\n", is_edge ? 'x' : 'o', log_signal(outbit), is_edge == is_ref_edge ? "OK" : "ERROR");
+ }
+ }
+ }
+
+ if (satgen_db == edges_db.db)
+ log("PASS.\n");
+ else
+ log_error("SAT-based edge table does not match the database!\n");
+}
+
static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
{
log("Eval testing:%c", verbose ? '\n' : ' ');
@@ -534,7 +681,7 @@ struct TestCellPass : public Pass {
log(" pass this option to techmap.\n");
log("\n");
log(" -simlib\n");
- log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
+ log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n");
log("\n");
log(" -aigmap\n");
log(" instead of calling \"techmap\", call \"aigmap\"\n");
@@ -555,6 +702,9 @@ struct TestCellPass : public Pass {
log(" -noeval\n");
log(" do not check const-eval models\n");
log("\n");
+ log(" -edges\n");
+ log(" test cell edges db creator against sat-based implementation\n");
+ log("\n");
log(" -v\n");
log(" print additional debug information to the console\n");
log("\n");
@@ -574,6 +724,7 @@ struct TestCellPass : public Pass {
bool constmode = false;
bool nosat = false;
bool noeval = false;
+ bool edges = false;
int argidx;
for (argidx = 1; argidx < GetSize(args); argidx++)
@@ -604,7 +755,7 @@ struct TestCellPass : public Pass {
continue;
}
if (args[argidx] == "-simlib") {
- techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
+ techmap_cmd = "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc";
continue;
}
if (args[argidx] == "-aigmap") {
@@ -627,6 +778,10 @@ struct TestCellPass : public Pass {
noeval = true;
continue;
}
+ if (args[argidx] == "-edges") {
+ edges = true;
+ continue;
+ }
if (args[argidx] == "-v") {
verbose = true;
continue;
@@ -690,13 +845,18 @@ struct TestCellPass : public Pass {
cell_types["$logic_and"] = "ABSY";
cell_types["$logic_or"] = "ABSY";
- // cell_types["$mux"] = "A";
- // cell_types["$pmux"] = "A";
+ if (edges) {
+ cell_types["$mux"] = "*";
+ cell_types["$pmux"] = "*";
+ }
+
// cell_types["$slice"] = "A";
// cell_types["$concat"] = "A";
// cell_types["$assert"] = "A";
+ // cell_types["$assume"] = "A";
cell_types["$lut"] = "*";
+ cell_types["$sop"] = "*";
cell_types["$alu"] = "ABSY";
cell_types["$lcu"] = "*";
cell_types["$macc"] = "*";
@@ -763,6 +923,9 @@ struct TestCellPass : public Pass {
create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
if (!write_prefix.empty()) {
Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
+ } else if (edges) {
+ Pass::call(design, "dump gold");
+ run_edges_test(design, verbose);
} else {
Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
if (!nosat)