forked from github/verilator
Fix dot indexing into arrayed inferfaces, bug978.
This commit is contained in:
parent
215d5f68b0
commit
4464b13163
2
Changes
2
Changes
@ -31,6 +31,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
**** Fix struct.enum.name method calls, bug855. [Jonathon Donaldson]
|
||||
|
||||
**** Fix dot indexing into arrayed inferfaces, bug978. [Johan Bjork]
|
||||
|
||||
|
||||
* Verilator 3.876 2015-08-12
|
||||
|
||||
|
@ -109,8 +109,9 @@ private:
|
||||
// Create an AstAssignVarScope for Vars to Cells so we can link with their scope later
|
||||
AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
AstVarRef* refp = exprp->castVarRef();
|
||||
if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
|
||||
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp);
|
||||
AstVarXRef* xrefp = exprp->castVarXRef();
|
||||
if (!refp && !xrefp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef or VarXRef");
|
||||
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, exprp);
|
||||
m_modp->addStmtp(assp);
|
||||
} else {
|
||||
nodep->v3error("Assigned pin is neither input nor output");
|
||||
@ -169,6 +170,12 @@ private:
|
||||
if (nodep->rangep()) {
|
||||
m_cellRangep = nodep->rangep();
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
|
||||
AstVar *ifaceVarp = nodep->nextp()->castVar();
|
||||
bool isIface = ifaceVarp
|
||||
&& ifaceVarp->dtypep()->castUnpackArrayDType()
|
||||
&& ifaceVarp->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType();
|
||||
|
||||
// Make all of the required clones
|
||||
m_instLsb = m_cellRangep->lsbConst();
|
||||
for (m_instNum = m_instLsb; m_instNum<=m_cellRangep->msbConst(); m_instNum++) {
|
||||
@ -181,6 +188,22 @@ private:
|
||||
// The spec says we add [x], but that won't work in C...
|
||||
newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
|
||||
// If this AstCell is actually an interface instantiation, let's ensure we also clone
|
||||
// the IfaceRef.
|
||||
if (isIface) {
|
||||
AstUnpackArrayDType *arrdtype = ifaceVarp->dtypep()->castUnpackArrayDType();
|
||||
AstVar* varNewp = ifaceVarp->cloneTree(false);
|
||||
AstIfaceRefDType *ifaceRefp = arrdtype->subDTypep()->castIfaceRefDType()->cloneTree(false);
|
||||
arrdtype->addNextHere(ifaceRefp);
|
||||
ifaceRefp->cellp(newp);
|
||||
ifaceRefp->cellName(newp->name());
|
||||
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(m_instNum) + "__KET__");
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(m_instNum) + "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
newp->addNextHere(varNewp);
|
||||
if (debug()==9) { varNewp->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
}
|
||||
// Fixup pins
|
||||
newp->pinsp()->iterateAndNext(*this);
|
||||
if (debug()==9) { newp->dumpTree(cout,"newcell: "); cout<<endl; }
|
||||
@ -188,9 +211,14 @@ private:
|
||||
|
||||
// Done. Delete original
|
||||
m_cellRangep=NULL;
|
||||
if (isIface) {
|
||||
ifaceVarp->unlinkFrBack(); pushDeletep(ifaceVarp); VL_DANGLING(ifaceVarp);
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||
// Any non-direct pins need reconnection with a part-select
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
@ -217,6 +245,29 @@ private:
|
||||
} else {
|
||||
nodep->v3fatalSrc("Width mismatch; V3Width should have errored out.");
|
||||
}
|
||||
} else if(AstArraySel *arrselp = nodep->exprp()->castArraySel()) {
|
||||
if (AstUnpackArrayDType *arrp = arrselp->lhsp()->dtypep()->castUnpackArrayDType()) {
|
||||
if (!arrp->subDTypep()->castIfaceRefDType())
|
||||
return;
|
||||
|
||||
AstConst *constp = arrselp->rhsp()->castConst();
|
||||
if (!constp) {
|
||||
nodep->v3error("Unsupported: Non-constant index when passing interface to module");
|
||||
return;
|
||||
}
|
||||
string index = AstNode::encodeNumber(constp->toSInt());
|
||||
AstVarRef *varrefp = arrselp->lhsp()->castVarRef();
|
||||
AstVarXRef *newp = new AstVarXRef(nodep->fileline(),varrefp->name () + "__BRA__" + index + "__KET__", "", true);
|
||||
AstVar *varp = varrefp->varp()->cloneTree(true);
|
||||
varp->name(varp->name() + "__TMP__" + "__BRA__" + index + "__KET__");
|
||||
varp->dtypep(arrp->subDTypep()->backp()->castIfaceRefDType());
|
||||
newp->addNextHere(varp);
|
||||
newp->varp(varp);
|
||||
newp->dtypep(arrp->subDTypep()->castIfaceRefDType());
|
||||
newp->packagep(varrefp->packagep());
|
||||
arrselp->addNextHere(newp);
|
||||
arrselp->unlinkFrBack()->deleteTree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,8 +323,10 @@ public:
|
||||
// Else create a intermediate wire to perform the interconnect
|
||||
// Return the new assignment, if one was made
|
||||
// Note this module calles cloneTree() via new AstVar
|
||||
|
||||
AstVar* pinVarp = pinp->modVarp();
|
||||
AstVarRef* connectRefp = pinp->exprp()->castVarRef();
|
||||
AstVarXRef* connectXRefp = pinp->exprp()->castVarXRef();
|
||||
AstBasicDType* pinBasicp = pinVarp->dtypep()->basicp(); // Maybe NULL
|
||||
AstBasicDType* connBasicp = NULL;
|
||||
AstAssignW* assignp = NULL;
|
||||
@ -288,6 +341,9 @@ public:
|
||||
&& connectRefp
|
||||
&& connectRefp->varp()->isIfaceRef()) {
|
||||
// Done. Interface
|
||||
} else if (!alwaysCvt
|
||||
&& connectXRefp
|
||||
&& connectXRefp->varp()->isIfaceRef()) {
|
||||
} else if (!alwaysCvt
|
||||
&& connBasicp
|
||||
&& pinBasicp
|
||||
|
@ -348,18 +348,23 @@ private:
|
||||
// This is quite similar to how classes work; when unpacked classes are better supported
|
||||
// may remap interfaces to be more like a class.
|
||||
if (!nodep->hasIfaceVar()) {
|
||||
if (!nodep->rangep()) {
|
||||
string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming
|
||||
AstIfaceRefDType *idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(),
|
||||
nodep->modp()->name());
|
||||
string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming
|
||||
AstIfaceRefDType *idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(),
|
||||
nodep->modp()->name());
|
||||
idtypep->ifacep(NULL); // cellp overrides
|
||||
AstVar *varp;
|
||||
if (nodep->rangep()) {
|
||||
AstNodeArrayDType *arrp = new AstUnpackArrayDType(nodep->fileline(),VFlagChildDType(), idtypep, nodep->rangep()->cloneTree(true));
|
||||
varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), arrp);
|
||||
} else {
|
||||
idtypep->cellp(nodep); // Only set when real parent cell known
|
||||
idtypep->ifacep(NULL); // cellp overrides
|
||||
AstVar *varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), idtypep);
|
||||
varp->isIfaceParent(true);
|
||||
nodep->addNextHere(varp);
|
||||
nodep->hasIfaceVar(true);
|
||||
varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), idtypep);
|
||||
}
|
||||
varp->isIfaceParent(true);
|
||||
nodep->addNextHere(varp);
|
||||
nodep->hasIfaceVar(true);
|
||||
}
|
||||
}
|
||||
if (nodep->modp()) {
|
||||
|
@ -1145,8 +1145,9 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
||||
VSymEnt* rhsSymp;
|
||||
{
|
||||
AstVarRef* refp = nodep->rhsp()->castVarRef();
|
||||
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarRef attached to interface pin");
|
||||
string scopename = refp->name();
|
||||
AstVarXRef* xrefp = nodep->rhsp()->castVarXRef();
|
||||
if (!refp && !xrefp) nodep->v3fatalSrc("Unsupported: Non Var(X)Ref attached to interface pin");
|
||||
string scopename = refp ? refp->name() : xrefp->name();
|
||||
string baddot; VSymEnt* okSymp;
|
||||
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
|
||||
if (!symp) nodep->v3fatalSrc("No symbol for interface alias rhs");
|
||||
|
@ -481,15 +481,28 @@ void ParamVisitor::visitCell(AstCell* nodep) {
|
||||
AstVar* modvarp = pinp->modVarp();
|
||||
if (modvarp->isIfaceRef()) {
|
||||
AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
|
||||
AstIfaceRefDType* pinIrefp = NULL;
|
||||
AstNode *exprp = pinp->exprp();
|
||||
if (exprp
|
||||
&& exprp->castVarRef()
|
||||
&& exprp->castVarRef()->varp()
|
||||
&& exprp->castVarRef()->varp()->subDTypep()
|
||||
&& exprp->castVarRef()->varp()->subDTypep()->castIfaceRefDType())
|
||||
pinIrefp = exprp->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
|
||||
else if (exprp
|
||||
&& exprp->op1p()
|
||||
&& exprp->op1p()->castVarRef()
|
||||
&& exprp->op1p()->castVarRef()->varp()
|
||||
&& exprp->op1p()->castVarRef()->varp()->subDTypep()
|
||||
&& exprp->op1p()->castVarRef()->varp()->subDTypep()->castUnpackArrayDType()
|
||||
&& exprp->op1p()->castVarRef()->varp()->subDTypep()->castUnpackArrayDType()->subDTypep()
|
||||
&& exprp->op1p()->castVarRef()->varp()->subDTypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType())
|
||||
pinIrefp = exprp->op1p()->castVarRef()->varp()->subDTypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType();
|
||||
//UINFO(9," portIfaceRef "<<portIrefp<<endl);
|
||||
if (!pinp->exprp()
|
||||
|| !pinp->exprp()->castVarRef()
|
||||
|| !pinp->exprp()->castVarRef()->varp()
|
||||
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()
|
||||
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
|
||||
|
||||
if (!pinIrefp) {
|
||||
pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
|
||||
} else {
|
||||
AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
|
||||
//UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
|
||||
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
|
||||
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
|
||||
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug978");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
|
@ -4,24 +4,53 @@
|
||||
// without warranty, 2015 by Johan Bjork.
|
||||
|
||||
interface intf;
|
||||
logic a;
|
||||
modport source(output a);
|
||||
modport sink(input a);
|
||||
logic logic_in_intf;
|
||||
modport source(output logic_in_intf);
|
||||
modport sink(input logic_in_intf);
|
||||
endinterface
|
||||
|
||||
module modify_interface
|
||||
(
|
||||
input logic value,
|
||||
intf.source intf_inst
|
||||
);
|
||||
assign intf_inst.logic_in_intf = value;
|
||||
endmodule
|
||||
|
||||
module t
|
||||
#(
|
||||
parameter N = 1
|
||||
)
|
||||
( input [N-1:0] a_in,
|
||||
output[N-1:0] a_out
|
||||
);
|
||||
parameter N = 6
|
||||
)();
|
||||
intf ifs[N-1:0] ();
|
||||
logic [N-1:0] a_q;
|
||||
logic [N-1:0] data;
|
||||
assign data = {1'b0, 1'b1, 1'b0, 1'b1, 1'b0, 1'b1};
|
||||
|
||||
generate
|
||||
genvar i;
|
||||
for (i = 0;i < 4; i++) begin
|
||||
assign ifs[i].logic_in_intf = data[i];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
modify_interface m (
|
||||
.value(data[4]),
|
||||
.intf_inst(ifs[4]));
|
||||
|
||||
modify_interface m1 (
|
||||
.value(~ifs[4].logic_in_intf),
|
||||
.intf_inst(ifs[5]));
|
||||
|
||||
generate
|
||||
genvar j;
|
||||
for (j = 0;j < N-1; j++) begin
|
||||
initial begin
|
||||
if (ifs[j].logic_in_intf != data[j]) $stop;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign a_out = a_q;
|
||||
assign ifs[0].a = a_in[0];
|
||||
initial begin
|
||||
if (ifs[5].logic_in_intf != ~ifs[4].logic_in_intf) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user