aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/rename.cc50
-rw-r--r--passes/equiv/Makefile.inc2
-rw-r--r--passes/equiv/equiv_make.cc27
-rw-r--r--passes/equiv/equiv_opt.cc157
-rw-r--r--passes/memory/memory_bram.cc17
-rw-r--r--passes/opt/Makefile.inc1
-rw-r--r--passes/opt/opt_expr.cc2
-rw-r--r--passes/opt/opt_lut.cc503
-rw-r--r--passes/opt/opt_muxtree.cc18
-rw-r--r--passes/techmap/abc.cc80
-rw-r--r--passes/techmap/deminout.cc7
-rw-r--r--passes/techmap/dff2dffe.cc35
-rw-r--r--passes/techmap/lut2mux.cc2
13 files changed, 855 insertions, 46 deletions
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index dce576fdf..4b4af0a40 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -52,6 +52,15 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
+static std::string derive_name_from_src(const std::string &src, int counter)
+{
+ std::string src_base = src.substr(0, src.find('|'));
+ if (src_base.empty())
+ return stringf("$%d", counter);
+ else
+ return stringf("\\%s$%d", src_base.c_str(), counter);
+}
+
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
void help() YS_OVERRIDE
@@ -63,6 +72,10 @@ struct RenamePass : public Pass {
log("Rename the specified object. Note that selection patterns are not supported\n");
log("by this command.\n");
log("\n");
+ log(" rename -src [selection]\n");
+ log("\n");
+ log("Assign names auto-generated from the src attribute to all selected wires and\n");
+ log("cells with private names.\n");
log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
@@ -84,6 +97,7 @@ struct RenamePass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string pattern_prefix = "_", pattern_suffix = "_";
+ bool flag_src = false;
bool flag_enumerate = false;
bool flag_hide = false;
bool flag_top = false;
@@ -93,6 +107,11 @@ struct RenamePass : public Pass {
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
+ if (arg == "-src" && !got_mode) {
+ flag_src = true;
+ got_mode = true;
+ continue;
+ }
if (arg == "-enumerate" && !got_mode) {
flag_enumerate = true;
got_mode = true;
@@ -117,6 +136,37 @@ struct RenamePass : public Pass {
break;
}
+ if (flag_src)
+ {
+ extra_args(args, argidx, design);
+
+ for (auto &mod : design->modules_)
+ {
+ int counter = 0;
+
+ RTLIL::Module *module = mod.second;
+ if (!design->selected(module))
+ continue;
+
+ dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ for (auto &it : module->wires_) {
+ if (it.first[0] == '$' && design->selected(module, it.second))
+ it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
+ new_wires[it.second->name] = it.second;
+ }
+ module->wires_.swap(new_wires);
+ module->fixup_ports();
+
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ for (auto &it : module->cells_) {
+ if (it.first[0] == '$' && design->selected(module, it.second))
+ it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
+ new_cells[it.second->name] = it.second;
+ }
+ module->cells_.swap(new_cells);
+ }
+ }
+ else
if (flag_enumerate)
{
extra_args(args, argidx, design);
diff --git a/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc
index dd7b3be02..27ea54b22 100644
--- a/passes/equiv/Makefile.inc
+++ b/passes/equiv/Makefile.inc
@@ -9,4 +9,4 @@ OBJS += passes/equiv/equiv_induct.o
OBJS += passes/equiv/equiv_struct.o
OBJS += passes/equiv/equiv_purge.o
OBJS += passes/equiv/equiv_mark.o
-
+OBJS += passes/equiv/equiv_opt.o
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 66ee28aff..dbd8682e6 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -290,22 +290,29 @@ struct EquivMakeWorker
init_bit2driven();
- pool<Cell*> visited_cells;
+ pool<Cell*> visited_cells;
for (auto c : cells_list)
for (auto &conn : c->connections())
if (!ct.cell_output(c->type, conn.first)) {
SigSpec old_sig = assign_map(conn.second);
SigSpec new_sig = rd_signal_map(old_sig);
-
- visited_cells.clear();
- if (old_sig != new_sig) {
- if (check_signal_in_fanout(visited_cells, old_sig, new_sig))
- continue;
- log("Changing input %s of cell %s (%s): %s -> %s\n",
- log_id(conn.first), log_id(c), log_id(c->type),
- log_signal(old_sig), log_signal(new_sig));
- c->setPort(conn.first, new_sig);
+ if(old_sig != new_sig) {
+ SigSpec tmp_sig = old_sig;
+ for (int i = 0; i < GetSize(old_sig); i++) {
+ SigBit old_bit = old_sig[i], new_bit = new_sig[i];
+
+ visited_cells.clear();
+ if (check_signal_in_fanout(visited_cells, old_bit, new_bit))
+ continue;
+
+ log("Changing input %s of cell %s (%s): %s -> %s\n",
+ log_id(conn.first), log_id(c), log_id(c->type),
+ log_signal(old_bit), log_signal(new_bit));
+
+ tmp_sig[i] = new_bit;
+ }
+ c->setPort(conn.first, tmp_sig);
}
}
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
new file mode 100644
index 000000000..86550a69b
--- /dev/null
+++ b/passes/equiv/equiv_opt.cc
@@ -0,0 +1,157 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 whitequark <whitequark@whitequark.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivOptPass:public ScriptPass
+{
+ EquivOptPass() : ScriptPass("equiv_opt", "prove equivalence for optimized circuit") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_opt [options] [command]\n");
+ log("\n");
+ log("This command checks circuit equivalence before and after an optimization pass.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to the start of the command list, and empty to\n");
+ log(" label is synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -map <filename>\n");
+ log(" expand the modules in this file before proving equivalence. this is\n");
+ log(" useful for handling architecture-specific primitives.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" produce an error if the circuits are not equivalent\n");
+ log("\n");
+ log("The following commands are executed by this verification command:\n");
+ help_script();
+ log("\n");
+ }
+
+ std::string command, techmap_opts;
+ bool assert;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ command = "";
+ techmap_opts = "";
+ assert = false;
+ }
+
+ void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-run" && argidx + 1 < args.size()) {
+ size_t pos = args[argidx + 1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos + 1);
+ continue;
+ }
+ if (args[argidx] == "-map" && argidx + 1 < args.size()) {
+ techmap_opts += " -map " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ assert = true;
+ continue;
+ }
+ break;
+ }
+
+ for (; argidx < args.size(); argidx++) {
+ if (command.empty()) {
+ if (args[argidx].substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unknown option.");
+ } else {
+ command += " ";
+ }
+ command += args[argidx];
+ }
+
+ if (command.empty())
+ log_cmd_error("No optimization pass specified!\n");
+
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+
+ log_header(design, "Executing EQUIV_OPT pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("run_pass")) {
+ run("hierarchy -auto-top");
+ run("design -save preopt");
+ if (help_mode)
+ run("[command]");
+ else
+ run(command);
+ run("design -stash postopt");
+ }
+
+ if (check_label("prepare")) {
+ run("design -copy-from preopt -as gold A:top");
+ run("design -copy-from postopt -as gate A:top");
+ }
+
+ if ((!techmap_opts.empty() || help_mode) && check_label("techmap", "(only with -map)")) {
+ string opts;
+ if (help_mode)
+ opts = " -map <filename> ...";
+ else
+ opts = techmap_opts;
+ run("techmap -D EQUIV -autoproc" + opts);
+ }
+
+ if (check_label("prove")) {
+ run("equiv_make gold gate equiv");
+ run("equiv_induct equiv");
+ if (help_mode)
+ run("equiv_status [-assert] equiv");
+ else if (assert)
+ run("equiv_status -assert equiv");
+ else
+ run("equiv_status equiv");
+ }
+
+ if (check_label("restore")) {
+ run("design -load preopt");
+ }
+ }
+} EquivOptPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index 8740042c4..cf4095d06 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -472,8 +472,12 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
std::vector<SigSpec> new_wr_en(GetSize(old_wr_en));
std::vector<SigSpec> new_wr_data(GetSize(old_wr_data));
std::vector<SigSpec> new_rd_data(GetSize(old_rd_data));
+ std::vector<std::vector<State>> new_initdata;
std::vector<int> shuffle_map;
+ if (cell_init)
+ new_initdata.resize(mem_size);
+
for (auto &it : en_order)
{
auto &bits = bits_wr_en.at(it);
@@ -489,6 +493,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
for (int j = 0; j < rd_ports; j++)
new_rd_data[j].append(old_rd_data[j][bits[i]]);
+ if (cell_init) {
+ for (int j = 0; j < mem_size; j++)
+ new_initdata[j].push_back(initdata[j][bits[i]]);
+ }
shuffle_map.push_back(bits[i]);
}
@@ -499,6 +507,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
for (int j = 0; j < rd_ports; j++)
new_rd_data[j].append(State::Sx);
+ if (cell_init) {
+ for (int j = 0; j < mem_size; j++)
+ new_initdata[j].push_back(State::Sx);
+ }
shuffle_map.push_back(-1);
}
}
@@ -522,6 +534,11 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
for (int i = 0; i < rd_ports; i++)
rd_data.replace(i*mem_width, new_rd_data[i]);
+
+ if (cell_init) {
+ for (int i = 0; i < mem_size; i++)
+ initdata[i] = Const(new_initdata[i]);
+ }
}
// assign write ports
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 0d01e9d35..0f596b1f4 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -6,6 +6,7 @@ OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_expr.o
+OBJS += passes/opt/opt_lut.o
ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 0ba233c62..610edc5e9 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -1406,7 +1406,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
{
if (sigConst.is_fully_zero()) {
- RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, GetSize(cell->getPort("\\Y")));
if (is_lt) {
log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
log_id(cell->type), log_id(cell));
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
new file mode 100644
index 000000000..be050c713
--- /dev/null
+++ b/passes/opt/opt_lut.cc
@@ -0,0 +1,503 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 whitequark <whitequark@whitequark.org>
+ *
+ * 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"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct OptLutWorker
+{
+ dict<IdString, dict<int, IdString>> &dlogic;
+ RTLIL::Module *module;
+ ModIndex index;
+ SigMap sigmap;
+
+ pool<RTLIL::Cell*> luts;
+ dict<RTLIL::Cell*, int> luts_arity;
+ dict<RTLIL::Cell*, pool<RTLIL::Cell*>> luts_dlogics;
+ dict<RTLIL::Cell*, pool<int>> luts_dlogic_inputs;
+
+ int combined_count = 0;
+
+ bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
+ {
+ SigSpec lut_input = sigmap(lut->getPort("\\A"));
+ int lut_width = lut->getParam("\\WIDTH").as_int();
+ Const lut_table = lut->getParam("\\LUT");
+ int lut_index = 0;
+
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit input = sigmap(lut_input[i]);
+ if (inputs.count(input))
+ {
+ lut_index |= inputs[input] << i;
+ }
+ else
+ {
+ lut_index |= SigSpec(lut_input[i]).as_bool() << i;
+ }
+ }
+
+ return lut_table.extract(lut_index).as_bool();
+ }
+
+ void show_stats_by_arity()
+ {
+ dict<int, int> arity_counts;
+ dict<IdString, int> dlogic_counts;
+ int max_arity = 0;
+
+ for (auto lut_arity : luts_arity)
+ {
+ max_arity = max(max_arity, lut_arity.second);
+ arity_counts[lut_arity.second]++;
+ }
+
+ for (auto &lut_dlogics : luts_dlogics)
+ {
+ for (auto &lut_dlogic : lut_dlogics.second)
+ {
+ dlogic_counts[lut_dlogic->type]++;
+ }
+ }
+
+ log("Number of LUTs: %8zu\n", luts.size());
+ for (int arity = 1; arity <= max_arity; arity++)
+ {
+ if (arity_counts[arity])
+ log(" %d-LUT %16d\n", arity, arity_counts[arity]);
+ }
+ for (auto &dlogic_count : dlogic_counts)
+ {
+ log(" with %-12s %4d\n", dlogic_count.first.c_str(), dlogic_count.second);
+ }
+ }
+
+ OptLutWorker(dict<IdString, dict<int, IdString>> &dlogic, RTLIL::Module *module, int limit) :
+ dlogic(dlogic), module(module), index(module), sigmap(module)
+ {
+ log("Discovering LUTs.\n");
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$lut")
+ {
+ int lut_width = cell->getParam("\\WIDTH").as_int();
+ SigSpec lut_input = cell->getPort("\\A");
+ int lut_arity = 0;
+
+ log("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
+ luts.insert(cell);
+
+ // First, find all dedicated logic we're connected to. This results in an overapproximation
+ // of such connections.
+ pool<RTLIL::Cell*> lut_all_dlogics;
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit bit = lut_input[i];
+ for (auto &port : index.query_ports(bit))
+ {
+ if (dlogic.count(port.cell->type))
+ {
+ auto &dlogic_map = dlogic[port.cell->type];
+ if (dlogic_map.count(i))
+ {
+ if (port.port == dlogic_map[i])
+ {
+ lut_all_dlogics.insert(port.cell);
+ }
+ }
+ }
+ }
+ }
+
+ // Second, make sure that the connection to dedicated logic is legal. If it is not legal,
+ // it means one of the two things:
+ // * The connection is spurious. I.e. this is dedicated logic that will be packed
+ // with some other LUT, and it just happens to be conected to this LUT as well.
+ // * The connection is illegal.
+ // In either of these cases, we don't need to concern ourselves with preserving the connection
+ // between this LUT and this dedicated logic cell.
+ pool<RTLIL::Cell*> lut_legal_dlogics;
+ pool<int> lut_dlogic_inputs;
+ for (auto lut_dlogic : lut_all_dlogics)
+ {
+ auto &dlogic_map = dlogic[lut_dlogic->type];
+ bool legal = true;
+ for (auto &dlogic_conn : dlogic_map)
+ {
+ if (lut_width <= dlogic_conn.first)
+ {
+ log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ log(" LUT input A[%d] not present.\n", dlogic_conn.first);
+ legal = false;
+ break;
+ }
+ if (sigmap(lut_input[dlogic_conn.first]) != sigmap(lut_dlogic->getPort(dlogic_conn.second)))
+ {
+ log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ log(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second)));
+ legal = false;
+ break;
+ }
+ }
+
+ if (legal)
+ {
+ log(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ lut_legal_dlogics.insert(lut_dlogic);
+ for (auto &dlogic_conn : dlogic_map)
+ lut_dlogic_inputs.insert(dlogic_conn.first);
+ }
+ }
+
+ // Third, determine LUT arity. An n-wide LUT that has k constant inputs and m inputs shared with dedicated
+ // logic implements an (n-k-m)-ary function.
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit bit = lut_input[i];
+ if (bit.wire || lut_dlogic_inputs.count(i))
+ lut_arity++;
+ }
+
+ log(" Cell implements a %d-LUT.\n", lut_arity);
+ luts_arity[cell] = lut_arity;
+ luts_dlogics[cell] = lut_legal_dlogics;
+ luts_dlogic_inputs[cell] = lut_dlogic_inputs;
+ }
+ }
+ show_stats_by_arity();
+
+ log("\n");
+ log("Combining LUTs.\n");
+ pool<RTLIL::Cell*> worklist = luts;
+ while (worklist.size())
+ {
+ if (limit == 0)
+ {
+ log("Limit reached.\n");
+ break;
+ }
+
+ auto lutA = worklist.pop();
+ SigSpec lutA_input = sigmap(lutA->getPort("\\A"));
+ SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]);
+ int lutA_width = lutA->getParam("\\WIDTH").as_int();
+ int lutA_arity = luts_arity[lutA];
+ pool<int> &lutA_dlogic_inputs = luts_dlogic_inputs[lutA];
+
+ auto lutA_output_ports = index.query_ports(lutA->getPort("\\Y"));
+ if (lutA_output_ports.size() != 2)
+ continue;
+
+ for (auto &port : lutA_output_ports)
+ {
+ if (port.cell == lutA)
+ continue;
+
+ if (luts.count(port.cell))
+ {
+ auto lutB = port.cell;
+ SigSpec lutB_input = sigmap(lutB->getPort("\\A"));
+ SigSpec lutB_output = sigmap(lutB->getPort("\\Y")[0]);
+ int lutB_width = lutB->getParam("\\WIDTH").as_int();
+ int lutB_arity = luts_arity[lutB];
+ pool<int> &lutB_dlogic_inputs = luts_dlogic_inputs[lutB];
+
+ log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
+
+ if (index.query_is_output(lutA->getPort("\\Y")))
+ {
+ log(" Not combining LUTs (cascade connection feeds module output).\n");
+ continue;
+ }
+
+ pool<SigBit> lutA_inputs;
+ pool<SigBit> lutB_inputs;
+ for (auto &bit : lutA_input)
+ {
+ if (bit.wire)
+ lutA_inputs.insert(sigmap(bit));
+ }
+ for (auto &bit : lutB_input)
+ {
+ if (bit.wire)
+ lutB_inputs.insert(sigmap(bit));
+ }
+
+ pool<SigBit> common_inputs;
+ for (auto &bit : lutA_inputs)
+ {
+ if (lutB_inputs.count(bit))
+ common_inputs.insert(bit);
+ }
+
+ int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
+ if (lutA_dlogic_inputs.size())
+ log(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size());
+ else
+ log(" Cell A is a %d-LUT. ", lutA_arity);
+ if (lutB_dlogic_inputs.size())
+ log("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size());
+ else
+ log("Cell B is a %d-LUT.\n", lutB_arity);
+ log(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity);
+
+ const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
+ int combine_mask = 0;
+ if (lutM_arity > lutA_width)
+ {
+ log(" Not combining LUTs into cell A (combined LUT wider than cell A).\n");
+ }
+ else if (lutB_dlogic_inputs.size() > 0)
+ {
+ log(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n");
+ }
+ else if (lutB->get_bool_attribute("\\lut_keep"))
+ {
+ log(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
+ }
+ else
+ {
+ combine_mask |= COMBINE_A;
+ }
+ if (lutM_arity > lutB_width)
+ {
+ log(" Not combining LUTs into cell B (combined LUT wider than cell B).\n");
+ }
+ else if (lutA_dlogic_inputs.size() > 0)
+ {
+ log(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n");
+ }
+ else if (lutA->get_bool_attribute("\\lut_keep"))
+ {
+ log(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
+ }
+ else
+ {
+ combine_mask |= COMBINE_B;
+ }
+
+ int combine = combine_mask;
+ if (combine == COMBINE_EITHER)
+ {
+ log(" Can combine into either cell.\n");
+ if (lutA_arity == 1)
+ {
+ log(" Cell A is a buffer or inverter, combining into cell B.\n");
+ combine = COMBINE_B;
+ }
+ else if (lutB_arity == 1)
+ {
+ log(" Cell B is a buffer or inverter, combining into cell A.\n");
+ combine = COMBINE_A;
+ }
+ else
+ {
+ log(" Arbitrarily combining into cell A.\n");
+ combine = COMBINE_A;
+ }
+ }
+
+ RTLIL::Cell *lutM, *lutR;
+ pool<SigBit> lutM_inputs, lutR_inputs;
+ pool<int> lutM_dlogic_inputs;
+ if (combine == COMBINE_A)
+ {
+ log(" Combining LUTs into cell A.\n");
+ lutM = lutA;
+ lutM_inputs = lutA_inputs;
+ lutM_dlogic_inputs = lutA_dlogic_inputs;
+ lutR = lutB;
+ lutR_inputs = lutB_inputs;
+ }
+ else if (combine == COMBINE_B)
+ {
+ log(" Combining LUTs into cell B.\n");
+ lutM = lutB;
+ lutM_inputs = lutB_inputs;
+ lutM_dlogic_inputs = lutB_dlogic_inputs;
+ lutR = lutA;
+ lutR_inputs = lutA_inputs;
+ }
+ else
+ {
+ log(" Cannot combine LUTs.\n");
+ continue;
+ }
+
+ pool<SigBit> lutR_unique;
+ for (auto &bit : lutR_inputs)
+ {
+ if (!common_inputs.count(bit) && bit != lutA_output)
+ lutR_unique.insert(bit);
+ }
+
+ int lutM_width = lutM->getParam("\\WIDTH").as_int();
+ SigSpec lutM_input = sigmap(lutM->getPort("\\A"));
+ std::vector<SigBit> lutM_new_inputs;
+ for (int i = 0; i < lutM_width; i++)
+ {
+ bool input_unused = false;
+ if (sigmap(lutM_input[i]) == lutA_output)
+ input_unused = true;
+ if (!lutM_input[i].wire && !lutM_dlogic_inputs.count(i))
+ input_unused = true;
+
+ if (input_unused && lutR_unique.size())
+ {
+ SigBit new_input = lutR_unique.pop();
+ log(" Connecting input %d as %s.\n", i, log_signal(new_input));
+ lutM_new_inputs.push_back(new_input);
+ }
+ else if (sigmap(lutM_input[i]) == lutA_output)
+ {
+ log(" Disconnecting cascade input %d.\n", i);
+ lutM_new_inputs.push_back(SigBit());
+ }
+ else
+ {
+ log(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
+ lutM_new_inputs.push_back(lutM_input[i]);
+ }
+ }
+ log_assert(lutR_unique.size() == 0);
+
+ RTLIL::Const lutM_new_table(State::Sx, 1 << lutM_width);
+ for (int eval = 0; eval < 1 << lutM_width; eval++)
+ {
+ dict<SigBit, bool> eval_inputs;
+ for (size_t i = 0; i < lutM_new_inputs.size(); i++)
+ {
+ eval_inputs[lutM_new_inputs[i]] = (eval >> i) & 1;
+ }
+ eval_inputs[lutA_output] = evaluate_lut(lutA, eval_inputs);
+ lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs);
+ }
+
+ log(" Cell A truth table: %s.\n", lutA->getParam("\\LUT").as_string().c_str());
+ log(" Cell B truth table: %s.\n", lutB->getParam("\\LUT").as_string().c_str());
+ log(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
+
+ lutM->setParam("\\LUT", lutM_new_table);
+ lutM->setPort("\\A", lutM_new_inputs);
+ lutM->setPort("\\Y", lutB_output);
+
+ luts_arity[lutM] = lutM_arity;
+ luts.erase(lutR);
+ luts_arity.erase(lutR);
+ lutR->module->remove(lutR);
+
+ worklist.insert(lutM);
+ worklist.erase(lutR);
+
+ combined_count++;
+ if (limit > 0)
+ limit--;
+ }
+ }
+ }
+ show_stats_by_arity();
+ }
+};
+
+static void split(std::vector<std::string> &tokens, const std::string &text, char sep)
+{
+ size_t start = 0, end = 0;
+ while ((end = text.find(sep, start)) != std::string::npos) {
+ tokens.push_back(text.substr(start, end - start));
+ start = end + 1;
+ }
+ tokens.push_back(text.substr(start));
+}
+
+struct OptLutPass : public Pass {
+ OptLutPass() : Pass("opt_lut", "optimize LUT cells") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_lut [options] [selection]\n");
+ log("\n");
+ log("This pass combines cascaded $lut cells with unused inputs.\n");
+ log("\n");
+ log(" -dlogic <type>:<cell-port>=<LUT-input>[:<cell-port>=<LUT-input>...]\n");
+ log(" preserve connections to dedicated logic cell <type> that has ports\n");
+ log(" <cell-port> connected to LUT inputs <LUT-input>. this includes\n");
+ log(" the case where both LUT and dedicated logic input are connected to\n");
+ log(" the same constant.\n");
+ log("\n");
+ log(" -limit N\n");
+ log(" only perform the first N combines, then stop. useful for debugging.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n");
+
+ dict<IdString, dict<int, IdString>> dlogic;
+ int limit = -1;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-dlogic" && argidx+1 < args.size())
+ {
+ std::vector<std::string> tokens;
+ split(tokens, args[++argidx], ':');
+ if (tokens.size() < 2)
+ log_cmd_error("The -dlogic option requires at least one connection.\n");
+ IdString type = "\\" + tokens[0];
+ for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) {
+ std::vector<std::string> conn_tokens;
+ split(conn_tokens, *it, '=');
+ if (conn_tokens.size() != 2)
+ log_cmd_error("Invalid format of -dlogic signal mapping.\n");
+ IdString logic_port = "\\" + conn_tokens[0];
+ int lut_input = atoi(conn_tokens[1].c_str());
+ dlogic[type][lut_input] = logic_port;
+ }
+ continue;
+ }
+ if (args[argidx] == "-limit" && argidx + 1 < args.size())
+ {
+ limit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ int total_count = 0;
+ for (auto module : design->selected_modules())
+ {
+ OptLutWorker worker(dlogic, module, limit - total_count);
+ total_count += worker.combined_count;
+ }
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
+ log("\n");
+ log("Combined %d LUTs.\n", total_count);
+ }
+} OptLutPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 87c7ce9b2..375697dc8 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -36,6 +36,7 @@ struct OptMuxtreeWorker
RTLIL::Module *module;
SigMap assign_map;
int removed_count;
+ int glob_abort_cnt = 100000;
struct bitinfo_t {
bool seen_non_mux;
@@ -293,6 +294,9 @@ struct OptMuxtreeWorker
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
+ if (glob_abort_cnt == 0)
+ return;
+
muxinfo_t &muxinfo = mux2info[mux_idx];
if (do_enable_ports)
@@ -315,7 +319,7 @@ struct OptMuxtreeWorker
knowledge.visited_muxes[m] = true;
parent_muxes.push_back(m);
}
- for (int m : parent_muxes)
+ for (int m : parent_muxes) {
if (root_enable_muxes.at(m))
continue;
else if (root_muxes.at(m)) {
@@ -327,6 +331,9 @@ struct OptMuxtreeWorker
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else
eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
+ if (glob_abort_cnt == 0)
+ return;
+ }
for (int m : parent_muxes)
knowledge.visited_muxes[m] = false;
@@ -390,6 +397,12 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
+ glob_abort_cnt--;
+
muxinfo_t &muxinfo = mux2info[mux_idx];
// set input ports to constants if we find known active or inactive signals
@@ -433,6 +446,9 @@ struct OptMuxtreeWorker
if (knowledge.known_inactive.at(portinfo.ctrl_sig))
continue;
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
+
+ if (glob_abort_cnt == 0)
+ return;
}
}
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index d2d15a4a9..d3bdd555b 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -329,6 +329,18 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name)
{
+ std::string abc_sname = abc_name.substr(1);
+ if (abc_sname.substr(0, 5) == "ys__n") {
+ int sid = std::stoi(abc_sname.substr(5));
+ bool inv = abc_sname.back() == 'v';
+ for (auto sig : signal_list) {
+ if (sig.id == sid) {
+ std::stringstream sstr;
+ sstr << "$abc$" << map_autoidx << "$" << log_signal(sig.bit) << (inv ? "_inv" : "");
+ return sstr.str();
+ }
+ }
+ }
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
return sstr.str();
@@ -353,12 +365,12 @@ void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std:
}
for (auto n : nodes)
- fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
+ fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
for (auto &e : edges)
for (auto n : e.second)
- fprintf(f, " n%d -> n%d;\n", e.first, n);
+ fprintf(f, " ys__n%d -> ys__n%d;\n", e.first, n);
fprintf(f, "}\n");
}
@@ -624,7 +636,7 @@ 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, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
- const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
+ const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress)
{
module = current_module;
map_autoidx = autoidx++;
@@ -728,7 +740,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
-
+ if (abc_dress)
+ abc_script += "; dress";
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -784,7 +797,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list) {
if (!si.is_port || si.type != G(NONE))
continue;
- fprintf(f, " n%d", si.id);
+ fprintf(f, " ys__n%d", si.id);
pi_map[count_input++] = log_signal(si.bit);
}
if (count_input == 0)
@@ -796,17 +809,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list) {
if (!si.is_port || si.type == G(NONE))
continue;
- fprintf(f, " n%d", si.id);
+ fprintf(f, " ys__n%d", si.id);
po_map[count_output++] = log_signal(si.bit);
}
fprintf(f, "\n");
for (auto &si : signal_list)
- fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit));
+ fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit));
for (auto &si : signal_list) {
if (si.bit.wire == NULL) {
- fprintf(f, ".names n%d\n", si.id);
+ fprintf(f, ".names ys__n%d\n", si.id);
if (si.bit == RTLIL::State::S1)
fprintf(f, "1\n");
}
@@ -815,68 +828,68 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
int count_gates = 0;
for (auto &si : signal_list) {
if (si.type == G(BUF)) {
- fprintf(f, ".names n%d n%d\n", si.in1, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
fprintf(f, "1 1\n");
} else if (si.type == G(NOT)) {
- fprintf(f, ".names n%d n%d\n", si.in1, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
fprintf(f, "0 1\n");
} else if (si.type == G(AND)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "11 1\n");
} else if (si.type == G(NAND)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "0- 1\n");
fprintf(f, "-0 1\n");
} else if (si.type == G(OR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "-1 1\n");
fprintf(f, "1- 1\n");
} else if (si.type == G(NOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
} else if (si.type == G(XOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "01 1\n");
fprintf(f, "10 1\n");
} else if (si.type == G(XNOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
fprintf(f, "11 1\n");
} else if (si.type == G(ANDNOT)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "10 1\n");
} else if (si.type == G(ORNOT)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "1- 1\n");
fprintf(f, "-0 1\n");
} else if (si.type == G(MUX)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
fprintf(f, "-11 1\n");
} else if (si.type == G(AOI3)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "-00 1\n");
fprintf(f, "0-0 1\n");
} else if (si.type == G(OAI3)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "00- 1\n");
fprintf(f, "--0 1\n");
} else if (si.type == G(AOI4)) {
- fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
fprintf(f, "-0-0 1\n");
fprintf(f, "-00- 1\n");
fprintf(f, "0--0 1\n");
fprintf(f, "0-0- 1\n");
} else if (si.type == G(OAI4)) {
- fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
if (si.init == State::S0 || si.init == State::S1) {
- fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
+ fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
recover_init = true;
} else
- fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id);
+ fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@@ -889,7 +902,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
count_gates, GetSize(signal_list), count_input, count_output);
log_push();
-
if (count_output > 0)
{
log_header(design, "Executing ABC.\n");
@@ -1213,7 +1225,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list)
if (si.is_port) {
char buffer[100];
- snprintf(buffer, 100, "\\n%d", si.id);
+ snprintf(buffer, 100, "\\ys__n%d", si.id);
RTLIL::SigSig conn;
if (si.type != G(NONE)) {
conn.first = si.bit;
@@ -1407,6 +1419,11 @@ struct AbcPass : public Pass {
log(" this attribute is a unique integer for each ABC process started. This\n");
log(" is useful for debugging the partitioning of clock domains.\n");
log("\n");
+ log(" -dress\n");
+ log(" run the 'dress' command after all other ABC commands. This aims to\n");
+ log(" preserve naming by an equivalence check between the original and post-ABC\n");
+ log(" netlists (experimental).\n");
+ log("\n");
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
@@ -1441,6 +1458,7 @@ struct AbcPass : public Pass {
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
+ bool abc_dress = false;
vector<int> lut_costs;
markgroups = false;
@@ -1555,6 +1573,10 @@ struct AbcPass : public Pass {
map_mux16 = true;
continue;
}
+ if (arg == "-dress") {
+ abc_dress = true;
+ continue;
+ }
if (arg == "-g" && argidx+1 < args.size()) {
for (auto g : split_tokens(args[++argidx], ",")) {
vector<string> gate_list;
@@ -1704,7 +1726,7 @@ struct AbcPass : public Pass {
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, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
+ delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress);
continue;
}
@@ -1849,7 +1871,7 @@ struct AbcPass : public Pass {
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, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
+ keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
assign_map.set(mod);
}
}
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index 9f0c7bf67..47d0ff416 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -83,9 +83,9 @@ struct DeminoutPass : public Pass {
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
- if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_"))
+ if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_", "$tribuf"))
{
- bool tribuf = (cell->type == "$_TBUF_");
+ bool tribuf = (cell->type == "$_TBUF_" || cell->type == "$tribuf");
if (!tribuf) {
for (auto &c : cell->connections()) {
@@ -113,7 +113,8 @@ struct DeminoutPass : public Pass {
{
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
-
+ if (bit == State::S0 || bit == State::S1)
+ new_output = true;
if (bits_written.count(bit)) {
new_output = true;
if (bits_tribuf.count(bit))
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 3291f5a4a..7e1040963 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -267,6 +267,10 @@ struct Dff2dffePass : public Pass {
log(" operate in the opposite direction: replace $dffe cells with combinations\n");
log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n");
log("\n");
+ log(" -unmap-mince N\n");
+ log(" Same as -unmap but only unmap $dffe where the clock enable port\n");
+ log(" signal is used by less $dffe than the specified number\n");
+ log("\n");
log(" -direct <internal_gate_type> <external_gate_type>\n");
log(" map directly to external gate type. <internal_gate_type> can\n");
log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n");
@@ -289,6 +293,7 @@ struct Dff2dffePass : public Pass {
log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
bool unmap_mode = false;
+ int min_ce_use = -1;
dict<IdString, IdString> direct_dict;
size_t argidx;
@@ -297,6 +302,11 @@ struct Dff2dffePass : public Pass {
unmap_mode = true;
continue;
}
+ if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
+ unmap_mode = true;
+ min_ce_use = std::stoi(args[++argidx]);
+ continue;
+ }
if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
string direct_from = RTLIL::escape_id(args[++argidx]);
string direct_to = RTLIL::escape_id(args[++argidx]);
@@ -343,8 +353,21 @@ struct Dff2dffePass : public Pass {
if (!mod->has_processes_warn())
{
if (unmap_mode) {
+ SigMap sigmap(mod);
for (auto cell : mod->selected_cells()) {
if (cell->type == "$dffe") {
+ if (min_ce_use >= 0) {
+ int ce_use = 0;
+ for (auto cell_other : mod->selected_cells()) {
+ if (cell_other->type != cell->type)
+ continue;
+ if (sigmap(cell->getPort("\\EN")) == sigmap(cell_other->getPort("\\EN")))
+ ce_use++;
+ }
+ if (ce_use >= min_ce_use)
+ continue;
+ }
+
RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D")));
mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool());
if (cell->getParam("\\EN_POLARITY").as_bool())
@@ -355,6 +378,18 @@ struct Dff2dffePass : public Pass {
continue;
}
if (cell->type.substr(0, 7) == "$_DFFE_") {
+ if (min_ce_use >= 0) {
+ int ce_use = 0;
+ for (auto cell_other : mod->selected_cells()) {
+ if (cell_other->type != cell->type)
+ continue;
+ if (sigmap(cell->getPort("\\E")) == sigmap(cell_other->getPort("\\E")))
+ ce_use++;
+ }
+ if (ce_use >= min_ce_use)
+ continue;
+ }
+
bool clk_pol = cell->type.substr(7, 1) == "P";
bool en_pol = cell->type.substr(8, 1) == "P";
RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index d32bbff14..a4ed79550 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -32,7 +32,7 @@ int lut2mux(Cell *cell)
if (GetSize(sig_a) == 1)
{
- cell->module->addMuxGate(NEW_ID, lut[0], lut[1], sig_a, sig_y);
+ cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
}
else
{