Merge 3301c7c699 into a0b89dde8e
This commit is contained in:
commit
8d4f3d747c
|
|
@ -585,11 +585,7 @@ public:
|
|||
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
||||
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
|
||||
}
|
||||
bool similarDTypeNode(const AstNodeDType* samep) const override {
|
||||
// Doesn't need to compare m_classOrPackagep
|
||||
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
||||
return m_classp == asamep->m_classp;
|
||||
}
|
||||
bool similarDTypeNode(const AstNodeDType* samep) const override;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
|
|
|
|||
|
|
@ -1893,6 +1893,21 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
|||
}
|
||||
string AstClassRefDType::prettyDTypeName(bool) const { return "class{}"s + prettyName(); }
|
||||
string AstClassRefDType::name() const { return classp() ? classp()->name() : "<unlinked>"; }
|
||||
bool AstClassRefDType::similarDTypeNode(const AstNodeDType* samep) const {
|
||||
// Doesn't need to compare m_classOrPackagep
|
||||
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
||||
if (m_classp != asamep->m_classp) return false;
|
||||
// Also compare type parameters - C#(int) != C#(string)
|
||||
const AstPin* lp = paramsp();
|
||||
const AstPin* rp = asamep->paramsp();
|
||||
while (lp && rp) {
|
||||
if (!lp->exprp() != !rp->exprp()) return false;
|
||||
if (lp->exprp() && !lp->exprp()->sameTree(rp->exprp())) return false;
|
||||
lp = VN_CAST(lp->nextp(), Pin);
|
||||
rp = VN_CAST(rp->nextp(), Pin);
|
||||
}
|
||||
return !lp && !rp;
|
||||
}
|
||||
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " ["s + this->type().ascii() + "]";
|
||||
|
|
|
|||
|
|
@ -5593,6 +5593,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
iterate(cpackagep);
|
||||
return;
|
||||
}
|
||||
// Also defer if target is a typedef to a parameterized class (#5977)
|
||||
if (m_statep->forPrimary() && isParamedClassRef(cpackagerefp)) {
|
||||
iterate(cpackagep);
|
||||
return;
|
||||
}
|
||||
if (!cpackagerefp->classOrPackageSkipp()) {
|
||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
||||
m_ds.m_dotSymp, cpackagerefp, true, false, "class/package reference");
|
||||
|
|
|
|||
102
src/V3Param.cpp
102
src/V3Param.cpp
|
|
@ -948,6 +948,39 @@ class ParamProcessor final {
|
|||
if (!parseRefp) return;
|
||||
|
||||
const AstClass* lhsClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class);
|
||||
|
||||
// If the ClassOrPackageRef points to a type parameter (ParamTypeDType), we need
|
||||
// to check if the parameter's value contains a parameterized class that needs
|
||||
// specialization. This handles patterns like:
|
||||
// interface outer #(parameter type C = class_with_type_param#(T));
|
||||
// inner #(.P(C::typedef_name)) i(); // C is a type parameter
|
||||
// endinterface
|
||||
AstParamTypeDType* const paramTypep
|
||||
= VN_CAST(classRefp->classOrPackageNodep(), ParamTypeDType);
|
||||
if (paramTypep) {
|
||||
// Traverse through the type parameter to find if there's a ClassRefDType
|
||||
// with parameters that needs specialization
|
||||
AstNodeDType* const dtypep = paramTypep->subDTypep();
|
||||
AstClassRefDType* const classRefDTypep
|
||||
= dtypep ? VN_CAST(dtypep->skipRefp(), ClassRefDType) : nullptr;
|
||||
if (classRefDTypep) {
|
||||
AstClass* const srcClassp = classRefDTypep->classp();
|
||||
if (srcClassp && srcClassp->hasGParam() && classRefDTypep->paramsp()) {
|
||||
// The type parameter's value is a parameterized class - specialize it
|
||||
if (lhsClassp == srcClassp || !lhsClassp) {
|
||||
UINFO(9, "resolveDotToTypedef: specializing type param class "
|
||||
<< srcClassp->name() << endl);
|
||||
classRefDeparam(classRefDTypep, srcClassp);
|
||||
lhsClassp = classRefDTypep->classp();
|
||||
} else {
|
||||
UINFO(9, "resolveDotToTypedef: type param class "
|
||||
<< srcClassp->name()
|
||||
<< " already specialized to " << lhsClassp->name() << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classRefp->paramsp()) {
|
||||
// ClassOrPackageRef has parameters - may need to specialize the class
|
||||
AstClass* const srcClassp = VN_CAST(classRefp->classOrPackageNodep(), Class);
|
||||
|
|
@ -957,6 +990,10 @@ class ParamProcessor final {
|
|||
UINFO(9, "resolveDotToTypedef: specializing " << srcClassp->name() << endl);
|
||||
classRefDeparam(classRefp, srcClassp);
|
||||
lhsClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class);
|
||||
} else {
|
||||
UINFO(9, "resolveDotToTypedef: class " << srcClassp->name()
|
||||
<< " already specialized to "
|
||||
<< lhsClassp->name() << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -972,10 +1009,65 @@ class ParamProcessor final {
|
|||
}
|
||||
}
|
||||
|
||||
// Resolve a deferred RefDType referencing a typedef inside a parameterized class (#5461).
|
||||
// When a formal parameter's type is `cls1#()::bool_t`, the RefDType for `bool_t` is
|
||||
// left unresolved during linkDotPrimary. We resolve it here by specializing the class
|
||||
// and looking up the typedef in the specialized class.
|
||||
void resolveParamClassRefDType(AstNodeDType* dtypep) {
|
||||
AstRefDType* const refp = dtypep ? VN_CAST(dtypep, RefDType) : nullptr;
|
||||
if (!refp) return;
|
||||
if (refp->typedefp() || refp->refDTypep()) return; // Already resolved
|
||||
|
||||
AstClassOrPackageRef* const classRefp
|
||||
= VN_CAST(refp->classOrPackageOpp(), ClassOrPackageRef);
|
||||
if (!classRefp) return;
|
||||
|
||||
AstClass* srcClassp = VN_CAST(classRefp->classOrPackageNodep(), Class);
|
||||
if (srcClassp && srcClassp->hasGParam()) {
|
||||
// Direct class reference with parameters on the ClassOrPackageRef
|
||||
// (classRefDeparam also resolves the RefDType via its backp() check
|
||||
// when the ClassOrPackageRef is a child of RefDType)
|
||||
classRefDeparam(classRefp, srcClassp);
|
||||
return;
|
||||
}
|
||||
|
||||
// ClassOrPackageRef targets a typedef to a parameterized class (e.g.,
|
||||
// typedef cls#(N) alias; typedef alias::member_t m_t;).
|
||||
// Follow the typedef chain to find the ClassRefDType with the actual class.
|
||||
AstNode* targetp = classRefp->classOrPackageNodep();
|
||||
while (const AstTypedef* const tdefp = VN_CAST(targetp, Typedef))
|
||||
targetp = tdefp->subDTypep();
|
||||
if (AstNodeDType* const dtargetp = VN_CAST(targetp, NodeDType))
|
||||
targetp = dtargetp->skipRefOrNullp();
|
||||
if (!targetp) return;
|
||||
AstClassRefDType* const classRefDTypep = VN_CAST(targetp, ClassRefDType);
|
||||
if (!classRefDTypep) return;
|
||||
srcClassp = classRefDTypep->classp();
|
||||
if (!srcClassp) return;
|
||||
|
||||
AstClass* newClassp = srcClassp;
|
||||
if (srcClassp->hasGParam()) {
|
||||
// Specialize using the ClassRefDType (which has the actual parameters)
|
||||
classRefDeparam(classRefDTypep, srcClassp);
|
||||
newClassp = classRefDTypep->classp();
|
||||
}
|
||||
// else: class already specialized, use it directly
|
||||
|
||||
// Look up the member typedef in the specialized class
|
||||
AstTypedef* const typedefp
|
||||
= VN_CAST(m_memberMap.findMember(newClassp, refp->name()), Typedef);
|
||||
if (typedefp) {
|
||||
refp->typedefp(typedefp);
|
||||
refp->classOrPackagep(newClassp);
|
||||
}
|
||||
}
|
||||
|
||||
void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer,
|
||||
bool& any_overridesr) {
|
||||
if (!pinp->exprp()) return; // No-connect
|
||||
if (AstVar* const modvarp = pinp->modVarp()) {
|
||||
// Resolve deferred formal param type referencing parameterized class typedef (#5461)
|
||||
resolveParamClassRefDType(modvarp->subDTypep());
|
||||
if (!modvarp->isGParam()) {
|
||||
pinp->v3fatalSrc("Attempted parameter setting of non-parameter: Param "
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
|
|
@ -1034,6 +1126,16 @@ class ParamProcessor final {
|
|||
// Handle DOT with ParseRef RHS (e.g., p_class#(8)::p_type)
|
||||
// by this point ClassOrPackageRef should be updated to point to the specialized class.
|
||||
resolveDotToTypedef(pinp->exprp());
|
||||
// Resolve deferred formal param type referencing parameterized class typedef (#5461)
|
||||
resolveParamClassRefDType(modvarp->subDTypep());
|
||||
// Also resolve deferred RefDType inside the pin expression's typedef chain.
|
||||
// Handles: typedef cls#(N) alias; typedef alias::member_t m_t; mod#(.T(m_t))
|
||||
// where alias::member_t was deferred during linkDotPrimary (#5977).
|
||||
if (const AstRefDType* const pinRefp = VN_CAST(pinp->exprp(), RefDType)) {
|
||||
if (const AstTypedef* const tdefp = pinRefp->typedefp()) {
|
||||
resolveParamClassRefDType(tdefp->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeDType* rawTypep = VN_CAST(pinp->exprp(), NodeDType);
|
||||
if (rawTypep) V3Width::widthParamsEdit(rawTypep);
|
||||
|
|
|
|||
|
|
@ -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,61 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Leela Pakanati
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test for issue #5461: Class parameter type using cls#()::typedef
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Basic parameterized class with a typedef
|
||||
class cls1 #(bit PARAM = 0);
|
||||
typedef bit bool_t;
|
||||
typedef logic [7:0] byte_t;
|
||||
endclass
|
||||
|
||||
// Class whose parameter TYPE is a typedef from a parameterized class (default params)
|
||||
class cls2 #(cls1#()::bool_t PARAM = 1);
|
||||
function int get_param();
|
||||
return int'(PARAM);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Class using non-default params for the referenced class
|
||||
class cls3 #(cls1#(1)::bool_t PARAM = 0);
|
||||
function int get_param();
|
||||
return int'(PARAM);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Class using a wider typedef from the parameterized class
|
||||
class cls4 #(cls1#()::byte_t PARAM = 8'hAB);
|
||||
function int get_param();
|
||||
return int'(PARAM);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
automatic cls2#(1) obj2 = new;
|
||||
automatic cls3#(1) obj3 = new;
|
||||
automatic cls4#(8'hCD) obj4 = new;
|
||||
// Default param
|
||||
automatic cls2 obj2d = new;
|
||||
|
||||
`checkd(obj2.get_param(), 1);
|
||||
`checkd(obj3.get_param(), 1);
|
||||
`checkd(obj4.get_param(), 'hCD);
|
||||
`checkd(obj2d.get_param(), 1);
|
||||
|
||||
`checkd($bits(cls1#()::bool_t), 1);
|
||||
`checkd($bits(cls1#(1)::bool_t), 1);
|
||||
`checkd($bits(cls1#()::byte_t), 8);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/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.top_filename = "t/t_class_param_typedef7.v"
|
||||
|
||||
test.compile(verilator_flags2=['--binary', '-fno-inline'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -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,45 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Leela Pakanati
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test for issue #5977: Typedef of parameterized class for member access
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
package pkg;
|
||||
class cls_l0 #(parameter AW = 32);
|
||||
logic [AW-1:0] addr;
|
||||
function new();
|
||||
addr = '0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class cls_l1 #(parameter int AW = 32);
|
||||
typedef cls_l0 #(.AW(AW)) beat_t;
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
// Typedef of parameterized class, then access member typedef via ::
|
||||
typedef pkg::cls_l1 #(.AW(64)) drv64_t;
|
||||
typedef pkg::cls_l1 #(.AW(128)) drv128_t;
|
||||
|
||||
initial begin
|
||||
// Access class-type typedef member through module-level typedef
|
||||
automatic drv64_t::beat_t item1 = new;
|
||||
automatic drv128_t::beat_t item2 = new;
|
||||
item1.addr = 64'hDEAD_BEEF_CAFE_BABE;
|
||||
|
||||
`checkd(item1.addr, 64'hDEAD_BEEF_CAFE_BABE);
|
||||
`checkd($bits(item1.addr), 64);
|
||||
`checkd($bits(item2.addr), 128);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/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.top_filename = "t/t_class_param_typedef8.v"
|
||||
|
||||
test.compile(verilator_flags2=['--binary', '-fno-inline'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -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,87 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Leela Pakanati
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test that parameterized class typedefs work as interface type parameters
|
||||
// when the class itself has type parameters.
|
||||
// See issue #7000
|
||||
|
||||
// Class with single type parameter
|
||||
class C #(parameter type T = logic);
|
||||
typedef struct packed { T data; } td_t;
|
||||
endclass
|
||||
|
||||
// Class with multiple type parameters and multiple typedefs
|
||||
class multi_param #(parameter type ADDR_T = logic, parameter type DATA_T = logic);
|
||||
typedef struct packed { ADDR_T addr; } addr_td_t;
|
||||
typedef struct packed { DATA_T data; } data_td_t;
|
||||
endclass
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Leaf interface: holds a value of parameterized type
|
||||
interface l0 #(type P = logic);
|
||||
P p;
|
||||
endinterface
|
||||
|
||||
// 1-level nesting: wraps l0 with a class typedef parameter
|
||||
interface l1 #(parameter type X = C#(logic));
|
||||
l0 #(.P(X::td_t)) sub();
|
||||
endinterface
|
||||
|
||||
// 2-level nesting: forwards type param through l1 to l0
|
||||
interface l2 #(parameter type X = C#(logic));
|
||||
l1 #(.X(X)) sub();
|
||||
endinterface
|
||||
|
||||
// Multi-param leaf: holds two values of different parameterized types
|
||||
interface multi_l0 #(type P = logic, type Q = logic);
|
||||
P p;
|
||||
Q q;
|
||||
endinterface
|
||||
|
||||
// Multi-param nesting: accesses different typedefs from same class
|
||||
interface multi_l1 #(
|
||||
parameter type CFG = multi_param#(logic, logic)
|
||||
);
|
||||
multi_l0 #(.P(CFG::addr_td_t), .Q(CFG::data_td_t)) sub();
|
||||
endinterface
|
||||
|
||||
module t;
|
||||
// Test 1-level nesting with different parameterizations
|
||||
l1 #(.X(C#(logic[7:0]))) l1_i1();
|
||||
l1 #(.X(C#(logic[15:0]))) l1_i2();
|
||||
// Test default type parameter (C#(logic) -> td_t is struct packed { logic data; })
|
||||
l1 l1_default();
|
||||
|
||||
// Test 2-level nesting - type parameter passed through multiple levels
|
||||
l2 #(.X(C#(logic[31:0]))) l2_i();
|
||||
|
||||
// Test multiple type params - different parameterizations accessing multiple typedefs
|
||||
multi_l1 #(.CFG(multi_param#(logic[7:0], logic[31:0]))) ml1_i1();
|
||||
multi_l1 #(.CFG(multi_param#(logic[15:0], logic[63:0]))) ml1_i2();
|
||||
|
||||
initial begin
|
||||
// 1-level nesting
|
||||
`checkd($bits(l1_i1.sub.p), 8);
|
||||
`checkd($bits(l1_i2.sub.p), 16);
|
||||
`checkd($bits(l1_default.sub.p), 1); // default C#(logic) -> 1-bit
|
||||
|
||||
// 2-level nesting
|
||||
`checkd($bits(l2_i.sub.sub.p), 32);
|
||||
|
||||
// Multiple type params passed to sub-interface - two different typedefs
|
||||
`checkd($bits(ml1_i1.sub.p), 8); // addr_td_t from ADDR_T=logic[7:0]
|
||||
`checkd($bits(ml1_i1.sub.q), 32); // data_td_t from DATA_T=logic[31:0]
|
||||
`checkd($bits(ml1_i2.sub.p), 16); // addr_td_t from ADDR_T=logic[15:0]
|
||||
`checkd($bits(ml1_i2.sub.q), 64); // data_td_t from DATA_T=logic[63:0]
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/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.top_filename = "t/t_iface_param_class_type_param.v"
|
||||
|
||||
test.compile(verilator_flags2=['--binary', '-fno-inline'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
Loading…
Reference in New Issue