Internals: Modport expression parsing and tests (#2601 partial) (#6848)

This commit is contained in:
Thomas Aldrian 2025-12-21 13:58:21 +00:00 committed by GitHub
parent 32dafdcc61
commit 361ab194ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 238 additions and 12 deletions

View File

@ -233,6 +233,7 @@ Steven Hugg
Szymon Gizler Szymon Gizler
Sören Tempel Sören Tempel
Teng Huang Teng Huang
Thomas Aldrian
Thomas Dybdahl Ahle Thomas Dybdahl Ahle
Tim Hutt Tim Hutt
Tim Snyder Tim Snyder

View File

@ -1203,6 +1203,7 @@ class AstModportVarRef final : public AstNode {
// A input/output/etc variable referenced under a modport // A input/output/etc variable referenced under a modport
// The storage for the variable itself is inside the interface, thus this is a reference // The storage for the variable itself is inside the interface, thus this is a reference
// PARENT: AstModport // PARENT: AstModport
// @astgen op1 := exprp : Optional[AstNodeExpr]
// //
// @astgen ptr := m_varp : Optional[AstVar] // Link to the actual Var // @astgen ptr := m_varp : Optional[AstVar] // Link to the actual Var
string m_name; // Name of the variable referenced string m_name; // Name of the variable referenced
@ -1212,6 +1213,13 @@ public:
: ASTGEN_SUPER_ModportVarRef(fl) : ASTGEN_SUPER_ModportVarRef(fl)
, m_name{name} , m_name{name}
, m_direction{direction} {} , m_direction{direction} {}
AstModportVarRef(FileLine* fl, const string& name, AstNodeExpr* exprp,
VDirection::en direction)
: ASTGEN_SUPER_ModportVarRef(fl)
, m_name{name}
, m_direction{direction} {
this->exprp(exprp);
};
ASTGEN_MEMBERS_AstModportVarRef; ASTGEN_MEMBERS_AstModportVarRef;
void dump(std::ostream& str) const override; void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override; void dumpJson(std::ostream& str) const override;

View File

@ -2529,7 +2529,13 @@ class LinkDotIfaceVisitor final : public VNVisitor {
void visit(AstModportVarRef* nodep) override { // IfaceVisitor:: void visit(AstModportVarRef* nodep) override { // IfaceVisitor::
UINFO(5, " fiv: " << nodep); UINFO(5, " fiv: " << nodep);
iterateChildren(nodep); iterateChildren(nodep);
VSymEnt* const symp = m_curSymp->findIdFallback(nodep->name()); VSymEnt* symp = nullptr;
if (nodep->exprp()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)");
} else {
symp = m_curSymp->findIdFallback(nodep->name());
}
if (!symp) { if (!symp) {
nodep->v3error("Modport item not found: " << nodep->prettyNameQ()); nodep->v3error("Modport item not found: " << nodep->prettyNameQ());
} else if (AstVar* const varp = VN_CAST(symp->nodep(), Var)) { } else if (AstVar* const varp = VN_CAST(symp->nodep(), Var)) {

View File

@ -1679,8 +1679,7 @@ modportPortsDeclList<nodep>:
// We track the type as with the V2k series of defines, then create as each ID is seen. // We track the type as with the V2k series of defines, then create as each ID is seen.
modportPortsDecl<nodep>: modportPortsDecl<nodep>:
// // IEEE: modport_simple_ports_declaration // // IEEE: modport_simple_ports_declaration
port_direction modportSimplePortOrTFPort { $$ = new AstModportVarRef{$<fl>2, *$2, GRAMMARP->m_varIO}; port_direction { GRAMMARP->m_modportImpExpActive = false; } modportSimplePortOrTFPort { $$ = $3; }
GRAMMARP->m_modportImpExpActive = false;}
// // IEEE: modport_clocking_declaration // // IEEE: modport_clocking_declaration
| yCLOCKING idAny/*clocking_identifier*/ { $$ = new AstModportClockingRef{$1, *$2}; } | yCLOCKING idAny/*clocking_identifier*/ { $$ = new AstModportClockingRef{$1, *$2}; }
// // IEEE: yIMPORT modport_tf_port // // IEEE: yIMPORT modport_tf_port
@ -1700,19 +1699,20 @@ modportPortsDecl<nodep>:
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: Modport export with prototype"); DEL($2); } { $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: Modport export with prototype"); DEL($2); }
// Continuations of above after a comma. // Continuations of above after a comma.
// // IEEE: modport_simple_ports_declaration // // IEEE: modport_simple_ports_declaration
| modportSimplePortOrTFPort { $$ = GRAMMARP->m_modportImpExpActive ? | modportSimplePortOrTFPort { $$ = $1; }
;
modportSimplePortOrTFPort<nodep>:// IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
idAny { $$ = GRAMMARP->m_modportImpExpActive ?
static_cast<AstNode*>( static_cast<AstNode*>(
new AstModportFTaskRef{ new AstModportFTaskRef{
$<fl>1, *$1, GRAMMARP->m_modportImpExpLastIsExport} ) : $<fl>1, *$1, GRAMMARP->m_modportImpExpLastIsExport} ) :
static_cast<AstNode*>( static_cast<AstNode*>(
new AstModportVarRef{ new AstModportVarRef{
$<fl>1, *$1, GRAMMARP->m_varIO} ); } $<fl>1, *$1, GRAMMARP->m_varIO} ); }
; | '.' idAny '(' ')' { $$ = new AstModportVarRef{$<fl>2, *$2, GRAMMARP->m_varIO};
BBUNSUP($<fl>4, "Unsupported: Modport empty expression"); }
modportSimplePortOrTFPort<strp>:// IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier | '.' idAny '(' expr ')' { $$ = new AstModportVarRef{$<fl>2, *$2, $4, GRAMMARP->m_varIO}; }
idAny { $$ = $1; }
| '.' idAny '(' ')' { $$ = $2; BBUNSUP($<fl>1, "Unsupported: Modport dotted port name"); }
| '.' idAny '(' expr ')' { $$ = $2; BBUNSUP($<fl>1, "Unsupported: Modport dotted port name"); }
; ;
//************************************************ //************************************************

View File

@ -68,7 +68,7 @@ for s in [
'Unsupported: 4-state numbers in this context', 'Unsupported: 4-state numbers in this context',
'Unsupported: Bind with instance list', 'Unsupported: Bind with instance list',
'Unsupported: Concatenation to form ', 'Unsupported: Concatenation to form ',
'Unsupported: Modport dotted port name', 'Unsupported: Modport empty expression',
'Unsupported: Modport export with prototype', 'Unsupported: Modport export with prototype',
'Unsupported: Modport import with prototype', 'Unsupported: Modport import with prototype',
'Unsupported: Only one PSL clock allowed per assertion', 'Unsupported: Only one PSL clock allowed per assertion',

View File

@ -0,0 +1,39 @@
%Error-UNSUPPORTED: t/t_interface_modport_expr.v:15:22: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
15 | modport mp1(input .a(sig_a), output .b(sig_b));
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_modport_expr.v:15:22: Modport item not found: 'a'
15 | modport mp1(input .a(sig_a), output .b(sig_b));
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error-UNSUPPORTED: t/t_interface_modport_expr.v:15:40: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
15 | modport mp1(input .a(sig_a), output .b(sig_b));
| ^
%Error: t/t_interface_modport_expr.v:15:40: Modport item not found: 'b'
15 | modport mp1(input .a(sig_a), output .b(sig_b));
| ^
%Error-UNSUPPORTED: t/t_interface_modport_expr.v:16:22: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
16 | modport mp2(input .a(sig_c), output .b(sig_d));
| ^
%Error: t/t_interface_modport_expr.v:16:22: Modport item not found: 'a'
16 | modport mp2(input .a(sig_c), output .b(sig_d));
| ^
%Error-UNSUPPORTED: t/t_interface_modport_expr.v:16:40: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
16 | modport mp2(input .a(sig_c), output .b(sig_d));
| ^
%Error: t/t_interface_modport_expr.v:16:40: Modport item not found: 'b'
16 | modport mp2(input .a(sig_c), output .b(sig_d));
| ^
%Error: t/t_interface_modport_expr.v:28:18: Can't find definition of 'a' in dotted variable/method: 'i.a'
28 | assign i.b = i.a;
| ^
%Error: t/t_interface_modport_expr.v:28:12: Can't find definition of 'b' in dotted variable/method: 'i.b'
28 | assign i.b = i.a;
| ^
%Error: t/t_interface_modport_expr.v:22:18: Can't find definition of 'a' in dotted variable/method: 'i.a'
22 | assign i.b = i.a;
| ^
%Error: t/t_interface_modport_expr.v:22:12: Can't find definition of 'b' in dotted variable/method: 'i.b'
22 | assign i.b = i.a;
| ^
%Error: Exiting due to

View File

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

View File

@ -0,0 +1,46 @@
// 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 checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic sig_a, sig_b, sig_c, sig_d;
modport mp1(input .a(sig_a), output .b(sig_b));
modport mp2(input .a(sig_c), output .b(sig_d));
endinterface
module mod1 (
my_if.mp1 i
);
assign i.b = i.a;
endmodule
module mod2 (
my_if.mp2 i
);
assign i.b = i.a;
endmodule
module top ();
my_if myIf ();
assign myIf.sig_a = 1'b1, myIf.sig_c = 1'b1;
mod1 mod1Instance (myIf);
mod2 mod2Instance (myIf);
initial begin
#1;
`checkh(myIf.sig_a, myIf.sig_b);
`checkh(myIf.sig_c, myIf.sig_d);
#1;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,39 @@
%Error-UNSUPPORTED: t/t_interface_modport_expr_partsel.v:16:22: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
16 | modport mp1(input .in(a[7:0]), output .out(b));
| ^~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_modport_expr_partsel.v:16:22: Modport item not found: 'in'
16 | modport mp1(input .in(a[7:0]), output .out(b));
| ^~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error-UNSUPPORTED: t/t_interface_modport_expr_partsel.v:16:42: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
16 | modport mp1(input .in(a[7:0]), output .out(b));
| ^~~
%Error: t/t_interface_modport_expr_partsel.v:16:42: Modport item not found: 'out'
16 | modport mp1(input .in(a[7:0]), output .out(b));
| ^~~
%Error-UNSUPPORTED: t/t_interface_modport_expr_partsel.v:17:22: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
17 | modport mp2(input .in(a[15:8]), output .out(c));
| ^~
%Error: t/t_interface_modport_expr_partsel.v:17:22: Modport item not found: 'in'
17 | modport mp2(input .in(a[15:8]), output .out(c));
| ^~
%Error-UNSUPPORTED: t/t_interface_modport_expr_partsel.v:17:43: Unsupported: Modport expressions (IEEE 1800-2023 25.5.4)
17 | modport mp2(input .in(a[15:8]), output .out(c));
| ^~~
%Error: t/t_interface_modport_expr_partsel.v:17:43: Modport item not found: 'out'
17 | modport mp2(input .in(a[15:8]), output .out(c));
| ^~~
%Error: t/t_interface_modport_expr_partsel.v:29:21: Can't find definition of 'in' in dotted variable/method: 'i.in'
29 | assign i.out = ~i.in;
| ^~
%Error: t/t_interface_modport_expr_partsel.v:29:12: Can't find definition of 'out' in dotted variable/method: 'i.out'
29 | assign i.out = ~i.in;
| ^~~
%Error: t/t_interface_modport_expr_partsel.v:23:20: Can't find definition of 'in' in dotted variable/method: 'i.in'
23 | assign i.out = i.in;
| ^~
%Error: t/t_interface_modport_expr_partsel.v:23:12: Can't find definition of 'out' in dotted variable/method: 'i.out'
23 | assign i.out = i.in;
| ^~~
%Error: Exiting due to

View File

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

View File

@ -0,0 +1,47 @@
// 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 checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic [15:0] a;
logic [7:0] b, c;
modport mp1(input .in(a[7:0]), output .out(b));
modport mp2(input .in(a[15:8]), output .out(c));
endinterface
module mod1 (
my_if.mp1 i
);
assign i.out = i.in;
endmodule
module mod2 (
my_if.mp2 i
);
assign i.out = ~i.in;
endmodule
module top ();
my_if myIf ();
assign myIf.a = 16'habcd;
mod1 mod1Instance (myIf);
mod2 mod2Instance (myIf);
initial begin
#1;
`checkh(myIf.b, myIf.a[7:0]);
`checkh(myIf.c, ~myIf.a[15:8]);
#1;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -53,7 +53,7 @@
{"type":"VAR","name":"value","addr":"(X)","loc":"d,8:12,8:17","dtypep":"(W)","origName":"value","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"isStdRandomizeArg":false,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"integer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"VAR","name":"value","addr":"(X)","loc":"d,8:12,8:17","dtypep":"(W)","origName":"value","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"isStdRandomizeArg":false,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"integer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
{"type":"MODPORT","name":"out_modport","addr":"(MB)","loc":"d,9:12,9:23", {"type":"MODPORT","name":"out_modport","addr":"(MB)","loc":"d,9:12,9:23",
"varsp": [ "varsp": [
{"type":"MODPORTVARREF","name":"value","addr":"(NB)","loc":"d,9:32,9:37","direction":"OUTPUT","varp":"(X)"} {"type":"MODPORTVARREF","name":"value","addr":"(NB)","loc":"d,9:32,9:37","direction":"OUTPUT","varp":"(X)","exprp": []}
]} ]}
]} ]}
],"filesp": [], ],"filesp": [],