Fix virtual interface array typedef expressions (#6057).
This commit is contained in:
parent
593da4e38f
commit
ed46878f7b
1
Changes
1
Changes
|
|
@ -51,6 +51,7 @@ Verilator 5.037 devel
|
||||||
* Fix GCC 10 read-only linker error (#6040). [Todd Strader]
|
* Fix GCC 10 read-only linker error (#6040). [Todd Strader]
|
||||||
* Fix WIDTHCONCAT on packed pattern assignment (#6045). [Dan Petrisko]
|
* Fix WIDTHCONCAT on packed pattern assignment (#6045). [Dan Petrisko]
|
||||||
* Fix V3OrderParallel scoring contraction hang (#6052). [Bartłomiej Chmiel, Antmicro Ltd.]
|
* Fix V3OrderParallel scoring contraction hang (#6052). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Fix virtual interface array typedef expressions (#6057).
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.036 2025-04-27
|
Verilator 5.036 2025-04-27
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,11 @@ class InstVisitor final : public VNVisitor {
|
||||||
m_cellp->addNextHere(assp);
|
m_cellp->addNextHere(assp);
|
||||||
if (debug() >= 9) assp->dumpTree("- _new: ");
|
if (debug() >= 9) assp->dumpTree("- _new: ");
|
||||||
} else if (nodep->modVarp()->isIfaceRef()
|
} else if (nodep->modVarp()->isIfaceRef()
|
||||||
|| (VN_IS(nodep->modVarp()->subDTypep(), UnpackArrayDType)
|
|| (VN_IS(nodep->modVarp()->dtypep()->skipRefp(), UnpackArrayDType)
|
||||||
&& VN_IS(
|
&& VN_IS(VN_AS(nodep->modVarp()->dtypep()->skipRefp(), UnpackArrayDType)
|
||||||
VN_AS(nodep->modVarp()->subDTypep(), UnpackArrayDType)->subDTypep(),
|
->subDTypep()
|
||||||
IfaceRefDType))) {
|
->skipRefp(),
|
||||||
|
IfaceRefDType))) {
|
||||||
// Create an AstAssignVarScope for Vars to Cells so we can
|
// Create an AstAssignVarScope for Vars to Cells so we can
|
||||||
// link with their scope later
|
// link with their scope later
|
||||||
AstNodeExpr* const lhsp = new AstVarXRef{exprp->fileline(), nodep->modVarp(),
|
AstNodeExpr* const lhsp = new AstVarXRef{exprp->fileline(), nodep->modVarp(),
|
||||||
|
|
@ -133,7 +134,7 @@ private:
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstVar* nodep) override {
|
void visit(AstVar* nodep) override {
|
||||||
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
if (VN_IS(nodep->dtypep()->skipRefp(), IfaceRefDType)) {
|
||||||
UINFO(8, " dm-1-VAR " << nodep);
|
UINFO(8, " dm-1-VAR " << nodep);
|
||||||
insert(nodep);
|
insert(nodep);
|
||||||
}
|
}
|
||||||
|
|
@ -185,20 +186,22 @@ private:
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstVar* nodep) override {
|
void visit(AstVar* nodep) override {
|
||||||
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
|
AstNode* const dtp = nodep->dtypep()->skipRefp();
|
||||||
&& VN_IS(VN_AS(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
if (VN_IS(dtp, UnpackArrayDType)
|
||||||
if (VN_AS(VN_AS(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)
|
&& VN_IS(VN_AS(dtp, UnpackArrayDType)->subDTypep()->skipRefp(), IfaceRefDType)) {
|
||||||
|
if (VN_AS(VN_AS(dtp, UnpackArrayDType)->subDTypep()->skipRefp(), IfaceRefDType)
|
||||||
->isVirtual())
|
->isVirtual())
|
||||||
return;
|
return;
|
||||||
UINFO(8, " dv-vec-VAR " << nodep);
|
UINFO(8, " dv-vec-VAR " << nodep);
|
||||||
AstUnpackArrayDType* const arrdtype = VN_AS(nodep->dtypep(), UnpackArrayDType);
|
AstUnpackArrayDType* const arrdtype = VN_AS(dtp, UnpackArrayDType);
|
||||||
AstNode* prevp = nullptr;
|
AstNode* prevp = nullptr;
|
||||||
for (int i = arrdtype->lo(); i <= arrdtype->hi(); ++i) {
|
for (int i = arrdtype->lo(); i <= arrdtype->hi(); ++i) {
|
||||||
const string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
const string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||||
UINFO(8, "VAR name insert " << varNewName << " " << nodep);
|
UINFO(8, "VAR name insert " << varNewName << " " << nodep);
|
||||||
if (!m_deModVars.find(varNewName)) {
|
if (!m_deModVars.find(varNewName)) {
|
||||||
AstIfaceRefDType* const ifaceRefp
|
AstIfaceRefDType* const ifaceRefp
|
||||||
= VN_AS(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
|
= VN_AS(arrdtype->subDTypep()->skipRefp(), IfaceRefDType)
|
||||||
|
->cloneTree(false);
|
||||||
arrdtype->addNextHere(ifaceRefp);
|
arrdtype->addNextHere(ifaceRefp);
|
||||||
ifaceRefp->cellp(nullptr);
|
ifaceRefp->cellp(nullptr);
|
||||||
|
|
||||||
|
|
@ -233,11 +236,13 @@ private:
|
||||||
m_cellRangep = nodep->rangep();
|
m_cellRangep = nodep->rangep();
|
||||||
|
|
||||||
AstVar* const ifaceVarp = VN_CAST(nodep->nextp(), Var);
|
AstVar* const ifaceVarp = VN_CAST(nodep->nextp(), Var);
|
||||||
|
AstNodeDType* const ifaceVarDtp
|
||||||
|
= ifaceVarp ? ifaceVarp->dtypep()->skipRefp() : nullptr;
|
||||||
const bool isIface
|
const bool isIface
|
||||||
= ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
|
= ifaceVarp && VN_IS(ifaceVarDtp, UnpackArrayDType)
|
||||||
&& VN_IS(VN_AS(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
|
&& VN_IS(VN_AS(ifaceVarDtp, UnpackArrayDType)->subDTypep()->skipRefp(),
|
||||||
IfaceRefDType)
|
IfaceRefDType)
|
||||||
&& !VN_AS(VN_AS(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
|
&& !VN_AS(VN_AS(ifaceVarDtp, UnpackArrayDType)->subDTypep()->skipRefp(),
|
||||||
IfaceRefDType)
|
IfaceRefDType)
|
||||||
->isVirtual();
|
->isVirtual();
|
||||||
|
|
||||||
|
|
@ -261,10 +266,9 @@ private:
|
||||||
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
||||||
// within the same parent module as the cell
|
// within the same parent module as the cell
|
||||||
if (isIface) {
|
if (isIface) {
|
||||||
AstUnpackArrayDType* const arrdtype
|
AstUnpackArrayDType* const arrdtype = VN_AS(ifaceVarDtp, UnpackArrayDType);
|
||||||
= VN_AS(ifaceVarp->dtypep(), UnpackArrayDType);
|
|
||||||
AstIfaceRefDType* const origIfaceRefp
|
AstIfaceRefDType* const origIfaceRefp
|
||||||
= VN_AS(arrdtype->subDTypep(), IfaceRefDType);
|
= VN_AS(arrdtype->subDTypep()->skipRefp(), IfaceRefDType);
|
||||||
origIfaceRefp->cellp(nullptr);
|
origIfaceRefp->cellp(nullptr);
|
||||||
AstVar* const varNewp = ifaceVarp->cloneTree(false);
|
AstVar* const varNewp = ifaceVarp->cloneTree(false);
|
||||||
AstIfaceRefDType* const ifaceRefp = origIfaceRefp->cloneTree(false);
|
AstIfaceRefDType* const ifaceRefp = origIfaceRefp->cloneTree(false);
|
||||||
|
|
@ -306,14 +310,14 @@ private:
|
||||||
void visit(AstPin* nodep) override {
|
void visit(AstPin* nodep) override {
|
||||||
// Any non-direct pins need reconnection with a part-select
|
// Any non-direct pins need reconnection with a part-select
|
||||||
if (!nodep->exprp()) return; // No-connect
|
if (!nodep->exprp()) return; // No-connect
|
||||||
|
const AstNodeDType* expDtp = nodep->exprp()->dtypep()->skipRefp();
|
||||||
if (m_cellRangep) {
|
if (m_cellRangep) {
|
||||||
UINFO(4, " PIN " << nodep);
|
UINFO(4, " PIN " << nodep);
|
||||||
const int modwidth = nodep->modVarp()->width();
|
const int modwidth = nodep->modVarp()->width();
|
||||||
const int expwidth = nodep->exprp()->width();
|
const int expwidth = nodep->exprp()->width();
|
||||||
const std::pair<uint32_t, uint32_t> pinDim
|
const std::pair<uint32_t, uint32_t> pinDim
|
||||||
= nodep->modVarp()->dtypep()->dimensions(false);
|
= nodep->modVarp()->dtypep()->skipRefp()->dimensions(false);
|
||||||
const std::pair<uint32_t, uint32_t> expDim
|
const std::pair<uint32_t, uint32_t> expDim = expDtp->dimensions(false);
|
||||||
= nodep->exprp()->dtypep()->dimensions(false);
|
|
||||||
UINFO(4, " PINVAR " << nodep->modVarp());
|
UINFO(4, " PINVAR " << nodep->modVarp());
|
||||||
UINFO(4, " EXP " << nodep->exprp());
|
UINFO(4, " EXP " << nodep->exprp());
|
||||||
UINFO(4, " expwidth=" << expwidth << " modwidth=" << modwidth
|
UINFO(4, " expwidth=" << expwidth << " modwidth=" << modwidth
|
||||||
|
|
@ -321,8 +325,7 @@ private:
|
||||||
<< " pinDim(p,u)=" << pinDim.first << "," << pinDim.second);
|
<< " pinDim(p,u)=" << pinDim.first << "," << pinDim.second);
|
||||||
if (expDim.second == pinDim.second + 1) {
|
if (expDim.second == pinDim.second + 1) {
|
||||||
// Connection to array, where array dimensions match the instant dimension
|
// Connection to array, where array dimensions match the instant dimension
|
||||||
const AstRange* const rangep
|
const AstRange* const rangep = VN_AS(expDtp, UnpackArrayDType)->rangep();
|
||||||
= VN_AS(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep();
|
|
||||||
const int arraySelNum = rangep->ascending()
|
const int arraySelNum = rangep->ascending()
|
||||||
? (rangep->elementsConst() - 1 - m_instSelNum)
|
? (rangep->elementsConst() - 1 - m_instSelNum)
|
||||||
: m_instSelNum;
|
: m_instSelNum;
|
||||||
|
|
@ -358,9 +361,9 @@ private:
|
||||||
} // end expanding ranged cell
|
} // end expanding ranged cell
|
||||||
else if (AstArraySel* const arrselp = VN_CAST(nodep->exprp(), ArraySel)) {
|
else if (AstArraySel* const arrselp = VN_CAST(nodep->exprp(), ArraySel)) {
|
||||||
if (const AstUnpackArrayDType* const arrp
|
if (const AstUnpackArrayDType* const arrp
|
||||||
= VN_CAST(arrselp->fromp()->dtypep(), UnpackArrayDType)) {
|
= VN_CAST(arrselp->fromp()->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||||
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
|
if (!VN_IS(arrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
|
||||||
if (VN_AS(arrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
|
if (VN_AS(arrp->subDTypep()->skipRefp(), IfaceRefDType)->isVirtual()) return;
|
||||||
// Interface pin attaches to one element of arrayed interface
|
// Interface pin attaches to one element of arrayed interface
|
||||||
V3Const::constifyParamsEdit(arrselp->bitp());
|
V3Const::constifyParamsEdit(arrselp->bitp());
|
||||||
const AstConst* const constp = VN_CAST(arrselp->bitp(), Const);
|
const AstConst* const constp = VN_CAST(arrselp->bitp(), Const);
|
||||||
|
|
@ -386,9 +389,9 @@ private:
|
||||||
} else {
|
} else {
|
||||||
AstVar* const pinVarp = nodep->modVarp();
|
AstVar* const pinVarp = nodep->modVarp();
|
||||||
const AstUnpackArrayDType* const pinArrp
|
const AstUnpackArrayDType* const pinArrp
|
||||||
= VN_CAST(pinVarp->dtypep(), UnpackArrayDType);
|
= VN_CAST(pinVarp->dtypep()->skipRefp(), UnpackArrayDType);
|
||||||
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return;
|
if (!pinArrp || !VN_IS(pinArrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
|
||||||
if (VN_AS(pinArrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
|
if (VN_AS(pinArrp->subDTypep()->skipRefp(), IfaceRefDType)->isVirtual()) return;
|
||||||
// Arrayed pin/var attaches to arrayed submodule lower port/var, expand it
|
// Arrayed pin/var attaches to arrayed submodule lower port/var, expand it
|
||||||
AstNode* prevp = nullptr;
|
AstNode* prevp = nullptr;
|
||||||
AstNode* prevPinp = nullptr;
|
AstNode* prevPinp = nullptr;
|
||||||
|
|
@ -403,7 +406,8 @@ private:
|
||||||
if (!pinVarp->backp()) {
|
if (!pinVarp->backp()) {
|
||||||
varNewp = m_deModVars.find(varNewName);
|
varNewp = m_deModVars.find(varNewName);
|
||||||
} else {
|
} else {
|
||||||
AstIfaceRefDType* const ifaceRefp = VN_AS(pinArrp->subDTypep(), IfaceRefDType);
|
AstIfaceRefDType* const ifaceRefp
|
||||||
|
= VN_AS(pinArrp->subDTypep()->skipRefp(), IfaceRefDType);
|
||||||
ifaceRefp->cellp(nullptr);
|
ifaceRefp->cellp(nullptr);
|
||||||
varNewp = pinVarp->cloneTree(false);
|
varNewp = pinVarp->cloneTree(false);
|
||||||
varNewp->name(varNewName);
|
varNewp->name(varNewName);
|
||||||
|
|
@ -435,13 +439,14 @@ private:
|
||||||
UASSERT_OBJ(VN_IS(slicep->rhsp(), Const), slicep, "Slices should be constant");
|
UASSERT_OBJ(VN_IS(slicep->rhsp(), Const), slicep, "Slices should be constant");
|
||||||
const int slice_index
|
const int slice_index
|
||||||
= slicep->declRange().left() + in * slicep->declRange().leftToRightInc();
|
= slicep->declRange().left() + in * slicep->declRange().leftToRightInc();
|
||||||
const auto* const exprArrp = VN_AS(varrefp->dtypep(), UnpackArrayDType);
|
const auto* const exprArrp
|
||||||
|
= VN_AS(varrefp->dtypep()->skipRefp(), UnpackArrayDType);
|
||||||
UASSERT_OBJ(exprArrp, slicep, "Slice of non-array");
|
UASSERT_OBJ(exprArrp, slicep, "Slice of non-array");
|
||||||
expr_i = slice_index + exprArrp->lo();
|
expr_i = slice_index + exprArrp->lo();
|
||||||
} else if (!varrefp) {
|
} else if (!varrefp) {
|
||||||
newp->exprp()->v3error("Unexpected connection to arrayed port");
|
newp->exprp()->v3error("Unexpected connection to arrayed port");
|
||||||
} else if (const auto* const exprArrp
|
} else if (const auto* const exprArrp
|
||||||
= VN_CAST(varrefp->dtypep(), UnpackArrayDType)) {
|
= VN_CAST(varrefp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||||
expr_i = exprArrp->left() + in * exprArrp->declRange().leftToRightInc();
|
expr_i = exprArrp->left() + in * exprArrp->declRange().leftToRightInc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -492,9 +497,9 @@ private:
|
||||||
void visit(AstNodeAssign* nodep) override {
|
void visit(AstNodeAssign* nodep) override {
|
||||||
if (AstSliceSel* const arrslicep = VN_CAST(nodep->rhsp(), SliceSel)) {
|
if (AstSliceSel* const arrslicep = VN_CAST(nodep->rhsp(), SliceSel)) {
|
||||||
if (const AstUnpackArrayDType* const arrp
|
if (const AstUnpackArrayDType* const arrp
|
||||||
= VN_CAST(arrslicep->fromp()->dtypep(), UnpackArrayDType)) {
|
= VN_CAST(arrslicep->fromp()->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||||
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
|
if (!VN_IS(arrp->subDTypep()->skipRefp(), IfaceRefDType)) return;
|
||||||
if (VN_AS(arrp->subDTypep(), IfaceRefDType)->isVirtual()) return;
|
if (VN_AS(arrp->subDTypep()->skipRefp(), IfaceRefDType)->isVirtual()) return;
|
||||||
arrslicep->v3warn(E_UNSUPPORTED, "Interface slices unsupported");
|
arrslicep->v3warn(E_UNSUPPORTED, "Interface slices unsupported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -557,7 +562,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
void visit(AstNodeExpr*) override {} // Accelerate
|
|
||||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
void visit(AstNew* nodep) override { iterateChildren(nodep); }
|
void visit(AstNew* nodep) override { iterateChildren(nodep); }
|
||||||
void visit(AstMethodCall* nodep) override { iterateChildren(nodep); }
|
void visit(AstMethodCall* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
|
||||||
|
|
@ -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(verilator_flags2=['--binary'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// 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 my_ifc ();
|
||||||
|
logic sig;
|
||||||
|
modport master ( output sig );
|
||||||
|
modport slave ( input sig );
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
package my_pkg;
|
||||||
|
typedef virtual my_ifc my_vif;
|
||||||
|
function void my_func;
|
||||||
|
input my_vif in_vif;
|
||||||
|
begin
|
||||||
|
in_vif.sig = 1'b1;
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module dut (input logic clk, my_ifc.slave sif[2]);
|
||||||
|
generate
|
||||||
|
genvar i;
|
||||||
|
for (i=0; i<2; i++) begin
|
||||||
|
always_ff @( posedge clk ) begin
|
||||||
|
if (sif[i].sig == 1'b1) $display("Hello World %0d", i);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t;
|
||||||
|
import my_pkg::*;
|
||||||
|
|
||||||
|
logic clk;
|
||||||
|
my_ifc sif[2] ();
|
||||||
|
|
||||||
|
dut DUT (.*);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
clk = 0;
|
||||||
|
forever #(5) clk = ~clk;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
repeat (4) @(posedge clk);
|
||||||
|
my_func(sif[0]);
|
||||||
|
my_func(sif[1]);
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue