Skip to content

tribuf: -nested option: traverse muxes to find nested tribufs#5716

Open
Muxianesty wants to merge 2 commits intoYosysHQ:mainfrom
Muxianesty:muxianesty/tribuf_nested_muxes
Open

tribuf: -nested option: traverse muxes to find nested tribufs#5716
Muxianesty wants to merge 2 commits intoYosysHQ:mainfrom
Muxianesty:muxianesty/tribuf_nested_muxes

Conversation

@Muxianesty
Copy link
Copy Markdown

@Muxianesty Muxianesty commented Feb 28, 2026

Judging by how current tribuf-pass works, only muxes having the "direct" Z-operand are marked as $tribuf cells, while in more complex cases Z-operand muxes are used in other muxes, with latter being the "true" tristate cells:

module top(input [3:0] in1, input [3:0] in2, input [3:0] in3, input sel1, input sel2, input sel3, output [3:0] out1);
  assign out1 = (sel1) ? in1 : ((sel2) ? in2 : 4'bzzzz);
  assign out1 = (sel3) ? in3 : 4'bzzzz;
endmodule

In the example above current tribuf pass does not recognize the first mux as a tristate cell.

This Pull Request introduces an option -nested, which traverses muxes in a recursive fashion trying to find the first Z-operand (specifically, the $tribuf cell, leading to Z-operand). If found, we construct a logical expression - a conjuntion of all traversed selectors' expressions - to form a condition which "leads" us to the Z-operand, then reverse it. The resulting condition is used as a selector in a newly created $tribuf cell. In the example above the expression would be ~((~sel) && (~sel2)).

To put it simply, we "put forward" the Z-operand to create a "top-level" $tribuf cell to be picked by -merge-like options later.

The idea to put this functionality into a separate option rather than being used by default stems from the expansive muxes traversal needing to be done, which in most cases might impact the performance quite a lot.

@Muxianesty Muxianesty marked this pull request as ready for review February 28, 2026 21:42
Comment thread passes/techmap/tribuf.cc
log(" same net simultaneously. this option implies -merge.\n");
log("\n");
log(" -nested\n");
log(" convert multiplexers using tri-state cells to tri-state cells\n");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this help message could be improved, but I'm struggling to come up with a good replacement.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

treat nesting multiplexers with Z-vectors as tri-state cells

?

Copy link
Copy Markdown
Collaborator

@widlarizer widlarizer Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more complex and specific than that short version. "If a multiplexer is observed outside of a mux tree, convert it to a $tribuf and construct potentially highly complex logic connected to its EN pin to represent the total Z-generation condition" is probably as dense as I can make it. Ultimately, I don't think this will ever have more than one user benefitting from it (you) so it's not a big deal as long as users/devs don't enable it by accident expecting generally useful things to happen

Copy link
Copy Markdown
Collaborator

@Ravenslofty Ravenslofty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems okay to me, code-wise, and it seems like a feature that's useful enough that you might want to enable it inside the various synth flows that already call tribuf -logic.

@Ravenslofty Ravenslofty self-assigned this Mar 2, 2026
@Ravenslofty
Copy link
Copy Markdown
Collaborator

Ravenslofty commented Mar 2, 2026

After discussing this with the team, this actually seems like a correctness fix. In that scenario, we'd actually prefer this to be the default behaviour, with an option to disable it to restore the old behaviour if really needed.

@widlarizer
Copy link
Copy Markdown
Collaborator

image I change my mind, I don't think this is desirable default behavior. I wonder what kind of design even benefits from this?

@Muxianesty
Copy link
Copy Markdown
Author

Muxianesty commented Mar 2, 2026

The idea was to "correctly" gather all tri-state cells to then later convert them into $pmux with -merge.
I agree this is an expansive, yet simple solution to escape "multiple conflicting drivers" issue from pass check.

Comment thread passes/techmap/tribuf.cc
SigSpec sig;
bool inv;

TribufSelPart(const SigSpec &sig, bool inv) : sig(sig), inv(inv)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need constructors like this if you use curly brace initialization (another C++ bruh moment for the books)

Comment thread passes/techmap/tribuf.cc
}

private:
struct TribufSelPart {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire code block seems to be an integral part of the code of the pass. Since it's supporting a niche extra mode, it should be clearly seggregated. TribufSelPart, collect_tribuf_cell... they all seem like code a dev should read when trying to understand the basic function of the pass, which would be the wrong thing to do. You also need to make it clear what you're doing on a logic modeling and algorithmization level. Are you sure you're not doing exactly what we already have in kernel/pattern.h for example?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants