diff --git a/Changes b/Changes index 1495898e0..4c0ace434 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman] +** Add support for dynamic arrays, #379. + *** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel] *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index ef9f2b8bc..432c847d4 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -245,11 +245,12 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename, } //=================================================================== -// Verilog queue container +// Verilog queue and dynamic array container // There are no multithreaded locks on this; the base variable must // be protected by other means // // Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound +// For dynamic arrays it is always zero template class VlQueue { private: // TYPES @@ -279,6 +280,21 @@ public: void clear() { m_deque.clear(); } void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); } + // Dynamic array new[] becomes a renew() + void renew(size_t size) { + clear(); + m_deque.resize(size, atDefault()); + } + // Dynamic array new[]() becomes a renew_copy() + void renew_copy(size_t size, const VlQueue& rhs) { + if (size == 0) { + clear(); + } else { + *this = rhs; + m_deque.resize(size, atDefault()); + } + } + // function void q.push_front(value) void push_front(const T_Value& value) { m_deque.push_front(value); @@ -304,6 +320,7 @@ public: // because we need to be able to insert only when the value is set T_Value& at(size_t index) { static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index >= m_deque.size())) { s_throwAway = atDefault(); return s_throwAway; @@ -313,6 +330,7 @@ public: // Accessing. Verilog: v = assoc[index] const T_Value& at(size_t index) const { static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index >= m_deque.size())) return atDefault(); else return m_deque[index]; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 127026a30..89e6de50e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -278,6 +278,17 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT VlArgTypeRecursed info; info.m_oprefix = out; return info; + } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { + VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); + string out = "VlQueue<"; + out += sub.m_oprefix; + if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) { + out += " " + sub.m_osuffix + sub.m_oref; + } + out += "> "; + VlArgTypeRecursed info; + info.m_oprefix = out; + return info; } else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); VlArgTypeRecursed info; @@ -1168,6 +1179,13 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const { string AstAssocArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]"; } +void AstDynArrayDType::dumpSmall(std::ostream& str) const { + this->AstNodeDType::dumpSmall(str); + str<<"[]"; +} +string AstDynArrayDType::prettyDTypeName() const { + return subDTypep()->prettyDTypeName() + "[]"; +} void AstQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str<<"[queue]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7eec8a8a0..c4c55a1e3 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -451,6 +451,56 @@ public: virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; +class AstDynArrayDType : public AstNodeDType { + // Dynamic array data type, ie "[]" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + childDTypep(dtp); // Only for parser + refDTypep(NULL); + dtypep(NULL); // V3Width will resolve + } + AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + refDTypep(dtp); + dtypep(NULL); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(DynArrayDType) + virtual const char* broken() const { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return NULL; } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } } + virtual bool same(const AstNode* samep) const { + const AstAssocArrayDType* asamep = static_cast(samep); + return subDTypep() == asamep->subDTypep(); } + virtual bool similarDType(AstNodeDType* samep) const { + const AstAssocArrayDType* asamep = static_cast(samep); + return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + } + virtual string prettyDTypeName() const; + virtual void dumpSmall(std::ostream& str) const; + virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } + AstNodeDType* getChildDTypep() const { return childDTypep(); } + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } +}; + class AstPackArrayDType : public AstNodeArrayDType { // Packed array data type, ie "some_dtype [2:0] var_name" // Children: DTYPE (moved to refDTypep() in V3Width) diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 6581ec37e..8416378d4 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -88,6 +88,7 @@ private: if (!nodep->user2() && nodep->hasDType()) { if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths! || VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays + || VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType) || VN_IS(nodep->dtypep()->skipRefp(), QueueDType) || VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index d5e4f9b66..59c521fc5 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1503,6 +1503,9 @@ class EmitCImp : EmitCStmts { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()" + cvtarray); } + else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); + } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 9cd64af07..5d60724af 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -50,6 +50,10 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE { + v3Global.needHeavy(true); + iterateChildren(nodep); + } virtual void visit(AstQueueDType* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 69c0c32b6..8283ce30c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -457,7 +457,7 @@ private: if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) - || VN_IS(vdtypep, AssocArrayDType) + || VN_IS(vdtypep, DynArrayDType) || VN_IS(vdtypep, QueueDType))) { nodep->v3error("Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ() << "data type"); @@ -536,7 +536,9 @@ private: if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); if (vdtypep - && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType) + && (VN_IS(vdtypep, AssocArrayDType) + || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); @@ -1219,6 +1221,14 @@ private: nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); + // Iterate into subDTypep() to resolve that type and update pointer. + nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->dtypep(nodep); // The array itself, not subDtype + UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); @@ -1445,9 +1455,13 @@ private: if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var"); - if (VN_IS(nodep->dtypeSkipRefp(), UnsizedArrayDType)) { + if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) { if (!(m_ftaskp && m_ftaskp->dpiImport())) { - nodep->v3error("Unsized/open arrays ('[]') are only supported in DPI imports"); + UINFO(9, "Unsized becomes dynamic array " << nodep << endl); + AstDynArrayDType* newp + = new AstDynArrayDType(unsizedp->fileline(), unsizedp->subDTypep()); + nodep->dtypep(newp); + v3Global.rootp()->typeTablep()->addTypesp(newp); } } else if (nodep->isIO() && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) @@ -1778,6 +1792,7 @@ private: if (memberSelStruct(nodep, adtypep)) return; } else if (VN_IS(fromDtp, EnumDType) || VN_IS(fromDtp, AssocArrayDType) + || VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType) || VN_IS(fromDtp, BasicDType)) { // Method call on enum without following parenthesis, e.g. "ENUM.next" @@ -1849,6 +1864,9 @@ private: else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) { methodCallAssoc(nodep, adtypep); } + else if (AstDynArrayDType* adtypep = VN_CAST(fromDtp, DynArrayDType)) { + methodCallDyn(nodep, adtypep); + } else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) { methodCallQueue(nodep, adtypep); } @@ -2059,6 +2077,41 @@ private: if (lvalue) varrefp->lvalue(true); } } + void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) { + AstCMethodHard* newp = NULL; + if (nodep->name() == "at") { // Created internally for [] + methodOkArguments(nodep, 1, 1); + methodCallLValue(nodep, nodep->fromp(), true); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "at", NULL); + newp->dtypeFrom(adtypep->subDTypep()); + newp->protect(false); + newp->didWidth(true); + } else if (nodep->name() == "size") { + methodOkArguments(nodep, 0, 0); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "size", NULL); + newp->dtypeSetSigned32(); + newp->didWidth(true); + newp->protect(false); + } else if (nodep->name() == "delete") { // function void delete() + methodOkArguments(nodep, 0, 0); + methodCallLValue(nodep, nodep->fromp(), true); + newp = new AstCMethodHard(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "clear", NULL); + newp->makeStatement(); + } else { + nodep->v3error("Unsupported/unknown built-in dynamic array method " + << nodep->prettyNameQ()); + } + if (newp) { + newp->didWidth(true); + nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + } void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) { AstCMethodHard* newp = NULL; if (nodep->name() == "at") { // Created internally for [] @@ -2305,7 +2358,26 @@ private: } virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - nodep->v3error("Unsupported: Dynamic array new"); + AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType); + if (!adtypep) { // e.g. int a = new; + if (adtypep) UINFO(1, "Got adtypep " << adtypep << endl); + nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)"); + return; + } + // The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it + if (!VN_IS(nodep->backp(), NodeAssign)) { + if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl); + nodep->v3error("dynamic new() not expected in this context (expected under an assign)"); + return; + } + nodep->dtypep(adtypep); + if (m_vup && m_vup->prelim()) { + iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH); + } + if (nodep->rhsp()) { + iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep->subDTypep(), + BOTH); + } } virtual void visit(AstPattern* nodep) VL_OVERRIDE { @@ -2727,6 +2799,23 @@ private: iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep); //if (debug()) nodep->dumpTree(cout, " AssignOut: "); } + if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) { + UINFO(9, "= new[] -> .resize(): " << nodep); + AstCMethodHard* newp; + if (!dynp->rhsp()) { + newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + "renew", dynp->sizep()->unlinkFrBack()); + } else { + newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), + "renew_copy", dynp->sizep()->unlinkFrBack()); + newp->addPinsp(dynp->rhsp()->unlinkFrBack()); + } + newp->didWidth(true); + newp->protect(false); + newp->makeStatement(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } } virtual void visit(AstSFormatF* nodep) VL_OVERRIDE { @@ -2772,6 +2861,7 @@ private: added = true; newFormat += "%g"; } else if (VN_IS(dtypep, AssocArrayDType) + || VN_IS(dtypep, DynArrayDType) || VN_IS(dtypep, QueueDType)) { added = true; newFormat += "%@"; @@ -4225,8 +4315,8 @@ private: AstNode* checkCvtUS(AstNode* nodep) { if (nodep && nodep->isDouble()) { - nodep->v3error("Expected integral (non-real) input to " - <backp()->prettyTypeName()); + nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName() + << ") input to " << nodep->backp()->prettyTypeName()); nodep = spliceCvtS(nodep, true); } return nodep; diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index ae3e4946d..d2ddff0bc 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -93,6 +93,8 @@ private: } else if (VN_IS(ddtypep, AssocArrayDType)) { } + else if (VN_IS(ddtypep, DynArrayDType)) { + } else if (VN_IS(ddtypep, QueueDType)) { } else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) { @@ -260,6 +262,15 @@ private: if (debug()>=9) newp->dumpTree(cout, "--SELBTn: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } + else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) { + // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) + AstNode* subp = rhsp; + AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), + fromp, "at", subp); + newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference + if (debug()>=9) newp->dumpTree(cout, "--SELBTq: "); + nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) AstNode* subp = rhsp; diff --git a/test_regress/t/t_dpi_openreg_bad.out b/test_regress/t/t_dpi_openreg_bad.out deleted file mode 100644 index 12ffed236..000000000 --- a/test_regress/t/t_dpi_openreg_bad.out +++ /dev/null @@ -1,9 +0,0 @@ -%Error: t/t_dpi_openreg_bad.v:13: Unsized/open arrays ('[]') are only supported in DPI imports - : ... In instance t - reg a []; - ^ -%Error: t/t_dpi_openreg_bad.v:14: Unsized/open arrays ('[]') are only supported in DPI imports - : ... In instance t - input b []; - ^ -%Error: Exiting due to diff --git a/test_regress/t/t_dpi_openreg_bad.v b/test_regress/t/t_dpi_openreg_bad.v deleted file mode 100644 index f2b5375e0..000000000 --- a/test_regress/t/t_dpi_openreg_bad.v +++ /dev/null @@ -1,20 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// Copyright 2009 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. - -module t (/*AUTOARG*/ - // Inputs - b - ); - - reg a []; - input b []; - - initial begin - $stop; - end - -endmodule diff --git a/test_regress/t/t_dynarray.pl b/test_regress/t/t_dynarray.pl new file mode 100755 index 000000000..6b3b15be5 --- /dev/null +++ b/test_regress/t/t_dynarray.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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. + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v new file mode 100644 index 000000000..146ad0be2 --- /dev/null +++ b/test_regress/t/t_dynarray.v @@ -0,0 +1,108 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + integer i; + string v; + + // verilator lint_off UNUSED + integer unused[]; + // verilator lint_on UNUSED + + typedef bit [7:0] byte_t; + byte_t a[]; + byte_t b[]; + + always @ (posedge clk) begin + cyc <= cyc + 1; + begin + `checkh(a.size, 0); + v = $sformatf("%p", a); `checks(v, "'{} "); + + a = new [3]; + `checkh(a.size, 3); + a[0] = 10; + a[1] = 11; + a[2] = 12; + `checkh(a[0], 10); + `checkh(a[1], 11); + `checkh(a[2], 12); + v = $sformatf("%p", a); `checks(v, "'{'ha, 'hb, 'hc} "); + 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}; +`endif + `checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern + `checkh(a[0], 17); + + a = new[2]; + a[0] = 5; + a[1] = 6; + `checkh(a[0], 5); + `checkh(a[1], 6); + a = new[2]; + `checkh(a[0], 0); + `checkh(a[1], 0); + + a[0] = 5; + a[1] = 6; + `checkh(a[0], 5); + `checkh(a[1], 6); + + b = new [4](a); + `checkh(b.size, 4); + `checkh(b[0], 5); + `checkh(b[1], 6); + `checkh(b[2], 0); + `checkh(b[3], 0); + + a = b; + `checkh(a.size, 4); + `checkh(a[0], 5); + `checkh(a[1], 6); + `checkh(a[2], 0); + `checkh(a[3], 0); + + a = new [0]; + `checkh(a.size, 0); + b = new [4](a); + `checkh(b.size, 4); + `checkh(b[0], 0); + `checkh(b[1], 0); + `checkh(b[2], 0); + `checkh(b[4], 0); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dynarray_bad.out b/test_regress/t/t_dynarray_bad.out new file mode 100644 index 000000000..c323f3ca2 --- /dev/null +++ b/test_regress/t/t_dynarray_bad.out @@ -0,0 +1,6 @@ +%Warning-WIDTH: t/t_dynarray_bad.v:14: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits. + : ... In instance t + a = new [s]; + ^~~ + ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. +%Error: Internal Error: ../V3Number.cpp:#: Number operation called with non-logic (double or string) argument: '"str"" diff --git a/test_regress/t/t_dpi_openreg_bad.pl b/test_regress/t/t_dynarray_bad.pl similarity index 81% rename from test_regress/t/t_dpi_openreg_bad.pl rename to test_regress/t/t_dynarray_bad.pl index 57ecc0da2..4689d6999 100755 --- a/test_regress/t/t_dpi_openreg_bad.pl +++ b/test_regress/t/t_dynarray_bad.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2003 by Wilson Snyder. This program is free software; you can +# Copyright 2019 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. @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - fails => $Self->{vlt_all}, + fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_dynarray_bad.v b/test_regress/t/t_dynarray_bad.v new file mode 100644 index 000000000..2516a6deb --- /dev/null +++ b/test_regress/t/t_dynarray_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +module t (/*AUTOARG*/); + + integer a[]; + + string s; + + initial begin + s = "str"; + a = new [s]; // Bad + end + +endmodule