diff --git a/Changes b/Changes index 0379dbf2f..329a565f3 100644 --- a/Changes +++ b/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 diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 9aefd5cda..8a8abffdb 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -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 "<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<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 diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index cc85ee7ad..dcec8f38f 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -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()) { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 686958b65..96c32463e 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -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"); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 6c293bf78..2113179af 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -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 "<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 '"<prettyName()<<"' is not connected to interface/modport pin expression"); } else { - AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType(); //UINFO(9," pinIfaceRef "<ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { UINFO(9," IfaceRefDType needs reconnect "<{vlt} and $Self->unsupported("Verilator unsupported, bug978"); - compile ( ); diff --git a/test_regress/t/t_array_interface.v b/test_regress/t/t_array_interface.v index f2f67f0b7..6f688647c 100644 --- a/test_regress/t/t_array_interface.v +++ b/test_regress/t/t_array_interface.v @@ -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