Fix arrays of modport interfaces (#2614).

This commit is contained in:
Wilson Snyder 2020-11-08 22:43:32 -05:00
parent cef7708f38
commit fc52fb9093
12 changed files with 238 additions and 36 deletions

View File

@ -28,6 +28,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1]
**** Fix arrays of modport interfaces (#2614). [Thierry Tambe]
* Verilator 4.102 2020-10-15

View File

@ -377,7 +377,10 @@ private:
return;
}
string index = AstNode::encodeNumber(constp->toSInt());
if (VN_IS(arrselp->lhsp(), SliceSel))
arrselp->lhsp()->v3error("Unsupported: interface slices");
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
UASSERT_OBJ(varrefp, arrselp, "No interface varref under array");
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
varrefp->name() + "__BRA__" + index + "__KET__",
"", VAccess::WRITE);

View File

@ -46,6 +46,8 @@
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
// LinkResolve:
// #10: Unlink modports, not needed later except for XML/Lint
//*************************************************************************
// TOP
// {name-of-top-modulename}
@ -1865,20 +1867,12 @@ private:
m_ds.m_dotErr = true;
}
}
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep,
AstModport* modportp, AstRange* rangep) {
// Create iface variable, using duplicate var when under same module scope
string varName
= cellp->name() + "__Vmp__" + modportp->name() + "__Viftop" + cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(),
ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstNodeDType* vdtypep = idtypep;
if (rangep) vdtypep = new AstUnpackArrayDType(fl, VFlagChildDType(), vdtypep, rangep);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), vdtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
AstVar* findIfaceTopVarp(AstNode* nodep, VSymEnt* parentEntp, const string& name) {
string findName = name + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceTopVarp = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName);
return ifaceTopVarp;
}
void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) {
if (refp->user5p() && refp->user5p() != nodep) {
@ -2173,12 +2167,7 @@ private:
VSymEnt* parentEntp
= cellEntp->parentp(); // Container of the var; probably a module or
// generate begin
string findName = nodep->name() + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceRefVarp
= ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceRefVarp, nodep,
"Can't find interface var ref: " << findName);
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, nodep->name());
//
ok = true;
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
@ -2273,32 +2262,32 @@ private:
} else {
AstCell* cellp = VN_CAST(m_ds.m_dotSymp->nodep(), Cell);
UASSERT_OBJ(cellp, nodep, "Modport not referenced from a cell");
AstIface* ifacep = VN_CAST(cellp->modp(), Iface);
// string cellName = m_ds.m_dotText; // Use cellp->name
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
VSymEnt* cellEntp = m_statep->getNodeSym(cellp);
UASSERT_OBJ(cellEntp, nodep, "No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a
// module or generate begin
// We drop __BRA__??__KET__ as cells don't have that naming yet
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, cellp->name());
//
ok = true;
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
AstNode* newp
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
auto* cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef);
AstRange* rangep = nullptr;
if (cellarrayrefp)
rangep = new AstRange(nodep->fileline(),
cellarrayrefp->selp()->cloneTree(true),
cellarrayrefp->selp()->cloneTree(true));
AstVar* varp
= makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp, rangep);
AstNode* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
if (cellarrayrefp) {
// iface[vec].modport became CellArrayRef(iface, lsb)
// Convert back to SelBit(iface, lsb)
UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl);
refp = new AstSelBit(cellarrayrefp->fileline(), refp,
newp = new AstSelBit(cellarrayrefp->fileline(), newp,
cellarrayrefp->selp()->unlinkFrBack());
refp->user3(true); // Don't process again
newp->user3(true); // Don't process again
VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp);
m_ds.m_unlinkedScopep = nullptr;
}
nodep->replaceWith(refp);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) {

View File

@ -502,6 +502,16 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) override {
// LinkDot checked modports, now remove references to them
// Keeping them later caused problems with InstDeArray,
// as it needed to make new modport arrays and such
nodep->modportp(nullptr);
iterateChildren(nodep);
}
// virtual void visit(AstModport* nodep) override { ... }
// We keep Modport's themselves around for XML dump purposes
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

@ -377,6 +377,7 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstModportFTaskRef* nodep) override {
// The modport persists only for xml dump
// The crossrefs are dealt with in V3LinkDot
nodep->ftaskp(nullptr);
iterateChildren(nodep);

View File

@ -0,0 +1,17 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(simulator => 1);
compile(
);
ok(1);
1;

View File

@ -0,0 +1,30 @@
// DESCRIPTION: Verilator: SystemVerilog interface test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2020 by Thierry Tambe.
// SPDX-License-Identifier: CC0-1.0
module t ();
ahb_slave_intf AHB_S[1]();
AHB_MEM uMEM(.S(AHB_S[0].source));
// AHB_MEM V_MEM(.S(AHB_S[0]));
endmodule
module AHB_MEM
(
ahb_slave_intf.source S
);
endmodule
interface ahb_slave_intf
();
logic [31:0] HADDR;
modport source (input HADDR);
endinterface

View File

@ -0,0 +1,17 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(simulator => 1);
compile(
);
ok(1);
1;

View File

@ -0,0 +1,35 @@
// DESCRIPTION: Verilator: SystemVerilog interface test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2020 by Thierry Tambe.
// SPDX-License-Identifier: CC0-1.0
module t ();
sub sub [1] ();
ahb_slave_intf AHB_S[1]();
AHB_MEM uMEM(.S(AHB_S[0]));
// AHB_MEM uMEM(.S(AHB_S[0].source));
endmodule
module sub;
endmodule
module AHB_MEM
(
ahb_slave_intf.source S
);
endmodule
interface ahb_slave_intf
();
logic [31:0] HADDR;
modport source (input HADDR);
endinterface

View File

@ -0,0 +1,9 @@
%Error: t/t_interface_ar3.v:16:36: Unsupported: interface slices
: ... In instance t
16 | sub sub01 [2] (.clk, .infc(iinst[0:1]));
| ^
%Error: Internal Error: t/t_interface_ar3.v:16:36: ../V3Inst.cpp:#: No interface varref under array
: ... In instance t
16 | sub sub01 [2] (.clk, .infc(iinst[0:1]));
| ^
... See the manual and https://verilator.org for more assistance.

View File

@ -0,0 +1,23 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
expect_filename => $Self->{golden_filename},
);
execute(
check_finished => 1,
) if !$Self->{vlt_all};
ok(1);
1;

View File

@ -0,0 +1,66 @@
// DESCRIPTION: Verilator: SystemVerilog interface test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2020 by Thierry Tambe.
// SPDX-License-Identifier: CC0-1.0
module t (
input logic clk,
output logic HRESETn
);
int primsig[3];
ahb_slave_intf iinst[3] (primsig[2:0]);
sub sub01 [2] (.clk, .infc(iinst[0:1]));
sub sub2 (.clk, .infc(iinst[2]));
initial begin
primsig[0] = 30;
primsig[1] = 31;
primsig[2] = 32;
iinst[0].data = 10;
iinst[1].data = 11;
iinst[2].data = 12;
end
int cyc = 0;
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc == 10) begin
if (iinst[0].primsig != 30) $stop;
if (iinst[1].primsig != 31) $stop;
if (iinst[2].primsig != 32) $stop;
if (iinst[0].data != 10) $stop;
if (iinst[1].data != 11) $stop;
if (iinst[2].data != 12) $stop;
if (sub01[0].internal != 10) $stop;
if (sub01[1].internal != 11) $stop;
if (sub2.internal != 12) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
input logic clk,
ahb_slave_intf infc
);
int internal;
always_comb internal = infc.data;
endmodule
interface ahb_slave_intf
(
input int primsig
);
int data;
endinterface