Fix overlapping case item expressions (#6825) (#6886)

This commit is contained in:
Luca Colagrande 2026-01-06 21:07:25 +01:00 committed by GitHub
parent 45349990a1
commit 112e1e3752
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 97 additions and 14 deletions

View File

@ -595,6 +595,7 @@ class AssertVisitor final : public VNVisitor {
AstNodeExpr* propp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
AstNodeExpr* itembitp = nullptr;
for (AstNodeExpr* icondp = itemp->condsp(); icondp;
icondp = VN_AS(icondp->nextp(), NodeExpr)) {
AstNodeExpr* onep;
@ -612,17 +613,27 @@ class AssertVisitor final : public VNVisitor {
nodep->exprp()->cloneTreePure(false),
icondp->cloneTreePure(false));
}
// OR together all conditions within the same case item
if (onep) {
if (itembitp) {
itembitp = new AstOr{icondp->fileline(), onep, itembitp};
} else {
itembitp = onep;
}
}
}
if (itembitp) {
if (propp) {
propp = new AstConcat{icondp->fileline(), onep, propp};
propp = new AstConcat{itemp->fileline(), itembitp, propp};
} else {
propp = onep;
propp = itembitp;
}
}
}
// Empty case means no property
if (!propp) propp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
const bool allow_none = has_default || nodep->unique0Pragma();
// The following assertion lools as below.
// The following assertion looks as below.
// if (!$onehot(propp)) begin
// if (propp == '0) begin if (!allow_none) $error("none match"); end
// else $error("multiple match");

View File

@ -244,9 +244,13 @@ class CaseVisitor final : public VNVisitor {
caseItemMap[icondp] = itemp;
foundHit = true;
} else if (!overlappedCondp) {
firstOverlap = i;
overlappedCondp = m_valueItem[i];
m_caseNoOverlapsAllCovered = false;
// Overlapping case item expressions in the
// same case item are legal
if (caseItemMap[m_valueItem[i]] != itemp) {
firstOverlap = i;
overlappedCondp = m_valueItem[i];
m_caseNoOverlapsAllCovered = false;
}
}
}
}

View File

@ -1,17 +1,11 @@
%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:20:21: Case conditions overlap (example pattern 0x6)
20 | 3'b11?, 3'b???: v++;
| ^~~~~~
t/t_case_overlap_bad.v:20:13: ... Location of overlapping condition
20 | 3'b11?, 3'b???: v++;
| ^~~~~~
... For warning description see https://verilator.org/warn/CASEOVERLAP?v=latest
... Use "/* verilator lint_off CASEOVERLAP */" and lint_on around source to disable this message.
%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:25:13: Case conditions overlap
25 | 3'b001, 3'b000: $stop;
| ^~~~~~
t/t_case_overlap_bad.v:24:13: ... Location of overlapping condition
24 | 3'b00?: $stop;
| ^~~~~~
... For warning description see https://verilator.org/warn/CASEOVERLAP?v=latest
... Use "/* verilator lint_off CASEOVERLAP */" and lint_on around source to disable this message.
%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:30:13: Case conditions overlap (example pattern 0x7)
30 | 3'b11?: $stop;
| ^~~~~~

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2026 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,56 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Luca Colagrande.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
localparam logic [1:0] INST1 = 2'b0?;
localparam logic [1:0] INST2 = 2'b0?;
localparam logic [1:0] INST3 = 2'b1?;
logic [1:0] in, out;
always_comb begin
unique casez (in)
INST1, INST2: begin
if (in == 2'b00) out = 2'b01;
else out = 2'b00;
end
INST3: begin
out = 2'b10;
end
default: begin
out = 2'b11;
end
endcase
end
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] in=%x out=%x\n", $time, in, out);
`endif
if (in == 0) begin
if (out != 2'b01) $stop;
end
else if (in == 1) begin
if (out != 2'b00) $stop;
end
else if (in == 2) begin
if (out != 2'b10) $stop;
end
else if (in == 3) begin
if (out != 2'b10) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
in <= in + 1;
end
endmodule