This commit is contained in:
parent
8c11d0d0bd
commit
2736262b98
|
|
@ -1235,30 +1235,29 @@ class ParamProcessor final {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if exprp is a ClassRefDType whose class is the default-parameter clone
|
// Check if exprp's class matches origp's class after deparameterization.
|
||||||
// of origp's template class. This catches the case where an explicit type parameter
|
// Handles both the simple case (user4p link from defaultsResolved) and the
|
||||||
// like Holder#(W#(int)) resolves to the same specialization as the implicit default
|
// nested case where the default's inner class has non-default sub-parameters
|
||||||
// Holder#(), because W#(int) deparameterizes to W_ (the all-default clone of W).
|
// (e.g., uvm_sequence#(uvm_reg_item) where uvm_reg_item != default uvm_sequence_item).
|
||||||
// Uses the user4p link set at line ~1658 when defaultsResolved is true.
|
bool classTypeMatchesDefaultClone(const AstNodeDType* exprp, const AstNodeDType* origp) {
|
||||||
static bool classTypeMatchesDefaultClone(const AstNodeDType* exprp,
|
|
||||||
const AstNodeDType* origp) {
|
|
||||||
exprp = exprp->skipRefp();
|
exprp = exprp->skipRefp();
|
||||||
origp = origp->skipRefp();
|
origp = origp->skipRefp();
|
||||||
const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType);
|
const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType);
|
||||||
const auto* const origClassRefp = VN_CAST(origp, ClassRefDType);
|
const auto* const origClassRefp = VN_CAST(origp, ClassRefDType);
|
||||||
UINFO(9, "classTypeMatchesDefaultClone: exprClassRef="
|
|
||||||
<< exprClassRefp << " origClassRef=" << origClassRefp);
|
|
||||||
if (!exprClassRefp || !origClassRefp) return false;
|
if (!exprClassRefp || !origClassRefp) return false;
|
||||||
|
// Fast path: check user4p link (set when template was deparameterized with defaults)
|
||||||
const AstNodeModule* const defaultClonep
|
const AstNodeModule* const defaultClonep
|
||||||
= VN_CAST(origClassRefp->classp()->user4p(), Class);
|
= VN_CAST(origClassRefp->classp()->user4p(), Class);
|
||||||
const bool result = defaultClonep && defaultClonep == exprClassRefp->classp();
|
if (defaultClonep && defaultClonep == exprClassRefp->classp()) return true;
|
||||||
UINFO(9, " origClass=" << origClassRefp->classp()->prettyNameQ()
|
// Slow path: deparameterize the default type and compare the result.
|
||||||
<< " origClassp=" << cvtToHex(origClassRefp->classp())
|
if (!origClassRefp->classp()->hasGParam()) return false;
|
||||||
<< " user4p=" << (defaultClonep ? cvtToHex(defaultClonep) : "null")
|
// const_cast safe: cloneTree doesn't modify the source
|
||||||
<< " exprClass=" << exprClassRefp->classp()->prettyNameQ()
|
AstClassRefDType* const origClonep = static_cast<AstClassRefDType*>(
|
||||||
<< " exprClassp=" << cvtToHex(exprClassRefp->classp())
|
const_cast<AstClassRefDType*>(origClassRefp)->cloneTree(false));
|
||||||
<< " result=" << result);
|
AstNodeModule* const resolvedModp = classRefDeparam(origClonep, origClassRefp->classp());
|
||||||
return result;
|
const bool match = resolvedModp && VN_CAST(resolvedModp, Class) == exprClassRefp->classp();
|
||||||
|
VL_DO_DANGLING(origClonep->deleteTree(), origClonep);
|
||||||
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool paramConstsEqualAtMaxWidth(AstConst* exprp, AstConst* origp) {
|
static bool paramConstsEqualAtMaxWidth(AstConst* exprp, AstConst* origp) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=["--binary"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
// DESCRIPTION: Verilator: Verify that nested class type parameters with
|
||||||
|
// explicit-equivalent defaults resolve to the same specialization.
|
||||||
|
//
|
||||||
|
// When uvm_reg_sequence#(type BASE = uvm_sequence#(uvm_reg_item)) is
|
||||||
|
// extended with the explicit equivalent default, both must produce the
|
||||||
|
// same specialization so that $cast succeeds between them.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
virtual class uvm_object;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class uvm_factory;
|
||||||
|
uvm_object m_type_names[string];
|
||||||
|
|
||||||
|
function uvm_object create_object_by_name(string name);
|
||||||
|
uvm_object wrapper;
|
||||||
|
if (m_type_names.exists(name)) begin
|
||||||
|
wrapper = m_type_names[name];
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
$display("%%Error: object not found '%s'", name);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
return wrapper;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function void register(uvm_object obj, string name);
|
||||||
|
m_type_names[name] = obj;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
uvm_factory factory;
|
||||||
|
|
||||||
|
class uvm_sequence_item extends uvm_object;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class uvm_reg_item extends uvm_sequence_item;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
virtual class uvm_sequence #(
|
||||||
|
type REQ = uvm_sequence_item,
|
||||||
|
type RSP = REQ
|
||||||
|
) extends uvm_object;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class uvm_reg_sequence #(
|
||||||
|
type BASE = uvm_sequence#(uvm_reg_item)
|
||||||
|
) extends BASE;
|
||||||
|
function new;
|
||||||
|
factory.register(this, "uvm_reg_sequence");
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class uvm_reg_hw_reset_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item));
|
||||||
|
function new;
|
||||||
|
factory.register(this, "uvm_reg_hw_reset_seq");
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
initial begin
|
||||||
|
uvm_reg_hw_reset_seq rsq;
|
||||||
|
|
||||||
|
uvm_reg_sequence seq;
|
||||||
|
uvm_object obj;
|
||||||
|
int cst;
|
||||||
|
string seq_name;
|
||||||
|
|
||||||
|
factory = new;
|
||||||
|
rsq = new;
|
||||||
|
|
||||||
|
seq_name = "uvm_reg_hw_reset_seq";
|
||||||
|
|
||||||
|
obj = factory.create_object_by_name(seq_name);
|
||||||
|
if (obj == null) $stop;
|
||||||
|
|
||||||
|
cst = $cast(seq, obj);
|
||||||
|
/* verilator lint_off WIDTHTRUNC */
|
||||||
|
if (!cst || seq == null) begin
|
||||||
|
$display("%%Error: cast failed");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
/* verilator lint_on WIDTHTRUNC */
|
||||||
|
if (seq != rsq) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue