From f0f575593a05b35a1a6f04a2a97337164a23b1d7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 15 Nov 2025 01:58:16 +0100 Subject: [PATCH] proc_mux: add comments --- passes/proc/proc_mux.cc | 84 ++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index b0315da72..394c188af 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -28,6 +28,21 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +/** + * Actions are assignments in cases of switches. + * Snippets are non-overlapping slices of signals on the left-hand side + * of actions. For example, if you have these two actions for r[7:0]: + * r = a; r[1:2] = 2'b0; + * you will arrive at three snippets: + * r[0], r[2:1], r[7:3] + * For each snippet, multiplexers ($mux or $pmux) are emitted + * based on the full switch. + * $pmux are only emitted when legal based on whether the cases can be + * evaluated in parallel. + * In that case, instead of a $pmux, you get a chain of $mux. + * Nested switches build branching trees of muxes. + */ + using SnippetSourceMap = std::vector>; struct SnippetSourceMapBuilder { SnippetSourceMap map; @@ -202,6 +217,7 @@ struct MuxGenCtx { int current_snippet; pool& snippet_sources; + // Returns signal for the select input of a mux RTLIL::SigSpec gen_cmp() { std::stringstream sstr; sstr << "$procmux$" << (autoidx++); @@ -408,6 +424,38 @@ bool is_simple_parallel_case(RTLIL::SwitchRule* sw, dict parallel_groups(MuxTreeContext ctx, RTLIL::SwitchRule* sw) +{ + std::vector pgroups(sw->cases.size()); + if (!is_simple_parallel_case(sw, ctx.swpara)) { + BitPatternPool pool(sw->signal.size()); + bool extra_group_for_next_case = false; + for (size_t i = 0; i < sw->cases.size(); i++) { + RTLIL::CaseRule *cs2 = sw->cases[i]; + if (i != 0) { + pgroups[i] = pgroups[i-1]; + if (extra_group_for_next_case) { + pgroups[i] = pgroups[i-1]+1; + extra_group_for_next_case = false; + } + for (auto pat : cs2->compare) + if (!pat.is_fully_const() || !pool.has_all(pat)) + pgroups[i] = pgroups[i-1]+1; + if (cs2->compare.empty()) + pgroups[i] = pgroups[i-1]+1; + if (pgroups[i] != pgroups[i-1]) + pool = BitPatternPool(sw->signal.size()); + } + for (auto pat : cs2->compare) + if (!pat.is_fully_const()) + extra_group_for_next_case = true; + else if (!ctx.ifxmode) + pool.take(pat); + } + } + return pgroups; +} + RTLIL::SigSpec signal_to_mux_tree(MuxTreeContext ctx) { RTLIL::SigSpec result = ctx.defval; @@ -422,36 +470,9 @@ RTLIL::SigSpec signal_to_mux_tree(MuxTreeContext ctx) if (!ctx.swcache.check(sw)) continue; - // detect groups of parallel cases - std::vector pgroups(sw->cases.size()); + // Detect groups of parallel cases + std::vector pgroups = parallel_groups(ctx, sw); pool case_sources; - - if (!is_simple_parallel_case(sw, ctx.swpara)) { - BitPatternPool pool(sw->signal.size()); - bool extra_group_for_next_case = false; - for (size_t i = 0; i < sw->cases.size(); i++) { - RTLIL::CaseRule *cs2 = sw->cases[i]; - if (i != 0) { - pgroups[i] = pgroups[i-1]; - if (extra_group_for_next_case) { - pgroups[i] = pgroups[i-1]+1; - extra_group_for_next_case = false; - } - for (auto pat : cs2->compare) - if (!pat.is_fully_const() || !pool.has_all(pat)) - pgroups[i] = pgroups[i-1]+1; - if (cs2->compare.empty()) - pgroups[i] = pgroups[i-1]+1; - if (pgroups[i] != pgroups[i-1]) - pool = BitPatternPool(sw->signal.size()); - } - for (auto pat : cs2->compare) - if (!pat.is_fully_const()) - extra_group_for_next_case = true; - else if (!ctx.ifxmode) - pool.take(pat); - } - } // Create sources for default cases for (auto cs2 : sw -> cases) { if (cs2->compare.empty()) { @@ -466,7 +487,8 @@ RTLIL::SigSpec signal_to_mux_tree(MuxTreeContext ctx) result[i] = State::Sx; RTLIL::SigSpec initial_val = result; - MuxGenCtx mux_gen_ctx {ctx.mod, + MuxGenCtx mux_gen_ctx { + ctx.mod, sw->signal, nullptr, nullptr, @@ -477,7 +499,7 @@ RTLIL::SigSpec signal_to_mux_tree(MuxTreeContext ctx) ctx.swcache.current_snippet, case_sources }; - // evaluate in reverse order to give the first entry the top priority + // Evaluate in reverse order to give the first entry the top priority for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; MuxTreeContext new_ctx = ctx;