aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/bugpoint.cc3
-rw-r--r--passes/cmds/cover.cc10
-rw-r--r--passes/cmds/stat.cc76
-rw-r--r--passes/cmds/tee.cc5
-rw-r--r--passes/hierarchy/hierarchy.cc191
-rw-r--r--passes/opt/opt_clean.cc25
-rw-r--r--passes/opt/opt_muxtree.cc14
-rw-r--r--passes/opt/opt_rmdff.cc72
-rw-r--r--passes/opt/wreduce.cc10
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg15
-rw-r--r--passes/sat/fmcombine.cc45
-rw-r--r--passes/techmap/libparse.cc2
-rw-r--r--passes/techmap/zinit.cc2
13 files changed, 395 insertions, 75 deletions
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 85e2b0d56..038ab7c7c 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
}
extra_args(args, argidx, design);
+ if (script.empty())
+ log_cmd_error("Missing -script option.\n");
+
if (!has_part)
{
modules = true;
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 0ec747671..1128116b4 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -98,21 +98,23 @@ struct CoverPass : public Pass {
}
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
- std::string filename = args[++argidx];
+ const std::string &filename = args[++argidx];
+ FILE *f = nullptr;
if (args[argidx-1] == "-d") {
#ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
- filename = mkstemps(filename_buffer, 4);
+ f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif
+ } else {
+ f = fopen(filename.c_str(), open_mode);
}
- FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
for (auto f : out_files)
fclose(f);
- log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
}
out_files.push_back(f);
continue;
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 54f4ea817..d22685b62 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -37,7 +37,9 @@ struct statdata_t
STAT_INT_MEMBERS
#undef X
double area;
+ string tech;
+ std::map<RTLIL::IdString, int> techinfo;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area;
@@ -70,8 +72,10 @@ struct statdata_t
#undef X
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area)
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{
+ tech = techname;
+
#define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS
#undef X
@@ -153,7 +157,8 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
- log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+ if (it.second)
+ log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@@ -165,6 +170,59 @@ struct statdata_t
log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
+
+ if (tech == "xilinx")
+ {
+ int lut6_cnt = num_cells_by_type["\\LUT6"];
+ int lut5_cnt = num_cells_by_type["\\LUT5"];
+ int lut4_cnt = num_cells_by_type["\\LUT4"];
+ int lut3_cnt = num_cells_by_type["\\LUT3"];
+ int lut2_cnt = num_cells_by_type["\\LUT2"];
+ int lut1_cnt = num_cells_by_type["\\LUT1"];
+ int lc_cnt = 0;
+
+ lc_cnt += lut6_cnt;
+
+ lc_cnt += lut5_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut5_cnt, lut1_cnt);
+ lut5_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+
+ lc_cnt += lut4_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut4_cnt, lut1_cnt);
+ lut4_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+ if (lut2_cnt) {
+ int cnt = std::min(lut4_cnt, lut2_cnt);
+ lut4_cnt -= cnt;
+ lut2_cnt -= cnt;
+ }
+
+ lc_cnt += lut3_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut3_cnt, lut1_cnt);
+ lut3_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+ if (lut2_cnt) {
+ int cnt = std::min(lut3_cnt, lut2_cnt);
+ lut3_cnt -= cnt;
+ lut2_cnt -= cnt;
+ }
+ if (lut3_cnt) {
+ int cnt = (lut3_cnt + 1) / 2;
+ lut3_cnt -= cnt;
+ }
+
+ lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
+
+ log("\n");
+ log(" Estimated number of LCs: %10d\n", lc_cnt);
+ }
}
};
@@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n");
log("\n");
+ log(" -tech <technology>\n");
+ log(" print area estemate for the specified technology. Corrently supported\n");
+ log(" calues for <technology>: xilinx\n");
+ log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
+ string techname;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file);
continue;
}
+ if (args[argidx] == "-tech" && argidx+1 < args.size()) {
+ techname = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@@ -263,13 +330,16 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
+ if (techname != "" && techname != "xilinx")
+ log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
+
for (auto mod : design->selected_modules())
{
if (!top_mod && design->full_selection())
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
- statdata_t data(design, mod, width_mode, cell_area);
+ statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
log("\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index ee96ace86..1a44bdaec 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -52,7 +52,9 @@ struct TeePass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<FILE*> backup_log_files, files_to_close;
+ std::vector<std::ostream*> backup_log_streams;
int backup_log_verbose_level = log_verbose_level;
+ backup_log_streams = log_streams;
backup_log_files = log_files;
size_t argidx;
@@ -60,6 +62,7 @@ struct TeePass : public Pass {
{
if (args[argidx] == "-q" && files_to_close.empty()) {
log_files.clear();
+ log_streams.clear();
continue;
}
if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
@@ -89,6 +92,7 @@ struct TeePass : public Pass {
for (auto cf : files_to_close)
fclose(cf);
log_files = backup_log_files;
+ log_streams = backup_log_streams;
throw;
}
@@ -97,6 +101,7 @@ struct TeePass : public Pass {
log_verbose_level = backup_log_verbose_level;
log_files = backup_log_files;
+ log_streams = backup_log_streams;
}
} TeePass;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 72bc2e133..24e64a9b2 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -562,7 +562,8 @@ struct HierarchyPass : public Pass {
log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n");
- log("needed.\n");
+ log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
+ log("resolves positional module parameters, unroll array instances, and more.\n");
log("\n");
log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n");
@@ -943,62 +944,178 @@ struct HierarchyPass : public Pass {
std::vector<Module*> design_modules = design->modules();
for (auto module : design_modules)
- for (auto cell : module->cells())
{
- Module *m = design->module(cell->type);
+ pool<Wire*> wand_wor_index;
+ dict<Wire*, SigSpec> wand_map, wor_map;
+ vector<SigSig> new_connections;
- if (m == nullptr)
- continue;
+ for (auto wire : module->wires())
+ {
+ if (wire->get_bool_attribute("\\wand")) {
+ wand_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ if (wire->get_bool_attribute("\\wor")) {
+ wor_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ }
+
+ for (auto &conn : module->connections())
+ {
+ SigSig new_conn;
+ int cursor = 0;
+
+ for (auto c : conn.first.chunks())
+ {
+ Wire *w = c.wire;
+ SigSpec rhs = conn.second.extract(cursor, GetSize(c));
+
+ if (wand_wor_index.count(w) == 0) {
+ new_conn.first.append(c);
+ new_conn.second.append(rhs);
+ } else {
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wor_map.at(w).append(sig);
+ }
+ }
+ cursor += GetSize(c);
+ }
+ new_connections.push_back(new_conn);
+ }
+ module->new_connections(new_connections);
- if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
- IdString new_m_name = m->derive(design, cell->parameters, true);
- if (new_m_name.empty())
+ for (auto cell : module->cells())
+ {
+ if (!cell->known())
continue;
- if (new_m_name != m->name) {
- m = design->module(new_m_name);
- blackbox_derivatives.insert(m);
+
+ for (auto &conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ SigSpec new_sig;
+ bool update_port = false;
+
+ for (auto c : conn.second.chunks())
+ {
+ Wire *w = c.wire;
+
+ if (wand_wor_index.count(w) == 0) {
+ new_sig.append(c);
+ continue;
+ }
+
+ Wire *t = module->addWire(NEW_ID, GetSize(c));
+ new_sig.append(t);
+ update_port = true;
+
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, t);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, t);
+ wor_map.at(w).append(sig);
+ }
+ }
+
+ if (update_port)
+ cell->setPort(conn.first, new_sig);
}
}
- for (auto &conn : cell->connections())
+ for (auto w : wand_wor_index)
{
- Wire *w = m->wire(conn.first);
+ bool wand = wand_map.count(w);
+ SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
- if (w == nullptr || w->port_id == 0)
+ if (GetSize(sigs) == 0)
continue;
- if (GetSize(conn.second) == 0)
+ if (GetSize(w) == 1) {
+ if (wand)
+ module->addReduceAnd(NEW_ID, sigs, w);
+ else
+ module->addReduceOr(NEW_ID, sigs, w);
continue;
+ }
- SigSpec sig = conn.second;
+ SigSpec s = sigs.extract(0, GetSize(w));
+ for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) {
+ if (wand)
+ s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w)));
+ else
+ s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w)));
+ }
+ module->connect(w, s);
+ }
- if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
- {
- if (GetSize(w) < GetSize(conn.second))
- {
- int n = GetSize(conn.second) - GetSize(w);
- if (!w->port_input && w->port_output)
- module->connect(sig.extract(GetSize(w), n), Const(0, n));
- sig.remove(GetSize(w), n);
+ for (auto cell : module->cells())
+ {
+ Module *m = design->module(cell->type);
+
+ if (m == nullptr)
+ continue;
+
+ if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
+ IdString new_m_name = m->derive(design, cell->parameters, true);
+ if (new_m_name.empty())
+ continue;
+ if (new_m_name != m->name) {
+ m = design->module(new_m_name);
+ blackbox_derivatives.insert(m);
}
- else
+ }
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+
+ if (w == nullptr || w->port_id == 0)
+ continue;
+
+ if (GetSize(conn.second) == 0)
+ continue;
+
+ SigSpec sig = conn.second;
+
+ if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
{
- int n = GetSize(w) - GetSize(conn.second);
- if (w->port_input && !w->port_output)
- sig.append(Const(0, n));
+ if (GetSize(w) < GetSize(conn.second))
+ {
+ int n = GetSize(conn.second) - GetSize(w);
+ if (!w->port_input && w->port_output)
+ module->connect(sig.extract(GetSize(w), n), Const(0, n));
+ sig.remove(GetSize(w), n);
+ }
else
- sig.append(module->addWire(NEW_ID, n));
+ {
+ int n = GetSize(w) - GetSize(conn.second);
+ if (w->port_input && !w->port_output)
+ sig.append(Const(0, n));
+ else
+ sig.append(module->addWire(NEW_ID, n));
+ }
+
+ if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
+ log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
+ log_id(conn.first), GetSize(conn.second), GetSize(sig));
+ cell->setPort(conn.first, sig);
}
- if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
- log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
- log_id(conn.first), GetSize(conn.second), GetSize(sig));
- cell->setPort(conn.first, sig);
+ if (w->port_output && !w->port_input && sig.has_const())
+ log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
+ log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
}
-
- if (w->port_output && !w->port_input && sig.has_const())
- log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
- log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
}
}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6ca6ac820..7011d4602 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -232,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true;
}
-void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
+bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@@ -272,20 +272,17 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
- SigPool raw_used_signals_noaliases;
- for (auto &it : module->connections_)
- raw_used_signals_noaliases.add(it.second);
-
module->connections_.clear();
SigPool used_signals;
+ SigPool raw_used_signals;
SigPool used_signals_nodrivers;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
+ raw_used_signals.add(it2.second);
used_signals.add(it2.second);
- raw_used_signals_noaliases.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
}
@@ -294,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
+ raw_used_signals.add(sig);
assign_map.apply(sig);
used_signals.add(sig);
if (!wire->port_input)
@@ -321,8 +319,9 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
wire->attributes.erase("\\init");
if (GetSize(wire) == 0) {
- // delete zero-width wires
- goto delete_this_wire;
+ // delete zero-width wires, unless they are module ports
+ if (wire->port_id == 0)
+ goto delete_this_wire;
} else
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
@@ -330,11 +329,11 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!purge_mode && check_public_name(wire->name)) {
// do not get rid of public names unless in purge mode
} else
- if (!raw_used_signals_noaliases.check_any(s1)) {
+ if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
- if (!used_signals_nodrivers.check_any(s2)) {
+ if (!used_signals.check_any(s2)) {
// delete wires that aren't used by anything indirectly, even though other wires may alias it
goto delete_this_wire;
}
@@ -400,6 +399,8 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
+
+ return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@@ -497,10 +498,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose);
- rmunused_module_signals(module, purge_mode, verbose);
+ while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose))
- rmunused_module_signals(module, purge_mode, verbose);
+ while (rmunused_module_signals(module, purge_mode, verbose)) { }
}
struct OptCleanPass : public Pass {
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index dbebf21e0..6511e091b 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -184,6 +184,10 @@ struct OptMuxtreeWorker
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
}
while (!root_mux_rerun.empty()) {
@@ -192,9 +196,14 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
}
log(" Analyzing evaluation results.\n");
+ log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info)
{
@@ -397,10 +406,8 @@ 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");
+ if (glob_abort_cnt == 0)
return;
- }
glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx];
@@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
+ log_assert(glob_abort_cnt > 0);
knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info));
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index e8570f0eb..2abffa2a9 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -260,8 +260,8 @@ delete_dlatch:
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
{
- RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
- RTLIL::Const val_cp, val_rp, val_rv;
+ RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
+ RTLIL::Const val_cp, val_rp, val_rv, val_ep;
if (dff->type == "$_FF_") {
sig_d = dff->getPort("\\D");
@@ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
+ else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
+ (dff->type[7] == 'N' || dff->type[7] == 'P') &&
+ (dff->type[8] == 'N' || dff->type[8] == 'P')) {
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
+ sig_e = dff->getPort("\\E");
+ val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
+ val_ep = RTLIL::Const(dff->type[7] == 'P', 1);
+ }
else if (dff->type == "$ff") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
@@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
}
+ else if (dff->type == "$dffe") {
+ sig_e = dff->getPort("\\EN");
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
+ val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
+ val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
+ }
else if (dff->type == "$adff") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
@@ -337,39 +355,60 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
}
}
+ // If clock is driven by a constant and (i) no reset signal
+ // (ii) Q has no initial value
+ // (iii) initial value is same as reset value
if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
if (val_rv.bits.size() == 0)
val_rv = val_init;
+ // Q is permanently reset value or initial value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
+ // If D is fully undefined and reset signal present and (i) Q has no initial value
+ // (ii) initial value is same as reset value
if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
+ // Q is permanently reset value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
+ // If D is fully undefined and no reset signal and Q has an initial value
if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
+ // Q is permanently initial value
mod->connect(sig_q, val_init);
goto delete_dff;
}
+ // If D is fully constant and (i) no reset signal
+ // (ii) reset value is same as constant D
+ // and (a) has no initial value
+ // (b) initial value same as constant D
if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
+ // Q is permanently D
mod->connect(sig_q, sig_d);
goto delete_dff;
}
+ // If D input is same as Q output and (i) no reset signal
+ // (ii) no initial signal
+ // (iii) initial value is same as reset value
if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
+ // Q is permanently reset value or initial value
if (sig_r.size())
mod->connect(sig_q, val_rv);
- if (has_init)
+ else if (has_init)
mod->connect(sig_q, val_init);
goto delete_dff;
}
+ // If reset signal is present, and is fully constant
if (!sig_r.empty() && sig_r.is_fully_const())
{
+ // If reset value is permanently active or if reset is undefined
if (sig_r == val_rp || sig_r.is_fully_undef()) {
+ // Q is permanently reset value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
@@ -389,6 +428,30 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
dff->unsetPort("\\R");
}
+ // If enable signal is present, and is fully constant
+ if (!sig_e.empty() && sig_e.is_fully_const())
+ {
+ // If enable value is permanently inactive
+ if (sig_e != val_ep) {
+ // Q is permanently initial value
+ mod->connect(sig_q, val_init);
+ goto delete_dff;
+ }
+
+ log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
+
+ if (dff->type == "$dffe") {
+ dff->type = "$dff";
+ dff->unsetPort("\\EN");
+ dff->unsetParam("\\EN_POLARITY");
+ return true;
+ }
+
+ log_assert(dff->type.substr(0,7) == "$_DFFE_");
+ dff->type = stringf("$_DFF_%c_", + dff->type[7]);
+ dff->unsetPort("\\E");
+ }
+
return false;
delete_dff:
@@ -489,7 +552,8 @@ struct OptRmdffPass : public Pass {
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
- "$ff", "$dff", "$adff"))
+ "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
+ "$ff", "$dff", "$dffe", "$adff"))
dff_list.push_back(cell->name);
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 58c6e4b4b..1fbc41082 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig
{
pool<IdString> supported_cell_types;
+ bool keepdc = false;
WreduceConfig()
{
@@ -82,7 +83,7 @@ struct WreduceWorker
SigBit ref = sig_a[i];
for (int k = 0; k < GetSize(sig_s); k++) {
- if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
+ if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
if (sig_b[k*GetSize(sig_a) + i] != Sx)
ref = sig_b[k*GetSize(sig_a) + i];
@@ -495,6 +496,9 @@ struct WreducePass : public Pass {
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");
+ log(" -keepdc\n");
+ log(" Do not optimize explicit don't-care values.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
@@ -509,6 +513,10 @@ struct WreducePass : public Pass {
opt_memx = true;
continue;
}
+ if (args[argidx] == "-keepdc") {
+ config.keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg
index fe861b728..6adab4e5f 100644
--- a/passes/pmgen/peepopt_shiftmul.pmg
+++ b/passes/pmgen/peepopt_shiftmul.pmg
@@ -1,4 +1,7 @@
pattern shiftmul
+//
+// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
+//
state <SigSpec> shamt
@@ -49,12 +52,16 @@ code
if (GetSize(port(shift, \Y)) > const_factor)
reject;
+ int factor_bits = ceil_log2(const_factor);
+ SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A);
+
+ if (GetSize(shamt) < factor_bits+GetSize(mul_din))
+ reject;
+
did_something = true;
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
- int new_const_factor_log2 = ceil_log2(const_factor);
- int new_const_factor = 1 << new_const_factor_log2;
-
+ int new_const_factor = 1 << factor_bits;
SigSpec padding(State::Sx, new_const_factor-const_factor);
SigSpec old_a = port(shift, \A), new_a;
int trunc = 0;
@@ -73,7 +80,7 @@ code
if (trunc > 0)
new_a.remove(GetSize(new_a)-trunc, trunc);
- SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
+ SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
if (param(shift, \B_SIGNED).as_bool())
new_b.append(State::S0);
diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc
index cd75ca860..00c098542 100644
--- a/passes/sat/fmcombine.cc
+++ b/passes/sat/fmcombine.cc
@@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
struct opts_t
{
+ bool initeq = false;
+ bool anyeq = false;
bool fwd = false;
bool bwd = false;
bool nop = false;
@@ -56,7 +58,7 @@ struct FmcombineWorker
return newsig;
}
- void import_prim_cell(Cell *cell, const string &suffix)
+ Cell *import_prim_cell(Cell *cell, const string &suffix)
{
Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters;
@@ -64,6 +66,8 @@ struct FmcombineWorker
for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix));
+
+ return c;
}
void import_hier_cell(Cell *cell)
@@ -102,8 +106,24 @@ struct FmcombineWorker
for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) {
- import_prim_cell(cell, "_gold");
- import_prim_cell(cell, "_gate");
+ if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
+ Cell *gold = import_prim_cell(cell, "_gold");
+ for (auto &conn : cell->connections())
+ module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first));
+ } else {
+ Cell *gold = import_prim_cell(cell, "_gold");
+ Cell *gate = import_prim_cell(cell, "_gate");
+ if (opts.initeq) {
+ if (cell->type.in("$ff", "$dff", "$dffe",
+ "$dffsr", "$adff", "$dlatch", "$dlatchsr")) {
+ SigSpec gold_q = gold->getPort("\\Q");
+ SigSpec gate_q = gate->getPort("\\Q");
+ SigSpec en = module->Initstate(NEW_ID);
+ SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q);
+ module->addAssume(NEW_ID, eq, en);
+ }
+ }
+ }
} else {
import_hier_cell(cell);
}
@@ -229,6 +249,13 @@ struct FmcombinePass : public Pass {
log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n");
log("\n");
+ log(" -initeq\n");
+ log(" Insert assumptions that initially all FFs in both circuits have the\n");
+ log(" same initial values.\n");
+ log("\n");
+ log(" -anyeq\n");
+ log(" Do not duplicate $anyseq/$anyconst cells.\n");
+ log("\n");
log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n");
log("\n");
@@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
// filename = args[++argidx];
// continue;
// }
+ if (args[argidx] == "-initeq") {
+ opts.initeq = true;
+ continue;
+ }
+ if (args[argidx] == "-anyeq") {
+ opts.anyeq = true;
+ continue;
+ }
if (args[argidx] == "-fwd") {
opts.fwd = true;
continue;
@@ -297,7 +332,7 @@ struct FmcombinePass : public Pass {
gate_cell = module->cell(gate_name);
if (gate_cell == nullptr)
- log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
+ log_cmd_error("Gate cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
}
else
{
@@ -316,7 +351,7 @@ struct FmcombinePass : public Pass {
if (!gold_cell->parameters.empty())
log_cmd_error("Gold cell has unresolved instance parameters.\n");
if (!gate_cell->parameters.empty())
- log_cmd_error("Gold cell has unresolved instance parameters.\n");
+ log_cmd_error("Gate cell has unresolved instance parameters.\n");
FmcombineWorker worker(design, gold_cell->type, opts);
worker.generate();
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 991cc4498..349ccc115 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
- str = c;
+ str = static_cast<char>(c);
while (1) {
c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index b46147fb9..2aefc091d 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-singleton") {
+ if (args[argidx] == "-all") {
all_mode = true;
continue;
}