struct SnippetSwCache
{
+ dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
const SigSnippets *snippets;
int current_snippet;
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
+const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw)
+{
+ if (!swcache.full_case_bits_cache.count(sw))
+ {
+ pool<SigBit> bits;
+
+ if (sw->get_bool_attribute("\\full_case"))
+ {
+ bool first_case = true;
+
+ for (auto cs : sw->cases)
+ {
+ pool<SigBit> case_bits;
+
+ for (auto it : cs->actions) {
+ for (auto bit : it.first)
+ case_bits.insert(bit);
+ }
+
+ for (auto it : cs->switches) {
+ for (auto bit : get_full_case_bits(swcache, it))
+ case_bits.insert(bit);
+ }
+
+ if (first_case) {
+ first_case = false;
+ bits = case_bits;
+ } else {
+ pool<SigBit> new_bits;
+ for (auto bit : bits)
+ if (case_bits.count(bit))
+ new_bits.insert(bit);
+ bits.swap(new_bits);
+ }
+ }
+ }
+
+ bits.swap(swcache.full_case_bits_cache[sw]);
+ }
+
+ return swcache.full_case_bits_cache.at(sw);
+}
+
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{
}
}
+ // mask default bits that are irrelevant because the output is driven by a full case
+ const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw);
+ for (int i = 0; i < GetSize(sig); i++)
+ if (full_case_bits.count(sig[i]))
+ result[i] = State::Sx;
+
// evaluate in reverse order to give the first entry the top priority
RTLIL::SigSpec initial_val = result;
RTLIL::Cell *last_mux_cell = NULL;
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
BitPatternPool pool(sw->signal);
}
for (auto switch_it : sw->cases[i]->switches)
- proc_rmdead(switch_it, counter);
+ proc_rmdead(switch_it, counter, full_case_counter);
if (is_default)
pool.take_all();
}
+
+ if (pool.empty() && !sw->get_bool_attribute("\\full_case")) {
+ sw->set_bool_attribute("\\full_case");
+ full_case_counter++;
+ }
}
struct ProcRmdeadPass : public Pass {
for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second))
continue;
- int counter = 0;
+ int counter = 0, full_case_counter = 0;
for (auto switch_it : proc_it.second->root_case.switches)
- proc_rmdead(switch_it, counter);
+ proc_rmdead(switch_it, counter, full_case_counter);
if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter,
- proc_it.first.c_str(), log_id(mod));
+ log_id(proc_it.first), log_id(mod));
+ if (full_case_counter > 0)
+ log("Marked %d switch rules as full_case in process %s in module %s.\n",
+ full_case_counter, log_id(proc_it.first), log_id(mod));
total_counter += counter;
}
}