Fix interface array assignments (#5270) (#5633) (#5869)

This commit is contained in:
Nick Brereton 2025-03-21 17:00:49 -04:00 committed by GitHub
parent 8c287134d7
commit 27e39d7821
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 251 additions and 1 deletions

View File

@ -195,6 +195,9 @@ private:
void visit(AstVar* nodep) override {
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
&& VN_IS(VN_AS(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
if (VN_AS(VN_AS(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)
->isVirtual())
return;
UINFO(8, " dv-vec-VAR " << nodep << endl);
AstUnpackArrayDType* const arrdtype = VN_AS(nodep->dtypep(), UnpackArrayDType);
AstNode* prevp = nullptr;
@ -241,7 +244,10 @@ private:
const bool isIface
= ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
&& VN_IS(VN_AS(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
IfaceRefDType);
IfaceRefDType)
&& !VN_AS(VN_AS(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
IfaceRefDType)
->isVirtual();
// Make all of the required clones
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
@ -363,6 +369,7 @@ private:
if (const AstUnpackArrayDType* const arrp
= VN_CAST(arrselp->fromp()->dtypep(), UnpackArrayDType)) {
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
if (VN_AS(arrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
// Interface pin attaches to one element of arrayed interface
V3Const::constifyParamsEdit(arrselp->bitp());
const AstConst* const constp = VN_CAST(arrselp->bitp(), Const);
@ -390,6 +397,7 @@ private:
const AstUnpackArrayDType* const pinArrp
= VN_CAST(pinVarp->dtypep(), UnpackArrayDType);
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return;
if (VN_AS(pinArrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
// Arrayed pin/var attaches to arrayed submodule lower port/var, expand it
AstNode* prevp = nullptr;
AstNode* prevPinp = nullptr;
@ -467,6 +475,103 @@ private:
}
}
void visit(AstNodeAssign* nodep) override {
if (AstArraySel* const arrselp = VN_CAST(nodep->rhsp(), ArraySel)) {
// handle single element selection from RHS array
if (const AstUnpackArrayDType* const arrp
= VN_CAST(arrselp->fromp()->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!VN_IS(arrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
if (VN_AS(arrp->subDTypep()->skipRefp(), IfaceRefDType)->isVirtual()) return;
V3Const::constifyParamsEdit(arrselp->bitp());
const AstConst* const constp = VN_CAST(arrselp->bitp(), Const);
if (!constp) {
arrselp->bitp()->v3warn(E_UNSUPPORTED,
"Non-constant index in RHS interface array selection");
return;
}
const string index = AstNode::encodeNumber(constp->toSInt());
const AstVarRef* const varrefp = VN_CAST(arrselp->fromp(), VarRef);
UASSERT_OBJ(varrefp, arrselp, "No interface varref under array");
AstVarXRef* const newp = new AstVarXRef{
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "",
VAccess::READ};
newp->dtypep(arrp->subDTypep());
newp->classOrPackagep(varrefp->classOrPackagep());
arrselp->addNextHere(newp);
VL_DO_DANGLING(arrselp->unlinkFrBack()->deleteTree(), arrselp);
}
} else if (AstSliceSel* const arrslicep = VN_CAST(nodep->rhsp(), SliceSel)) {
if (const AstUnpackArrayDType* const arrp
= VN_CAST(arrslicep->fromp()->dtypep(), UnpackArrayDType)) {
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
if (VN_AS(arrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
arrslicep->v3warn(E_UNSUPPORTED, "Interface slices unsupported");
return;
}
} else {
if (const AstUnpackArrayDType* const lhsarrp
= VN_CAST(nodep->lhsp()->dtypep()->skipRefp(), UnpackArrayDType)) {
if (const AstUnpackArrayDType* const rhsarrp
= VN_CAST(nodep->rhsp()->dtypep()->skipRefp(), UnpackArrayDType)) {
// copy between arrays
if (!VN_IS(lhsarrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
if (!VN_IS(rhsarrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
if (VN_AS(rhsarrp->subDTypep()->skipRefp(), IfaceRefDType)->isVirtual())
return;
if (lhsarrp->elementsConst() != rhsarrp->elementsConst()) {
nodep->v3warn(E_UNSUPPORTED,
"Array size mismatch in interface assignment");
return;
}
for (int i = 0; i < lhsarrp->elementsConst(); ++i) {
const string index = AstNode::encodeNumber(i);
AstNodeExpr* lhsp = nullptr;
if (AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
if (VN_AS(lhsarrp->subDTypep()->skipRefp(), IfaceRefDType)
->isVirtual()) {
AstVarRef* const newvarp = varrefp->cloneTree(false);
AstArraySel* newarrselp = new AstArraySel(
nodep->fileline(), newvarp,
new AstConst(nodep->fileline(),
V3Number(nodep->fileline(), 32, i)));
lhsp = newarrselp;
} else {
AstVarXRef* const newvarrefp = new AstVarXRef{
nodep->fileline(),
varrefp->name() + "__BRA__" + index + "__KET__", "",
VAccess::WRITE};
newvarrefp->dtypep(lhsarrp->subDTypep()->skipRefp());
newvarrefp->classOrPackagep(varrefp->classOrPackagep());
lhsp = newvarrefp;
}
} else if (AstMemberSel* const prevselp
= VN_CAST(nodep->lhsp(), MemberSel)) {
AstMemberSel* membselp = prevselp->cloneTree(false);
AstArraySel* newarrselp = new AstArraySel(
nodep->fileline(), membselp,
new AstConst(nodep->fileline(),
V3Number(nodep->fileline(), 32, i)));
lhsp = newarrselp;
} else {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported lhs node type in array assignment");
return;
}
const AstVarRef* const rhsrefp = VN_CAST(nodep->rhsp(), VarRef);
AstVarXRef* const rhsp = new AstVarXRef{
nodep->fileline(), rhsrefp->name() + "__BRA__" + index + "__KET__", "",
VAccess::READ};
rhsp->dtypep(rhsarrp->subDTypep()->skipRefp());
rhsp->classOrPackagep(rhsrefp->classOrPackagep());
AstAssign* const assignp = new AstAssign(nodep->fileline(), lhsp, rhsp);
nodep->addNextHere(assignp);
}
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
}
}
}
//--------------------
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -0,0 +1,18 @@
#!/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()
test.execute()
test.passes()

View File

@ -0,0 +1,50 @@
// 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 A;
endinterface
typedef virtual A a_t;
typedef a_t a_array_t[6];
class C;
a_array_t vif;
endclass
module tb_top();
A a[6](), b[6]();
C c, d, e;
a_array_t g;
initial begin
static a_t aa = a[0];
b = a;
c = new();
c.vif = a;
d = new();
d.vif[0] = a[0];
d.vif[1] = a[1];
g[0] = a[0];
g = a;
d.vif[0] = g[0];
d.vif = g;
e = new();
for (int i = 0; i < 6; ++i) begin
e.vif[i] = g[i];
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,21 @@
%Error-UNSUPPORTED: t/t_interface_dearray_bad.v:25:13: Array size mismatch in interface assignment
: ... note: In instance 'tb_top'
25 | c.vif = b;
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_dearray_bad.v:30:23: Expecting expression to be constant, but variable isn't const: 'i'
: ... note: In instance 'tb_top'
30 | d.vif[i] = a[i];
| ^
%Error-UNSUPPORTED: t/t_interface_dearray_bad.v:30:23: Non-constant index in RHS interface array selection
: ... note: In instance 'tb_top'
30 | d.vif[i] = a[i];
| ^
%Error-UNSUPPORTED: t/t_interface_dearray_bad.v:34:16: Interface slices unsupported
: ... note: In instance 'tb_top'
34 | e.vif = b[0:5];
| ^
%Error: Internal Error: t/t_interface_dearray_bad.v:25:15: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ./V3Ast__gen_impl.h:#
: ... note: In instance 'tb_top'
25 | c.vif = b;
| ^

View File

@ -0,0 +1,16 @@
#!/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('linter')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,40 @@
// 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 A;
endinterface
typedef virtual A a_t;
typedef a_t a_array_t[6];
class C;
a_array_t vif;
endclass
module tb_top();
A a[6](), b[7]();
C c, d, e;
a_array_t g;
initial begin
c = new();
c.vif = b;
d = new();
for (int i = 0; i < 6; ++i) begin
d.vif[i] = a[i];
end
e = new();
e.vif = b[0:5];
$write("*-* All Finished *-*\n");
$finish;
end
endmodule