From c1e8337fc1b36652328eb00a5dd256d5c9a33691 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 10:18:32 -0500 Subject: [PATCH] Support pattern assignment to dynamic arrays. --- src/V3AstNodes.h | 22 ++++++++++++ src/V3EmitC.cpp | 15 ++++++++ src/V3Width.cpp | 69 +++++++++++++++++++++++++++++++++++-- test_regress/t/t_dynarray.v | 26 +++++++------- 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 72e727cbf..da115b3e2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4668,6 +4668,28 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; +class AstConsDynArray : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ConsDynArray) + virtual string emitVerilog() override { return "'{%l, %r}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } // op1 = expression + AstNode* rhsp() const { return op2p(); } // op2 = expression + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; + class AstConsQueue : public AstNodeMath { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // Parents: math diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index f38f7504a..c209d55da 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1593,6 +1593,21 @@ class EmitCImp : EmitCStmts { iterateAndNextNull(nodep->valuep()); puts(")"); } + virtual void visit(AstConsDynArray* nodep) override { + putbs(nodep->dtypep()->cType("", false, false)); + if (!nodep->lhsp()) { + puts("()"); + } else { + puts("::cons("); + iterateAndNextNull(nodep->lhsp()); + if (nodep->rhsp()) { + puts(", "); + putbs(""); + } + iterateAndNextNull(nodep->rhsp()); + puts(")"); + } + } virtual void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f41ba25a1..3fd5a7ebd 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -485,6 +485,7 @@ private: // signed: Unsigned (11.8.1) // width: LHS + RHS AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); + userIterateAndNext(vdtypep, WidthVP(SELF, BOTH).p()); if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -494,6 +495,14 @@ private: userIterateChildren(newp, m_vup); return; } + if (VN_IS(vdtypep, DynArrayDType)) { + auto* newp = new AstConsDynArray(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), + nodep->lhsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterateChildren(newp, m_vup); + return; + } if (m_vup->prelim()) { if (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // @@ -633,7 +642,7 @@ private: } AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - if (VN_IS(vdtypep, QueueDType)) { + if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)) { if (times != 1) nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form " << vdtypep->prettyDTypeNameQ() @@ -645,8 +654,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) - || VN_IS(vdtypep, UnpackArrayDType)) { + if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, UnpackArrayDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); } @@ -1509,6 +1517,11 @@ private: } UINFO(4, "dtWidthed " << nodep << endl); } + virtual void visit(AstVoidDType* nodep) override { + if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + nodep->dtypep(nodep); + UINFO(4, "dtWidthed " << nodep << endl); + } virtual void visit(AstUnsizedArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. @@ -1985,6 +1998,38 @@ private: EXTEND_EXP); } } + virtual void visit(AstConsDynArray* nodep) override { + // Type computed when constructed here + AstDynArrayDType* vdtypep = VN_CAST(m_vup->dtypep(), DynArrayDType); + UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type"); + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p()); + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p()); + nodep->dtypeFrom(vdtypep); + } + if (m_vup->final()) { + // Arguments can be either elements of the queue or a queue itself + // Concats (part of tree of concats) must always become ConsDynArray's + if (nodep->lhsp()) { + if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType) + || VN_IS(nodep->lhsp(), ConsDynArray)) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + // Sub elements are not queues, but concats, must always pass concats down + iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL); + } + } + if (nodep->rhsp()) { + if (VN_IS(nodep->rhsp()->dtypep(), DynArrayDType) + || VN_IS(nodep->rhsp(), ConsDynArray)) { + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL); + } + } + nodep->dtypeFrom(vdtypep); + } + } virtual void visit(AstConsQueue* nodep) override { // Type computed when constructed here AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType); @@ -2969,12 +3014,15 @@ private: while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) { dtypep = vdtypep->subDTypep()->skipRefp(); } + userIterateAndNext(dtypep, WidthVP(SELF, BOTH).p()); if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, AssocArrayDType)) { VL_DO_DANGLING(patternAssoc(nodep, vdtypep, defaultp), nodep); + } else if (auto* vdtypep = VN_CAST(dtypep, DynArrayDType)) { + VL_DO_DANGLING(patternDynArray(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, QueueDType)) { VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep); } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { @@ -3155,6 +3203,21 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember* defaultp) { + AstNode* newp = new AstConsDynArray(nodep->fileline()); + newp->dtypeFrom(arrayp); + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { + patp->dtypep(arrayp->subDTypep()); + AstNode* valuep = patternMemberValueIterate(patp); + auto* newap = new AstConsDynArray(nodep->fileline(), valuep, newp); + newap->dtypeFrom(arrayp); + newp = newap; + } + nodep->replaceWith(newp); + // if (debug() >= 9) newp->dumpTree("-apat-out: "); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present + } void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) { AstNode* newp = new AstConsQueue(nodep->fileline()); newp->dtypeFrom(arrayp); diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index aa2b87ba8..4be647804 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -36,12 +36,19 @@ module t (/*AUTOARG*/ pck256_t p256[]; + string s[] = { "hello", "sad", "world" }; + always @ (posedge clk) begin cyc <= cyc + 1; begin `checkh(a.size, 0); v = $sformatf("%p", a); `checks(v, "'{}"); + `checkh(s.size, 3); + `checks(s[0], "hello"); + `checks(s[1], "sad"); + `checks(s[2], "world"); + a = new [3]; `checkh(a.size, 3); a[0] = 10; @@ -54,22 +61,17 @@ module t (/*AUTOARG*/ a.delete; `checkh(a.size, 0); - a = new [2]; -`ifdef verilator // Unsupported pattern assignment - a[0] = 15; a[1] = 16; -`else a = '{15, 16}; -`endif `checkh(a.size, 2); `checkh(a[0], 15); `checkh(a[1], 16) -`ifdef verilator // Unsupported pattern assignment - a = new [1]; - a[0] = 17; -`else + a = {17, 18}; + `checkh(a.size, 2); + `checkh(a[0], 17); + `checkh(a[1], 18) + a = '{17}; -`endif `checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern `checkh(a[0], 17); @@ -122,7 +124,7 @@ module t (/*AUTOARG*/ `checkh(b[0], 0); `checkh(b[1], 0); `checkh(b[2], 0); - `checkh(b[4], 0); + `checkh(b[3], 0); // test wide dynamic array p256 = new [11]; @@ -135,7 +137,7 @@ module t (/*AUTOARG*/ `checkh(p256[1].header, 16'hcafe); `checkh(p256[1], {16'hcafe,{14{16'hbabe}},16'hdead}); - `checkh(p256[0], '0); + //X's: `checkh(p256[0], 'x); p256[5] = '1; `checkh(p256[5], {32{8'hff}});