Fix internal error on covergroup in a specialized parameterized class (#8450) (#8452)

This commit is contained in:
David Harris
2026-09-22 19:00:20 -04:00
committed by GitHub
parent 6eced23e84
commit 525d1fade3
5 changed files with 119 additions and 10 deletions
+1
View File
@@ -63,6 +63,7 @@ Daniel Bates
Danny Oler
Dave Sargeant
David Garau
David Harris
David Horton
David Ledger
David Metz
+15 -10
View File
@@ -880,10 +880,12 @@ class ParamProcessor final {
V3LinkDotIfaceCapture::forEach([&](const V3LinkDotIfaceCapture::CapturedEntry& entry) {
if (!entry.refp) return;
if (entry.cloneCellPath != cloneCP) return;
UASSERT_OBJ(
entry.ownerModp
&& (entry.ownerModp == newModp || entry.ownerModp->name() == srcName),
entry.refp, "clone ledger entry for '" << cloneCP << "' has unexpected owner");
// Owner may also be a class nested in newModp (e.g. a covergroup).
const AstNodeModule* const ownerp = entry.ownerModp;
UASSERT_OBJ(ownerp == newModp || ownerp->name() == srcName
|| ownerp->aboveLoopp() == newModp,
entry.refp,
"clone ledger entry for '" << cloneCP << "' has unexpected owner");
if (entry.cellPath.empty()) return;
AstRefDType* const refp = entry.refp;
@@ -1022,12 +1024,15 @@ class ParamProcessor final {
if (AstRefDType* const clonedRefp = entry.refp->clonep()) {
// Use newname (unique specialized module name) as cloneCellPath.
const string cloneCP = newname;
// A cloned captured ref lives inside srcModp's tree, so its owner
// is srcModp (SV has no nested module definitions).
UASSERT_OBJ(
entry.ownerModp == srcModp, clonedRefp,
"cloned captured RefDType owner is not the specialized module");
AstNodeModule* const clonedOwnerp = newModp;
// Owner is srcModp or a class nested in it (e.g. a covergroup);
// cloneTree() populated clonep() for the nested case.
AstNodeModule* clonedOwnerp = newModp;
if (entry.ownerModp != srcModp) {
clonedOwnerp = entry.ownerModp->clonep();
UASSERT_OBJ(clonedOwnerp, clonedRefp,
"captured RefDType owner was not cloned with the "
"specialized module");
}
const V3LinkDotIfaceCapture::TemplateKey tkey{
entry.ownerModp ? entry.ownerModp->name() : "", entry.refp->name(),
entry.cellPath};
@@ -0,0 +1,2 @@
__vlAnonCG_cg.cp_insn.ecall: 1
__vlAnonCG_cg2.cp_insn.ebreak: 1
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
import coverage_covergroup_common
test.scenarios('vlt_all')
coverage_covergroup_common.run(test)
+85
View File
@@ -0,0 +1,85 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain
// SPDX-FileCopyrightText: 2026 David Harris
// SPDX-License-Identifier: CC0-1.0
interface trace_if #(parameter int ILEN = 32, parameter int XLEN = 32) ();
logic clk;
logic [ILEN-1:0] insn;
endinterface
package cov_pkg;
class TraceData #(parameter int ILEN = 32, parameter int XLEN = 32);
logic [ILEN-1:0] insn;
endclass
class Instr #(parameter int ILEN = 32, parameter int XLEN = 32);
TraceData #(ILEN, XLEN) current;
function new();
current = new();
endfunction
endclass
class CovBase #(parameter int ILEN = 32, parameter int XLEN = 32);
typedef Instr #(ILEN, XLEN) ins_t;
// A virtual interface member is what puts an interface type reference
// inside this class, alongside the covergroup below.
virtual trace_if #(ILEN, XLEN) vif;
covergroup cg with function sample(ins_t ins);
cp_insn: coverpoint ins.current.insn {
bins ecall = {32'h00000073};
}
endgroup
// A second covergroup, so one nested class is preceded by another
covergroup cg2 with function sample(ins_t ins);
cp_insn: coverpoint ins.current.insn {
bins ebreak = {32'h00100073};
}
endgroup
function new(virtual trace_if #(ILEN, XLEN) vif);
this.vif = vif;
cg = new();
cg2 = new();
endfunction
function void do_sample();
ins_t ins = new();
ins.current.insn = 32'h00000073;
cg.sample(ins);
ins.current.insn = 32'h00100073;
cg2.sample(ins);
endfunction
endclass
endpackage
import cov_pkg::*;
class Cov #(parameter int ILEN = 32, parameter int XLEN = 32)
extends CovBase #(ILEN, XLEN);
function new(virtual trace_if #(ILEN, XLEN) vif);
super.new(vif);
endfunction
endclass
module worker(trace_if vif);
// Specialized from parameters read off the interface instance
Cov #(vif.ILEN, vif.XLEN) cov;
initial begin
cov = new(vif);
cov.do_sample();
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module t;
trace_if #(32, 64) vif();
worker worker(vif);
endmodule