Internals: Defer interface typedefs, and add more tests (#3441 tests)

This commit is contained in:
Wilson Snyder 2025-11-21 19:42:22 -05:00
parent 7e3cab8e5d
commit 6bba9f6c40
16 changed files with 272 additions and 44 deletions

View File

@ -1171,11 +1171,13 @@ class AstRefDType final : public AstNodeDType {
//
// Pre-Width must reference the Typeref, not what it points to, as some child
// types like AstBracketArrayType will disappear and can't lose the handle
//
// @astgen ptr := m_typedefp : Optional[AstTypedef] // Referenced type
// Post-width typedefs are removed and point to type directly
// @astgen ptr := m_refDTypep : Optional[AstNodeDType] // Data type references
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package defined in
string m_name; // Name of an AstTypedef
string m_ifacePortName; // Name of pre-dot interface port identifier
public:
AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_RefDType(fl)
@ -1192,6 +1194,11 @@ public:
this->typeofp(typeofp);
if (AstNodeDType* const dtp = VN_CAST(typeofp, NodeDType)) refDTypep(dtp);
}
class FlagIfaceTypedef {};
AstRefDType(FileLine* fl, FlagIfaceTypedef, const string& ifc, const string& name)
: ASTGEN_SUPER_RefDType(fl)
, m_name{name}
, m_ifacePortName{ifc} {}
ASTGEN_MEMBERS_AstRefDType;
// METHODS
bool sameNode(const AstNode* samep) const override {
@ -1206,6 +1213,7 @@ public:
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
string ifacePortName() const { return m_ifacePortName; }
string prettyDTypeName(bool full) const override {
return subDTypep() ? prettyName(subDTypep()->prettyDTypeName(full)) : prettyName();
}

View File

@ -2318,10 +2318,15 @@ void AstRefDType::dump(std::ostream& str) const {
s_recursing = false;
}
} else {
if (!ifacePortName().empty()) str << " ifcPort=" << ifacePortName();
str << " -> UNLINKED";
}
}
void AstRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstRefDType::dumpJson(std::ostream& str) const {
if (!ifacePortName().empty()) dumpJsonStr(str, "ifcPortName", ifacePortName());
dumpJsonGen(str);
}
void AstRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "ref";

View File

@ -4961,6 +4961,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
const VSymEnt* foundp;
if (nodep->classOrPackagep()) {
foundp = m_statep->getNodeSym(nodep->classOrPackagep())->findIdFlat(nodep->name());
} else if (!nodep->ifacePortName().empty()) { // Interface typedef
nodep->v3error("Unsupported: SystemVerilog 2005 interface typedef");
return;
} else if (m_ds.m_dotPos == DP_FIRST || m_ds.m_dotPos == DP_NONE) {
foundp = m_curSymp->findIdFallback(nodep->name());
} else {

View File

@ -2516,8 +2516,9 @@ type_declaration<nodep>: // ==IEEE: type_declaration
AstNodeDType* const dtp = GRAMMARP->createArray(refp, $4, true);
$$ = GRAMMARP->createTypedef($<fl>5, *$5, $7, dtp, $6); }
// //
| yTYPEDEF idAny/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';'
{ $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); DEL($6); }
| yTYPEDEF idAny/*interface_port*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';'
{ AstRefDType* const refp = new AstRefDType{$<fl>2, AstRefDType::FlagIfaceTypedef{}, *$2, *$4};
$$ = GRAMMARP->createTypedef($<fl>5, *$5, $6, refp, nullptr); }
// // idAny as also allows redeclaring same typedef again
| yTYPEDEF idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>2, *$2, VFwdType::NONE); }
// // IEEE: expanded forward_type to prevent conflict

View File

@ -1,5 +1,5 @@
%Error-UNSUPPORTED: t/t_interface_typedef.v:46:4: Unsupported: SystemVerilog 2005 typedef in this context
46 | typedef ifc_if.struct_t struct_t;
| ^~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_typedef.v:49:11: Unsupported: SystemVerilog 2005 interface typedef
49 | typedef ifc_if.struct_t struct_t;
| ^~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -9,9 +9,11 @@
import vltest_bootstrap
test.scenarios('simulator')
test.scenarios('simulator_st')
test.compile(fails=test.vlt_all, expect_filename=test.golden_filename)
test.compile(verilator_flags2=['--binary'],
fails=test.vlt_all,
expect_filename=test.golden_filename)
if not test.vlt_all:
test.execute()

View File

@ -4,54 +4,58 @@
// any use, without warranty, 2021 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
// verilog_format: on
interface ifc
#(
interface ifc #(
parameter int unsigned WIDTH
) ();
typedef struct {
logic [WIDTH-1:0] data;
} struct_t;
) ();
typedef struct {logic [WIDTH-1:0] data;} struct_t;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
module t ( /*AUTOARG*/
// Inputs
clk
);
input clk;
ifc #(10) i_ifc10();
ifc #(20) i_ifc20();
ifc #(10) i_ifc10 ();
ifc #(20) i_ifc20 ();
sub #(10) u_sub10 (.clk, .ifc_if(i_ifc10));
sub #(20) u_sub20 (.clk, .ifc_if(i_ifc20));
sub #(10) u_sub10 (
.clk,
.ifc_if(i_ifc10)
);
sub #(20) u_sub20 (
.clk,
.ifc_if(i_ifc20)
);
integer cyc = 1;
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
initial begin
#100;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module sub #(
parameter int EXP_WIDTH)
(
parameter int EXP_WIDTH
) (
input logic clk,
ifc ifc_if);
typedef ifc_if.struct_t struct_t;
ifc ifc_if
);
typedef ifc_if.struct_t struct_t;
wire [EXP_WIDTH-1:0] expval = '1;
wire [EXP_WIDTH-1:0] expval = '1;
initial begin
struct_t substruct;
substruct.data = '1;
`checkh($bits(struct_t), EXP_WIDTH);
`checkh(substruct.data, expval);
end
initial begin
struct_t substruct;
#10;
substruct.data = '1;
`checkh($bits(struct_t), EXP_WIDTH);
`checkh(substruct.data, expval);
end
endmodule

View File

@ -0,0 +1,11 @@
%Error: t/t_interface_typedef2.v:37:11: Unsupported: SystemVerilog 2005 interface typedef
37 | typedef p1.stage_t stage1_t;
| ^~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_interface_typedef2.v:40:11: Unsupported: SystemVerilog 2005 interface typedef
40 | typedef p2.stage_t stage2_t;
| ^~
%Error: t/t_interface_typedef2.v:25:11: Unsupported: SystemVerilog 2005 interface typedef
25 | typedef p1.stage_t stage_t;
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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_st')
test.compile(verilator_flags2=['--binary'],
fails=test.vlt_all,
expect_filename=test.golden_filename)
if not test.vlt_all:
test.execute()
test.passes()

View File

@ -0,0 +1,65 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
interface common_intf #(
int ADDR_W,
DATA_W
);
typedef struct packed {
logic [ADDR_W-1:0] cntr_idx;
logic [DATA_W-1:0] cntr_val;
} stage_t;
stage_t bus;
endinterface
module mod1 (
common_intf p1
);
typedef p1.stage_t stage_t; // "imports" type into module
stage_t local_bus;
initial begin
$display("%m mod1: idx bits %0d, val bits %0d", $bits(p1.bus.cntr_idx), $bits(p1.bus.cntr_val));
end
endmodule
module mod2 (
common_intf p1,
p2
);
typedef p1.stage_t stage1_t; // "imports" type into module
stage1_t local_bus1;
typedef p2.stage_t stage2_t; // "imports" type into module
stage2_t local_bus2;
initial begin
$display("%m-1 mod2: idx bits %0d, val bits %0d", $bits(p1.bus.cntr_idx), $bits(p1.bus.cntr_val));
$display("%m-2 mod2: idx bits %0d, val bits %0d", $bits(p2.bus.cntr_idx), $bits(p2.bus.cntr_val));
$display("%m mod2: params p1 ADDR_W %0d DATA_W %0d", p1.ADDR_W, p1.DATA_W);
$display("%m mod2: params p2 ADDR_W %0d DATA_W %0d", p2.ADDR_W, p2.DATA_W);
end
endmodule
module t;
common_intf #(8, 16) i1_2 (); // connects m1 to m2
common_intf #(4, 32) i2_3 (); // connects m2 to m3
mod1 m1 (i1_2);
mod2 m2 (
i1_2,
i2_3
);
mod1 m3 (i2_3);
initial begin
#10;
$finish;
end
endmodule

View File

@ -0,0 +1,5 @@
%Error: t/t_interface_typedef3.v:22:11: Unsupported: SystemVerilog 2005 interface typedef
22 | typedef iface_mp.choice_t tdef_t;
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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_st')
test.compile(verilator_flags2=['--binary'],
fails=test.vlt_all,
expect_filename=test.golden_filename)
if not test.vlt_all:
test.execute()
test.passes()

View File

@ -0,0 +1,32 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface ifc;
typedef logic [3:0] choice_t;
choice_t q;
localparam int ONE = 1;
modport mp(input q);
endinterface
module sub (
interface.mp iface_mp
);
typedef iface_mp.choice_t tdef_t;
tdef_t P;
initial begin
`checkd($bits(tdef_t), 4);
end
endmodule
module t;
ifc u_ifc ();
sub u_sub (u_ifc.mp);
endmodule

View File

@ -0,0 +1,11 @@
%Error: t/t_interface_typedef_bad.v:15:11: Unsupported: SystemVerilog 2005 interface typedef
15 | typedef not_found.choice_t choice1_t;
| ^~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_interface_typedef_bad.v:16:11: Unsupported: SystemVerilog 2005 interface typedef
16 | typedef i.not_found_t choice2_t;
| ^
%Error: t/t_interface_typedef_bad.v:17:11: Unsupported: SystemVerilog 2005 interface typedef
17 | typedef not_ifc.x_t choice3_t;
| ^~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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('linter')
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,23 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
interface ifc;
integer i;
endinterface
module sub (
interface i
);
logic not_ifc;
typedef not_found.choice_t choice1_t; // <--- Error: not found interface port
typedef i.not_found_t choice2_t; // <--- Error: not found typedef
typedef not_ifc.x_t choice3_t; // <--- Error: sub not interface reference
endmodule
module t;
ifc u_ifc ();
sub u_sub (u_ifc);
endmodule