mirror of
https://github.com/YosysHQ/yosys
synced 2026-03-23 04:49:15 +00:00
Merge 7b88b31601 into 5fd39ff3e1
This commit is contained in:
commit
0c7ec830df
3 changed files with 111 additions and 0 deletions
|
|
@ -393,6 +393,27 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
|
|||
if (full_case_bits.count(sig[i]))
|
||||
result[i] = State::Sx;
|
||||
|
||||
// For full_case switches, if a majority of arms assign the same value to a bit
|
||||
// (via direct actions), use that as the else-branch seed instead of Sx. This
|
||||
// lets proc_mux skip generating mux cells for arms that produce the dominant value.
|
||||
if (!full_case_bits.empty() && !sw->cases.empty()) {
|
||||
int n = GetSize(sw->cases);
|
||||
std::vector<dict<SigBit, int>> counts(GetSize(sig));
|
||||
for (auto cs2 : sw->cases) {
|
||||
RTLIL::SigSpec probe = RTLIL::SigSpec(RTLIL::State::Sx, sig.size());
|
||||
for (auto &action : cs2->actions)
|
||||
sig.replace(action.first, action.second, &probe);
|
||||
for (int i = 0; i < GetSize(sig); i++)
|
||||
if (full_case_bits.count(sig[i]) && probe[i] != RTLIL::State::Sx)
|
||||
counts[i][probe[i]]++;
|
||||
}
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
if (!full_case_bits.count(sig[i])) continue;
|
||||
for (auto &kv : counts[i])
|
||||
if (kv.second * 2 > n) { result[i] = kv.first; break; }
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate in reverse order to give the first entry the top priority
|
||||
RTLIL::SigSpec initial_val = result;
|
||||
RTLIL::Cell *last_mux_cell = NULL;
|
||||
|
|
|
|||
50
tests/proc/proc_mux_dominant.v
Normal file
50
tests/proc/proc_mux_dominant.v
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Test cases for proc_mux dominant-value optimization.
|
||||
//
|
||||
// When a full_case switch has a majority of arms assigning the same value to a
|
||||
// signal bit, proc_mux uses that dominant value as the starting point instead
|
||||
// of Sx. Arms that produce the dominant value are then skipped (the mux
|
||||
// condition evaluates to "when == else"), avoiding spurious $eq/$mux cells.
|
||||
|
||||
// dominant_explicit: 3 of 4 arms assign the same constants (dominant values).
|
||||
// Expected after proc: one $mux per output word, one $logic_not for the
|
||||
// selector — zero $eq cells, zero $pmux cells.
|
||||
module dominant_explicit(input [1:0] s, output reg [2:0] y, output reg [1:0] z);
|
||||
always @* begin
|
||||
y = 3'b001;
|
||||
z = 2'b00;
|
||||
case (s)
|
||||
2'b00: begin y = 3'b110; z = 2'b11; end // only arm that differs
|
||||
2'b01: begin y = 3'b001; z = 2'b00; end // explicit dominant
|
||||
2'b10: begin y = 3'b001; z = 2'b00; end // explicit dominant
|
||||
2'b11: begin y = 3'b001; z = 2'b00; end // explicit dominant
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
||||
// dominant_wire: dominant value is an input wire (not a constant).
|
||||
// Expected after proc: 1 $logic_not + 1 $mux, no $eq/$pmux.
|
||||
module dominant_wire(input [1:0] s, input [2:0] a, output reg [2:0] y);
|
||||
always @* begin
|
||||
y = a;
|
||||
case (s)
|
||||
2'b00: y = 3'b110; // only arm that differs
|
||||
2'b01: y = a; // explicit dominant
|
||||
2'b10: y = a; // explicit dominant
|
||||
2'b11: y = a; // explicit dominant
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
||||
// no_dominant: all four arms assign distinct values — no majority.
|
||||
// The optimization must NOT fire; behavior must be unchanged.
|
||||
// Expected after proc: $eq cells for each non-zero compare arm, $pmux.
|
||||
module no_dominant(input [1:0] s, input [2:0] a, b, c, d, output reg [2:0] y);
|
||||
always @* begin
|
||||
case (s)
|
||||
2'b00: y = a;
|
||||
2'b01: y = b;
|
||||
2'b10: y = c;
|
||||
2'b11: y = d;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
40
tests/proc/proc_mux_dominant.ys
Normal file
40
tests/proc/proc_mux_dominant.ys
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Test that proc_mux uses a dominant-value pre-scan to avoid generating
|
||||
# unnecessary mux cells when a full_case switch has a majority of arms
|
||||
# assigning the same value.
|
||||
|
||||
# 3 of 4 arms assign identical constants for both outputs.
|
||||
# The optimization should seed the result with the dominant values (3'b001,
|
||||
# 2'b00) so only the one differing arm (2'b00 -> 3'b110, 2'b11) generates
|
||||
# cells. Each output word is a separate SigSnippet, so we expect one
|
||||
# $logic_not + one $mux per word = 2 of each total.
|
||||
read_verilog proc_mux_dominant.v
|
||||
hierarchy -top dominant_explicit
|
||||
proc
|
||||
select -assert-count 2 t:$logic_not
|
||||
select -assert-count 2 t:$mux
|
||||
select -assert-count 0 t:$eq
|
||||
select -assert-count 0 t:$pmux
|
||||
|
||||
# 3 of 4 arms pass through an input wire 'a'. The dominant value is a wire
|
||||
# signal rather than a constant; the optimization must still recognise it.
|
||||
# Only one arm differs (2'b00 -> 3'b110), producing 1 $logic_not + 1 $mux.
|
||||
design -reset
|
||||
read_verilog proc_mux_dominant.v
|
||||
hierarchy -top dominant_wire
|
||||
proc
|
||||
select -assert-count 1 t:$logic_not
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 0 t:$eq
|
||||
select -assert-count 0 t:$pmux
|
||||
|
||||
# All four arms assign distinct values; no majority exists. The optimization
|
||||
# must not fire and the generated netlist must be functionally correct.
|
||||
design -reset
|
||||
read_verilog proc_mux_dominant.v
|
||||
hierarchy -top no_dominant
|
||||
proc
|
||||
# Three explicit non-zero compare arms each produce an $eq; the 2'b00 arm
|
||||
# uses $logic_not (all-zero check); all results are merged into one $pmux.
|
||||
select -assert-count 3 t:$eq
|
||||
select -assert-count 1 t:$logic_not
|
||||
select -assert-count 1 t:$pmux
|
||||
Loading…
Add table
Add a link
Reference in a new issue