YosysHQ / yosys

Yosys Open SYnthesis Suite
https://yosyshq.net/yosys/
ISC License
3.51k stars 895 forks source link

Add tri-state support for const eval and add tribuf -propagate option #4661

Open Rodrigodd opened 1 month ago

Rodrigodd commented 1 month ago

What are the reasons/motivation for this change?

I am working on a non-synthesizable project (https://github.com/emu-russia/dmgcpu) that makes extensive use of tri-state signals. This causes problems because projects like Verilator and Yosys don't handle those very well.

Explain how this is achieved.

Yosys already has the tribuf -logic pass, which can merge signals driven by multiple tribuf cells into a $pmux, allowing the elimination of tristate signals in a design. However, it didn't handle tristates nested in muxes.

This change implements the -propagate option, which propagates tri-state buffers through muxes.

This allows for eliminating all tristate usage in a design by flattening the module hierarchy, detecting and propagating all tribuf cells, and resolving them as a $pmux. See https://github.com/emu-russia/dmgcpu/pull/292 for this being done in practice.

If applicable, please suggest to reviewers how they can test the change.

The change includes the test file tests/techmap/tribuf.ys, which tests many of the cases the implementation handles and exemplifies how the command is used.

Summary of changes

The PR can be split into these changes:

The main change is the -propagate option, and the two above are only used to allow automatic testing of that change. If you prefer, I can split up this PR.

eval -assert

Asserts that a signal evaluates to a specific value. This is used in conjunction with equiv_make to check if the modifications applied maintain the circuit behavior. I think most tests used miter -equiv instead, but I'm not sure if that works with designs with tristate signals (at least it didn't work before adding tri-state support to consteval).

When -table is used, it asserts the same value for each input combination. The command will first print the result or table before erroring out.

Consteval tri-state signals

This change makes consteval.cc resolve signals from multiple drivers, following the Verilog spec but ignoring signal strength.

The old implementation contained a SigMap values_map that mapped the signals to their constant value. This was split into a ConstMap that maps a sigbit to its possibly partially evaluated State, and a SigPool evaluated that tells if a sigbit was fully evaluated.

ConstEval::add handles resolving the new value assigned to a sigbit with its previous value, like resolving conflicting values to x, or keeping one value when the other is z.

Stopped using ConstEval::set internally, replacing it with ConstEval::assign. ConstEval::set is now only used externally and marks a value as evaluated.

tribuf -propagate

Propagates tri-state signals through muxes and tribuf cells. Also reworks the implementation of -merge, making it work at sigbit granularity and splitting tribuf cells when necessary.

tribuf -logic -force

By default, tribuf -logic will not replace a tribuf cell that is driving an output port. -force allows doing something like tribuf -logic -force w:OutPort %ci1 in case the output port is not actually a tristate port.