diff --git a/Changes b/Changes index c8f2d9b2a..610232fab 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! ** PSL is no longer supported, please use System Verilog assertions. +** Support '{} assignment pattern on arrays, bug355. + *** Add --no-trace-params. *** Add assertions on 'unique if', bug725. [Jeff Bush] diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 1d835666c..4e186d3d2 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -408,6 +408,22 @@ class SliceVisitor : public AstNVisitor { virtual void visit(AstNodeAssign* nodep, AstNUser*) { if (!nodep->user1()) { + // Cleanup initArrays + if (AstInitArray* initp = nodep->rhsp()->castInitArray()) { + //if (debug()>=9) nodep->dumpTree(cout, "-InitArrayIn: "); + AstNode* newp = NULL; + int index = 0; + while (AstNode* subp=initp->initsp()) { + AstNode* lhsp = new AstArraySel(nodep->fileline(), + nodep->lhsp()->cloneTree(false), + index++); + newp = newp->addNext(nodep->cloneType(lhsp, subp->unlinkFrBack())); + } + //if (debug()>=9) newp->dumpTreeAndNext(cout, "-InitArrayOut: "); + nodep->replaceWith(newp); + pushDeletep(nodep); nodep=NULL; + return; // WIll iterate in a moment + } // Hasn't been searched for implicit slices yet findImplicit(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0a4fa7d33..079473606 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -911,7 +911,7 @@ private: } if (nodep->valuep()) { //if (debug()) nodep->dumpTree(cout," final: "); - if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep()->width(),0,BOTH).p()); + if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep(),BOTH).p()); if (!nodep->valuep()->castInitArray()) { // No dtype at present, perhaps TODO widthCheck(nodep,"Initial value",nodep->valuep(),nodep->width(),nodep->widthMin()); } @@ -1020,8 +1020,15 @@ private: nodep->dtypeFrom(nodep->itemp()); } virtual void visit(AstInitArray* nodep, AstNUser* vup) { - // Should be correct by construction, so we'll just loop through all types - nodep->iterateChildren(*this, vup); + // InitArray has type of the array; children are array values + AstNodeDType* vdtypep = vup->c()->dtypep(); + if (!vdtypep) nodep->v3fatalSrc("InitArray type not assigned by AstPattern visitor"); + nodep->dtypep(vdtypep); + if (AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType()) { + nodep->iterateChildren(*this,WidthVP(arrayp->subDTypep(),BOTH).p()); + } else { + nodep->v3fatalSrc("InitArray on non-array"); + } } virtual void visit(AstInside* nodep, AstNUser* vup) { nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); @@ -1269,19 +1276,95 @@ private: patp->dtypep(memp); patp->accept(*this,WidthVP(memp,BOTH).p()); // Convert to concat for now - if (!newp) newp = patp->lhssp()->unlinkFrBack(); + AstNode* valuep = patp->lhssp()->unlinkFrBack(); + if (!newp) newp = valuep; else { - AstConcat* concatp = new AstConcat(patp->fileline(), newp, patp->lhssp()->unlinkFrBack()); + AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); newp = concatp; newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(), concatp->lhsp()->width()+concatp->rhsp()->width(), nodep->dtypep()->numeric()); } - if (newpatp) pushDeletep(newpatp); + if (newpatp) { pushDeletep(newpatp); newpatp=NULL; } } if (newp) nodep->replaceWith(newp); else nodep->v3error("Assignment pattern with no members"); pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present + } + else if (AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType()) { + typedef map PatMap; + PatMap patmap; + { + int element = arrayp->declRange().left(); + for (AstPatMember* patp = nodep->itemsp()->castPatMember(); + patp; patp = patp->nextp()->castPatMember()) { + if (patp->keyp()) { + if (AstConst* constp = patp->keyp()->castConst()) { + element = constp->toSInt(); + } else { + patp->keyp()->v3error("Assignment pattern key not supported/understood: "<keyp()->prettyTypeName()); + } + } + if (patmap.find(element) != patmap.end()) { + patp->v3error("Assignment pattern key used multiple times: "<declRange().leftToRightInc(); + } + } + UINFO(9,"ent "<declRange().hi()<<" to "<declRange().lo()<declRange().hi(); ent>=arrayp->declRange().lo(); --ent) { + AstPatMember* newpatp = NULL; + AstPatMember* patp = NULL; + PatMap::iterator it=patmap.find(ent); + if (it == patmap.end()) { + if (defaultp) { + newpatp = defaultp->cloneTree(false); + patp = newpatp; + } + else { + nodep->v3error("Assignment pattern missed initializing elements: "<second; + patmap.erase(it); + } + + // Determine initial values + vdtypep = arrayp->subDTypep(); + // Don't want the RHS an array + patp->dtypep(arrayp->subDTypep()); + // Determine values - might be another InitArray + patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p()); + // Convert to InitArray or constify immediately + AstNode* valuep = patp->lhssp()->unlinkFrBack(); + if (arrayp->castUnpackArrayDType()) { + if (!newp) { + newp = new AstInitArray(nodep->fileline(), arrayp, valuep); + } else { + // We iterate hi()..lo() as that is what packed needs, + // but INITARRAY needs lo() first + newp->castInitArray()->initsp()->addHereThisAsNext(valuep); + } + } else { // Packed. Convert to concat for now. + if (!newp) newp = valuep; + else { + AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); + newp = concatp; + newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(), + concatp->lhsp()->width()+concatp->rhsp()->width(), + nodep->dtypep()->numeric()); + } + } + if (newpatp) { pushDeletep(newpatp); newpatp=NULL; } + } + if (patmap.size()) nodep->v3error("Assignment pattern with too many elements"); + if (newp) nodep->replaceWith(newp); + else nodep->v3error("Assignment pattern with no members"); + //if (debug()>=9) newp->dumpTree("-apat-out: "); + pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present } else { nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<prettyTypeName()); } @@ -1291,10 +1374,11 @@ private: AstNodeDType* vdtypep = vup->c()->dtypep(); if (!vdtypep) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor"); nodep->dtypep(vdtypep); + UINFO(9," PATMEMBER "<lhssp()->nextp()) nodep->v3fatalSrc("PatMember value should be singular w/replicates removed"); nodep->lhssp()->dtypeFrom(nodep); nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p()); - widthCheck(nodep,"LHS",nodep->lhssp(),nodep->width(),nodep->width()); + widthCheck(nodep,"Value",nodep->lhssp(),vdtypep); } int visitPatMemberRep(AstPatMember* nodep) { uint32_t times = 1; diff --git a/test_regress/t/t_array_pattern_packed.pl b/test_regress/t/t_array_pattern_packed.pl index 690264b14..f91289753 100755 --- a/test_regress/t/t_array_pattern_packed.pl +++ b/test_regress/t/t_array_pattern_packed.pl @@ -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, bug355"); - compile ( ); diff --git a/test_regress/t/t_array_pattern_packed.v b/test_regress/t/t_array_pattern_packed.v index 9c8712815..1a293d5dc 100644 --- a/test_regress/t/t_array_pattern_packed.v +++ b/test_regress/t/t_array_pattern_packed.v @@ -26,11 +26,21 @@ module t (/*AUTOARG*/ //array_simp[0] = '{ 1:4'd3, default:13}; //if (array_simp[0] !== 16'hDD3D) $stop; - array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }}; + array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }}; if (array_simp !== 32'h3210_1234) $stop; + // IEEE says '{} allowed only on assignments, not !=, ==. + // Doesn't seem to work for unpacked arrays in other simulators - array_simp = '{2 { '{4 { 4'd3, 4'd2, 4'd1, 4'd0 }} } }; + array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }}; + if (array_simp !== 32'h3210_3210) $stop; + + array_simp = '{2{ '{4{ 4'd3 }} }}; + if (array_simp !== 32'h3333_3333) $stop; + + // Not legal in other simulators - replication doesn't match + // However IEEE suggests this is legal. + //array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2} $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_array_pattern_unpacked.pl b/test_regress/t/t_array_pattern_unpacked.pl index 690264b14..f91289753 100755 --- a/test_regress/t/t_array_pattern_unpacked.pl +++ b/test_regress/t/t_array_pattern_unpacked.pl @@ -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, bug355"); - compile ( ); diff --git a/test_regress/t/t_array_pattern_unpacked.v b/test_regress/t/t_array_pattern_unpacked.v index 617535c3d..9aea2cb6a 100644 --- a/test_regress/t/t_array_pattern_unpacked.v +++ b/test_regress/t/t_array_pattern_unpacked.v @@ -25,7 +25,17 @@ module t (/*AUTOARG*/); array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_1234) $stop; // Doesn't seem to work for unpacked arrays in other simulators - array_simp = '{2 { '{4 { 4'd3, 4'd2, 4'd1, 4'd0 }} } }; + array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }}; + if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0], + array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_3210) $stop; + + array_simp = '{2{ '{4{ 4'd3 }} }}; + if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0], + array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3333_3333) $stop; + + // Not legal in other simulators - replication doesn't match + // However IEEE suggests this is legal. + //array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2} $write("*-* All Finished *-*\n"); $finish;