From 8192cee0b3e435482f2bc98a26899db17efec7e9 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 19 Jan 2026 13:40:27 +0100 Subject: [PATCH] proc_dff: narrow $priority --- passes/proc/proc_dff.cc | 123 ++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc index 0bd442e2e..5004bf4cd 100644 --- a/passes/proc/proc_dff.cc +++ b/passes/proc/proc_dff.cc @@ -177,44 +177,46 @@ void gen_dffsr(RTLIL::Module *mod, DSigs sigs, bool clk_polarity, struct Builder { - using BitControl = std::pair, std::optional>; - std::vector cells {}; - std::unordered_map, BitControl> map = {}; + using MaybeBitControl = std::pair, std::optional>; + std::unordered_map, MaybeBitControl> map = {}; RTLIL::Module* mod; - RTLIL::Wire* prioritized; - RTLIL::SigSpec priority_in; - std::vector priority_pol; + RTLIL::Process* proc; bool set_pol, reset_pol; - Builder(RTLIL::Module* mod, size_t rule_count, bool s, bool r) : mod(mod), set_pol(s), reset_pol(r) { - prioritized = mod->addWire(NEW_ID, 0); - RTLIL::Cell* priority = mod->addPriority(NEW_ID, SigSpec(), prioritized); - priority->setParam(ID::P_WIDTH, rule_count); - cells.push_back(priority); + RTLIL::SigBit const_if_none(std::optional maybe, bool polarity) { + if (maybe) + return *maybe; + // Set the control signal to be constantly inactive + if (polarity) + return set_pol ? RTLIL::State::S0 : RTLIL::State::S1; + else + return reset_pol ? RTLIL::State::S0 : RTLIL::State::S1; } - BitControl build(std::vector>& rules) { - std::vector applicable; - int skips = 0; - for (auto rule : rules) { - if (rule) { - applicable.push_back(*rule); - } else { - skips += 1; - log_debug("Unused bit due to no assignment to this bit from this rule\n"); - } - } - log_debug("count?\n"); - if (map.count(applicable)) { - log_debug("hit!\n"); - return map[applicable]; + Builder(RTLIL::Module* mod, RTLIL::Process* proc, bool s, bool r) : mod(mod), proc(proc), set_pol(s), reset_pol(r) {} + std::pair priority(const std::vector& applicable) { + RTLIL::SigSpec bit_sets {}; + RTLIL::SigSpec bit_resets {}; + if (!applicable.size()) { + return std::make_pair(bit_sets, bit_resets); + } else if (applicable.size() == 1) { + auto rule = applicable[0]; + if (rule.effect) + bit_sets.append(rule.trig); + else + bit_resets.append(rule.trig); + return std::make_pair(bit_sets, bit_resets); } + RTLIL::Wire* prioritized = mod->addWire(NEW_ID, applicable.size()); + prioritized->attributes = proc->attributes; + RTLIL::Cell* priority = mod->addPriority(NEW_ID, SigSpec(), prioritized); + priority->attributes = proc->attributes; + priority->setParam(ID::WIDTH, applicable.size()); - SigSpec bit_sets; - SigSpec bit_resets; + RTLIL::SigSpec priority_in; + std::vector priority_pol; // Construct applicable rules for (auto rule : applicable) { log_debug("if %s == %d then set %d\n", log_signal(rule.trig), rule.trig_polarity, rule.effect); - prioritized->width++; priority_in.append(rule.trig); priority_pol.push_back(RTLIL::State(rule.trig_polarity)); if (rule.effect) @@ -223,70 +225,67 @@ void gen_dffsr(RTLIL::Module *mod, DSigs sigs, bool clk_polarity, bit_resets.append(SigBit(prioritized, priority_in.size() - 1)); } - // Stuff $priority with unused bits - priority_in.append(Const(0, skips)); - for (int i = 0; i < skips; i++) { - prioritized->width++; - priority_pol.push_back(RTLIL::State::S0); - } - - std::optional set; + priority->setPort(ID::A, priority_in); + priority->setPort(ID::Y, prioritized); // fixup (previously zero-width) + priority->setParam(ID::POLARITY, priority_pol); + return std::make_pair(bit_sets, bit_resets); + } + std::pair reduce(const std::pair& unreduced) { + const auto& [bit_sets, bit_resets] = unreduced; + std::optional set, reset; if (bit_sets.size()) { if (bit_sets.size() == 1) { set = bit_sets[0]; } else { set = mod->addWire(NEW_ID); - // Polarities are consistent, as guaranteed by check prior - cells.push_back(set_pol ? mod->addReduceOr(NEW_ID, bit_sets, *set) : mod->addReduceAnd(NEW_ID, bit_sets, *set)); + set->wire->attributes = proc->attributes; + // Polarities are required to be consistent, as guaranteed by check above buildere + (set_pol ? mod->addReduceOr(NEW_ID, bit_sets, *set) : mod->addReduceAnd(NEW_ID, bit_sets, *set))->attributes = proc->attributes; } } - std::optional reset; if (bit_resets.size()) { if (bit_resets.size() == 1) { reset = bit_resets[0]; } else { reset = mod->addWire(NEW_ID); - cells.push_back(reset_pol ? mod->addReduceOr(NEW_ID, bit_resets, *reset) : mod->addReduceAnd(NEW_ID, bit_resets, *reset)); + reset->wire->attributes = proc->attributes; + (reset_pol ? mod->addReduceOr(NEW_ID, bit_resets, *reset) : mod->addReduceAnd(NEW_ID, bit_resets, *reset))->attributes = proc->attributes; } } - if (!set) - set = set_pol ? RTLIL::State::S0 : RTLIL::State::S1; - if (!reset) - reset = reset_pol ? RTLIL::State::S0 : RTLIL::State::S1; + return std::make_pair(const_if_none(set, true), const_if_none(reset, false)); + } + MaybeBitControl build(std::vector>& rules) { + std::vector applicable; + for (auto rule : rules) { + if (rule) { + applicable.push_back(*rule); + } else { + log_debug("Unused bit due to no assignment to this bit from this rule\n"); + } + } + if (map.count(applicable)) { + return map[applicable]; + } - auto ret = std::make_pair(set, reset); + auto priority_controls = priority(applicable); + auto ret = reduce(priority_controls); map[applicable] = ret; return ret; - - } - void finish(RTLIL::Process* proc) { - prioritized->attributes = proc->attributes; - for (auto* cell : cells) - cell->attributes = proc->attributes; - - cells[0]->setPort(ID::A, priority_in); - cells[0]->setPort(ID::Y, prioritized); // fixup (previously zero-width) - cells[0]->setParam(ID::POLARITY, priority_pol); - cells[0]->setParam(ID::WIDTH, cells[0]->getPort(ID::A).size() / cells[0]->getParam(ID::P_WIDTH).as_int()); } }; - Builder builder(mod, async_rules.size(), *set_pol, *reset_pol); + Builder builder(mod, proc, *set_pol, *reset_pol); for (int i = 0; i < sigs.d.size(); i++) { - log_debug("bit %d:\n", i); auto [set, reset] = builder.build(bit_rules[i]); sig_sr_set.append(*set); sig_sr_clr.append(*reset); } - builder.finish(proc); std::stringstream sstr; sstr << "$procdff$" << (autoidx++); - RTLIL::Cell *cell = mod->addDffsr(sstr.str(), sigs.clk, sig_sr_set, sig_sr_clr, sigs.d, sigs.q, clk_polarity); cell->attributes = proc->attributes; cell->setParam(ID::SET_POLARITY, Const(*set_pol, 1)); cell->setParam(ID::CLR_POLARITY, Const(*reset_pol, 1)); - log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative"); }