aboutsummaryrefslogtreecommitdiffstats
path: root/passes/opt
diff options
context:
space:
mode:
authorEddie Hung <eddie@fpgeh.com>2019-06-12 08:50:39 -0700
committerEddie Hung <eddie@fpgeh.com>2019-06-12 08:50:39 -0700
commitf7a9769c140f6a56e51d7384dfd8e76bf2aef66d (patch)
tree4be49b8b30a03ac7d4deafaa7318de275d5c3a7f /passes/opt
parentac2aff9e28a087a9a2697cd6ccf754af738903a7 (diff)
parenta91ea6612a73568782c80bd12ce2875353e2b5c5 (diff)
downloadyosys-f7a9769c140f6a56e51d7384dfd8e76bf2aef66d.tar.gz
yosys-f7a9769c140f6a56e51d7384dfd8e76bf2aef66d.tar.bz2
yosys-f7a9769c140f6a56e51d7384dfd8e76bf2aef66d.zip
Merge remote-tracking branch 'origin/master' into xaig
Diffstat (limited to 'passes/opt')
-rw-r--r--passes/opt/opt_clean.cc203
-rw-r--r--passes/opt/opt_expr.cc50
-rw-r--r--passes/opt/opt_muxtree.cc14
-rw-r--r--passes/opt/opt_rmdff.cc72
-rw-r--r--passes/opt/wreduce.cc50
5 files changed, 308 insertions, 81 deletions
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index c38e9df5e..cfb0f788a 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true;
if (cell->has_keep_attr())
@@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
pool<Cell*> queue, unused;
+ pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
+ dict<SigBit, vector<string>> driver_driver_logs;
+
+ SigMap raw_sigmap;
+ for (auto &it : module->connections_) {
+ for (int i = 0; i < GetSize(it.second); i++) {
+ if (it.second[i].wire != nullptr)
+ raw_sigmap.add(it.first[i], it.second[i]);
+ }
+ }
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
- if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
- for (auto raw_bit : it2.second) {
- if (raw_bit.wire == nullptr)
- continue;
- auto bit = sigmap(raw_bit);
- if (bit.wire == nullptr)
- log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
- log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
- if (bit.wire != nullptr)
- wire2driver[bit].insert(cell);
- }
+ if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
+ continue;
+ for (auto raw_bit : it2.second) {
+ if (raw_bit.wire == nullptr)
+ continue;
+ auto bit = sigmap(raw_bit);
+ if (bit.wire == nullptr && ct_all.cell_known(cell->type))
+ driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
+ "for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
+ log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
+ if (bit.wire != nullptr)
+ wire2driver[bit].insert(cell);
+ }
}
if (keep_cache.query(cell))
queue.insert(cell);
@@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c);
+ for (auto raw_bit : SigSpec(wire))
+ used_raw_bits.insert(raw_sigmap(raw_bit));
}
}
@@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose)
module->remove(cell);
count_rm_cells++;
}
+
+ for (auto &it : module->cells_) {
+ Cell *cell = it.second;
+ for (auto &it2 : cell->connections()) {
+ if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
+ continue;
+ for (auto raw_bit : raw_sigmap(it2.second))
+ used_raw_bits.insert(raw_bit);
+ }
+ }
+
+ for (auto it : driver_driver_logs) {
+ if (used_raw_bits.count(it.first))
+ for (auto msg : it.second)
+ log_warning("%s\n", msg.c_str());
+ }
}
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@@ -202,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;
@@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
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);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
@@ -259,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)
@@ -271,72 +304,103 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
- std::vector<RTLIL::Wire*> maybe_del_wires;
+ pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires())
{
- if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
- RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
- assign_map.apply(s2);
- if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
- maybe_del_wires.push_back(wire);
- } else {
- log_assert(GetSize(s1) == GetSize(s2));
- RTLIL::SigSig new_conn;
- for (int i = 0; i < GetSize(s1); i++)
- if (s1[i] != s2[i]) {
- new_conn.first.append_bit(s1[i]);
- new_conn.second.append_bit(s2[i]);
+ SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
+ log_assert(GetSize(s1) == GetSize(s2));
+
+ Const initval;
+ if (wire->attributes.count("\\init"))
+ initval = wire->attributes.at("\\init");
+ if (GetSize(initval) != GetSize(wire))
+ initval.bits.resize(GetSize(wire), State::Sx);
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+
+ if (GetSize(wire) == 0) {
+ // 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
+ } else
+ if (!purge_mode && check_public_name(wire->name)) {
+ // do not get rid of public names unless in purge mode
+ } else
+ if (!raw_used_signals.check_any(s1)) {
+ // delete wires that aren't used by anything directly
+ goto delete_this_wire;
+ } else
+ 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;
+ }
+
+ if (0)
+ {
+ delete_this_wire:
+ del_wires_queue.insert(wire);
+ }
+ else
+ {
+ RTLIL::SigSig new_conn;
+ for (int i = 0; i < GetSize(s1); i++)
+ if (s1[i] != s2[i]) {
+ if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
+ s2[i] = initval[i];
+ initval[i] = State::Sx;
}
- if (new_conn.first.size() > 0) {
- used_signals.add(new_conn.first);
- used_signals.add(new_conn.second);
- module->connect(new_conn);
+ new_conn.first.append_bit(s1[i]);
+ new_conn.second.append_bit(s2[i]);
}
+ if (new_conn.first.size() > 0) {
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ used_signals.add(new_conn.first);
+ used_signals.add(new_conn.second);
+ module->connect(new_conn);
}
- } else {
- if (!used_signals.check_any(RTLIL::SigSpec(wire)))
- maybe_del_wires.push_back(wire);
- }
- RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
- if (!used_signals_nodrivers.check_any(sig)) {
- std::string unused_bits;
- for (int i = 0; i < GetSize(sig); i++) {
- if (sig[i].wire == NULL)
- continue;
- if (!used_signals_nodrivers.check(sig[i])) {
- if (!unused_bits.empty())
- unused_bits += " ";
- unused_bits += stringf("%d", i);
+ if (!used_signals_nodrivers.check_all(s2)) {
+ std::string unused_bits;
+ for (int i = 0; i < GetSize(s2); i++) {
+ if (s2[i].wire == NULL)
+ continue;
+ if (!used_signals_nodrivers.check(s2[i])) {
+ if (!unused_bits.empty())
+ unused_bits += " ";
+ unused_bits += stringf("%d", i);
+ }
}
- }
- if (unused_bits.empty() || wire->port_id != 0)
+ if (unused_bits.empty() || wire->port_id != 0)
+ wire->attributes.erase("\\unused_bits");
+ else
+ wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
+ } else {
wire->attributes.erase("\\unused_bits");
- else
- wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
- } else {
- wire->attributes.erase("\\unused_bits");
+ }
}
}
+ int del_temp_wires_count = 0;
+ for (auto wire : del_wires_queue) {
+ if (ys_debug() || (check_public_name(wire->name) && verbose))
+ log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
+ else
+ del_temp_wires_count++;
+ }
- pool<RTLIL::Wire*> del_wires;
+ module->remove(del_wires_queue);
+ count_rm_wires += GetSize(del_wires_queue);
- int del_wires_count = 0;
- for (auto wire : maybe_del_wires)
- if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
- if (check_public_name(wire->name) && verbose) {
- log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
- }
- del_wires.insert(wire);
- del_wires_count++;
- }
+ if (verbose && del_temp_wires_count)
+ log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
- module->remove(del_wires);
- count_rm_wires += del_wires.size();
-
- if (verbose && del_wires_count > 0)
- log_debug(" removed %d unused temporary wires.\n", del_wires_count);
+ return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@@ -434,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 {
@@ -483,6 +547,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design);
+ count_rm_cells = 0;
+ count_rm_wires = 0;
+
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
@@ -548,7 +615,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, false, false);
+ rmunused_module(module, purge_mode, ys_debug(), false);
}
log_suppressed();
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index af6d352af..512ef0cbf 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals;
SigPool all_signals;
+ dict<SigBit, pair<Wire*, State>> initbits;
+ pool<Wire*> revisit_initwires;
+
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
@@ -48,9 +51,17 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
for (auto wire : module->wires()) {
+ if (wire->attributes.count("\\init")) {
+ SigSpec sig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[sig[i]] = make_pair(wire, initval[i]);
+ }
+ }
if (wire->port_input)
driven_signals.add(sigmap(wire));
- if (wire->port_output)
+ if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
@@ -67,10 +78,43 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0)
continue;
- log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
- module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
+ Const val(RTLIL::State::Sx, GetSize(sig));
+ for (int i = 0; i < GetSize(sig); i++) {
+ SigBit bit = sigmap(sig[i]);
+ auto cursor = initbits.find(bit);
+ if (cursor != initbits.end()) {
+ revisit_initwires.insert(cursor->second.first);
+ val[i] = cursor->second.second;
+ }
+ }
+
+ log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
+ module->connect(sig, val);
did_something = true;
}
+
+ if (!revisit_initwires.empty())
+ {
+ SigMap sm2(module);
+
+ for (auto wire : revisit_initwires) {
+ SigSpec sig = sm2(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
+ if (SigBit(initval[i]) == sig[i])
+ initval[i] = State::Sx;
+ }
+ if (initval.is_fully_undef()) {
+ log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
+ wire->attributes.erase("\\init");
+ did_something = true;
+ } else if (initval != wire->attributes.at("\\init")) {
+ log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
+ wire->attributes["\\init"] = initval;
+ did_something = true;
+ }
+ }
+ }
}
void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
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..eeb992a3e 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[7] == 'P', 1);
+ val_ep = RTLIL::Const(dff->type[8] == '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 52245ce3e..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];
@@ -180,6 +181,8 @@ struct WreduceWorker
}
auto info = mi.query(sig_q[i]);
+ if (info == nullptr)
+ return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
@@ -462,12 +465,10 @@ struct WreduceWorker
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) {
- log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
w->attributes.at("\\init") = new_initval;
- log_dump(w->name, initval, new_initval);
}
}
}
@@ -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);
@@ -531,6 +539,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig)));
}
}
+
+ if (c->type.in("$div", "$mod", "$pow"))
+ {
+ SigSpec A = c->getPort("\\A");
+ int original_a_width = GetSize(A);
+ if (c->getParam("\\A_SIGNED").as_bool()) {
+ while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
+ A.remove(GetSize(A)-1, 1);
+ } else {
+ while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
+ A.remove(GetSize(A)-1, 1);
+ }
+ if (original_a_width != GetSize(A)) {
+ log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
+ original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
+ c->setPort("\\A", A);
+ c->setParam("\\A_WIDTH", GetSize(A));
+ }
+
+ SigSpec B = c->getPort("\\B");
+ int original_b_width = GetSize(B);
+ if (c->getParam("\\B_SIGNED").as_bool()) {
+ while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
+ B.remove(GetSize(B)-1, 1);
+ } else {
+ while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
+ B.remove(GetSize(B)-1, 1);
+ }
+ if (original_b_width != GetSize(B)) {
+ log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
+ original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
+ c->setPort("\\B", B);
+ c->setParam("\\B_WIDTH", GetSize(B));
+ }
+ }
+
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid);