Fix spurious FSM COVERIGN on datapath comparisons (#7900) (#7908)

Fixes #7900.
This commit is contained in:
Yogish Sekhar 2026-07-10 14:00:17 +01:00 committed by GitHub
parent 3191d98391
commit 3c7727a8f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 39 deletions

View File

@ -988,21 +988,11 @@ class FsmDetectVisitor final : public VNVisitor {
return assp; return assp;
} }
static AstVarRef* tryExtractVarRef(AstNodeExpr* const exprp) {
AstVarRef* const varp = VN_CAST(AstArraySel::baseFromp(exprp, true), VarRef);
if (!varp) {
exprp->v3warn(COVERIGN,
"Ignoring unsupported: FSM coverage with " << exprp->prettyTypeName());
return nullptr;
}
return varp;
}
static AstNodeAssign* nodeStateVarAssign(AstNode* nodep, AstVarScope*& stateVscp, static AstNodeAssign* nodeStateVarAssign(AstNode* nodep, AstVarScope*& stateVscp,
AstVarScope*& fromVscp) { AstVarScope*& fromVscp) {
AstNodeAssign* const assp = VN_CAST(nodep, NodeAssign); AstNodeAssign* const assp = VN_CAST(nodep, NodeAssign);
if (!assp) return nullptr; if (!assp) return nullptr;
AstVarRef* const lhsp = tryExtractVarRef(assp->lhsp()); AstVarRef* const lhsp = VN_CAST(AstArraySel::baseFromp(assp->lhsp(), true), VarRef);
AstVarRef* const rhsp = VN_CAST(assp->rhsp(), VarRef); AstVarRef* const rhsp = VN_CAST(assp->rhsp(), VarRef);
if (!rhsp || !lhsp) return nullptr; if (!rhsp || !lhsp) return nullptr;
stateVscp = lhsp->varScopep(); stateVscp = lhsp->varScopep();
@ -1016,7 +1006,7 @@ class FsmDetectVisitor final : public VNVisitor {
FsmStateValue& resetValue) { FsmStateValue& resetValue) {
AstNodeAssign* const assp = VN_CAST(nodep, NodeAssign); AstNodeAssign* const assp = VN_CAST(nodep, NodeAssign);
if (!assp) return nullptr; if (!assp) return nullptr;
AstVarRef* const lhsp = tryExtractVarRef(assp->lhsp()); AstVarRef* const lhsp = VN_CAST(AstArraySel::baseFromp(assp->lhsp(), true), VarRef);
AstCond* const rhsp = VN_CAST(assp->rhsp(), Cond); AstCond* const rhsp = VN_CAST(assp->rhsp(), Cond);
if (!rhsp || !lhsp) return nullptr; if (!rhsp || !lhsp) return nullptr;
if (AstVarRef* const elsep = VN_CAST(rhsp->elsep(), VarRef)) { if (AstVarRef* const elsep = VN_CAST(rhsp->elsep(), VarRef)) {
@ -1228,7 +1218,7 @@ class FsmDetectVisitor final : public VNVisitor {
AstVarRef* vrefp = VN_CAST(eqp->lhsp(), VarRef); AstVarRef* vrefp = VN_CAST(eqp->lhsp(), VarRef);
AstNodeExpr* valuep = eqp->rhsp(); AstNodeExpr* valuep = eqp->rhsp();
if (!vrefp) { if (!vrefp) {
vrefp = tryExtractVarRef(eqp->rhsp()); vrefp = VN_CAST(AstArraySel::baseFromp(eqp->rhsp(), true), VarRef);
if (!vrefp) { return false; } if (!vrefp) { return false; }
valuep = eqp->lhsp(); valuep = eqp->lhsp();
} }

View File

@ -1,6 +0,0 @@
%Warning-COVERIGN: t/t_cover_fsm_concat_unsup.v:12:17: Ignoring unsupported: FSM coverage with CONCAT
12 | assign c = ({a, b} == 8'h00);
| ^
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -1,18 +0,0 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
module t (
input logic [6:0] a,
input logic b,
output logic c
);
assign c = ({a, b} == 8'h00);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# DESCRIPTION: Verilator: FSM coverage concat as unsupported operation test # DESCRIPTION: Verilator: FSM coverage ignores unrelated datapath comparisons
# #
# This program is free software; you can redistribute it and/or modify it # 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 # under the terms of either the GNU Lesser General Public License Version 3
@ -11,6 +11,6 @@ import vltest_bootstrap
test.scenarios('vlt') test.scenarios('vlt')
test.lint(fails=True, expect_filename=test.golden_filename, verilator_flags2=['--coverage']) test.lint(verilator_flags2=['--coverage-fsm'])
test.passes() test.passes()

View File

@ -0,0 +1,62 @@
// DESCRIPTION: Verilator: FSM coverage ignores unrelated datapath comparisons
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
module datapath_only #(
parameter logic [15:0] MASK = 16'hff00,
parameter logic [15:0] MATCH = 16'h1200
) (
input logic [6:0] a,
input logic b,
input logic [15:0] data,
output logic concat_hit,
output logic masked_hit
);
assign concat_hit = ({a, b} == 8'h00);
assign masked_hit = (data & MASK) == MATCH;
endmodule
module t #(
parameter logic [15:0] MASK = 16'hff00,
parameter logic [15:0] MATCH = 16'h1200
) (
input logic clk,
input logic rst,
input logic go,
input logic [6:0] a,
input logic b,
input logic [15:0] data,
output logic busy,
output logic hit,
output logic concat_hit,
output logic masked_hit
);
typedef enum logic [1:0] { IDLE, RUN, DONE } state_t;
state_t state;
always_ff @(posedge clk) begin
if (rst) begin
state <= IDLE;
end else begin
case (state)
IDLE: if (go) state <= RUN;
RUN: state <= DONE;
DONE: state <= IDLE;
default: state <= IDLE;
endcase
end
end
assign busy = (state != IDLE);
assign hit = (data & MASK) == MATCH;
datapath_only datapath_only_u (
.a(a),
.b(b),
.data(data),
.concat_hit(concat_hit),
.masked_hit(masked_hit)
);
endmodule