diff --git a/Changes b/Changes index b8e0333b4..8620ccfb2 100644 --- a/Changes +++ b/Changes @@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.025 devel +*** Add BOUNDED warning and promote bounded queues to unbounded. + * Verilator 4.024 2019-12-08 diff --git a/bin/verilator b/bin/verilator index 17a9bef07..8972cc341 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3743,6 +3743,14 @@ generally unrolls small loops. You may want to try increasing --unroll-count (and occasionally --unroll-stmts) which will raise the small loop bar to avoid this error. +=item BOUNDED + +This indicates that bounded queues (e.g. "var name[$ : 3]") are +unsupported. + +Ignoring this warning may make Verilator simulations differ from other +simulators. + =item BSSPACE Warns that a backslash is followed by a space then a newline. Likely the diff --git a/src/V3Error.h b/src/V3Error.h index 98ce5220f..8f2892c16 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -105,6 +105,7 @@ public: SYMRSVDWORD, // Symbol is Reserved Word SYNCASYNCNET, // Mixed sync + async reset TICKCOUNT, // Too large tick count + UNBOUNDED, // Unbounded queue UNDRIVEN, // No drivers UNOPT, // Unoptimizable block UNOPTFLAT, // Unoptimizable block after flattening @@ -154,7 +155,7 @@ public: "REALCVT", "REDEFMACRO", "SELRANGE", "SHORTREAL", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", - "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", + "UNBOUNDED", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSED", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", "VARHIDDEN", "WIDTH", "WIDTHCONCAT", diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 52f9345e3..13155ac15 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -116,11 +116,17 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, if (rangep && isPacked) { arrayp = new AstPackArrayDType (rangep->fileline(), VFlagChildDType(), arrayp, rangep); - } else if (rangep) { - if (VN_IS(rangep->leftp(), Unbounded) - || VN_IS(rangep->rightp(), Unbounded)) { - rangep->v3error("Unsupported: Bounded queues. Suggest use unbounded."); + } else if (VN_IS(nrangep, QueueRange)) { + arrayp = new AstQueueDType + (nrangep->fileline(), VFlagChildDType(), arrayp); + } else if (rangep && (VN_IS(rangep->leftp(), Unbounded) + || VN_IS(rangep->rightp(), Unbounded))) { + if (!VN_IS(rangep->rightp(), Unbounded)) { + rangep->v3warn(UNBOUNDED, + "Unsupported: Bounded queues. Converting to unbounded."); } + arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp); + } else if (rangep) { arrayp = new AstUnpackArrayDType (rangep->fileline(), VFlagChildDType(), arrayp, rangep); } else if (VN_IS(nrangep, UnsizedRange)) { @@ -131,9 +137,6 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeDType* keyp = arangep->keyDTypep(); keyp->unlinkFrBack(); arrayp = new AstAssocArrayDType (nrangep->fileline(), VFlagChildDType(), arrayp, keyp); - } else if (VN_IS(nrangep, QueueRange)) { - arrayp = new AstQueueDType - (nrangep->fileline(), VFlagChildDType(), arrayp); } else { UASSERT_OBJ(0, nrangep, "Expected range or unsized range"); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7087eac87..a8bc3140f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1935,28 +1935,46 @@ private: newp->protect(false); newp->makeStatement(); } else { - nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) complexity and slow."); AstNode* index_exprp = methodCallQueueIndexExpr(nodep); - newp = new AstCMethodCall(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "erase", index_exprp->unlinkFrBack()); - newp->protect(false); - newp->makeStatement(); + if (index_exprp->isZero()) { // delete(0) is a pop_front + newp = new AstCMethodCall(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "pop_front", NULL); + newp->dtypeFrom(adtypep->subDTypep()); + newp->protect(false); + newp->didWidth(true); + newp->makeStatement(); + } else { + nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) complexity and slow."); + newp = new AstCMethodCall(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "erase", index_exprp->unlinkFrBack()); + newp->protect(false); + newp->makeStatement(); + } } } else if (nodep->name() == "insert") { - nodep->v3error("Unsupported: Queue .insert method, as is O(n) complexity and slow."); methodOkArguments(nodep, 2, 2); methodCallLValue(nodep, nodep->fromp(), true); AstNode* index_exprp = methodCallQueueIndexExpr(nodep); AstArg* argp = VN_CAST(nodep->pinsp()->nextp(), Arg); iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH); - newp = new AstCMethodCall(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - nodep->name(), - index_exprp->unlinkFrBack()); - newp->addPinsp(argp->exprp()->unlinkFrBack()); - newp->protect(false); - newp->makeStatement(); + if (index_exprp->isZero()) { // insert(0, ...) is a push_front + newp = new AstCMethodCall(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + "push_front", argp->exprp()->unlinkFrBack()); + newp->protect(false); + newp->makeStatement(); + } else { + nodep->v3error("Unsupported: Queue .insert method, as is O(n) complexity and slow."); + newp = new AstCMethodCall(nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + nodep->name(), + index_exprp->unlinkFrBack()); + newp->addPinsp(argp->exprp()->unlinkFrBack()); + newp->protect(false); + newp->makeStatement(); + } } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { methodOkArguments(nodep, 0, 0); diff --git a/test_regress/t/t_queue.v b/test_regress/t/t_queue.v index f21b1522f..1eea7f91e 100644 --- a/test_regress/t/t_queue.v +++ b/test_regress/t/t_queue.v @@ -72,6 +72,15 @@ module t (/*AUTOARG*/ i = q.size(); `checkh(i, 0); v = q.pop_front(); `checks(v, ""); // Was empty, optional warning v = q.pop_back(); `checks(v, ""); // Was empty, optional warning + + // COnversion of insert/delete with zero to operator + q.push_front("front"); + q.insert(0, "newfront"); + i = q.size(); `checkh(i, 2); + q.delete(0); + i = q.size(); `checkh(i, 1); + `checks(q[0], "front"); + end // See t_queue_unsup_bad for more unsupported stuff diff --git a/test_regress/t/t_queue_bounded.pl b/test_regress/t/t_queue_bounded.pl new file mode 100755 index 000000000..89a4e77d9 --- /dev/null +++ b/test_regress/t/t_queue_bounded.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 2003 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_queue_bounded.v b/test_regress/t/t_queue_bounded.v new file mode 100644 index 000000000..4e0898601 --- /dev/null +++ b/test_regress/t/t_queue_bounded.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +module t (/*AUTOARG*/); + + // verilator lint_off UNBOUNDED + int q[$ : 3]; + + initial begin + q.push_front(1); + q.push_front(1); + q.push_front(1); + if (q.size() != 3) $stop; + q.push_front(1); + // TODO correct answer when supported: + //if (q.size() != 3) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_queue_bounded_unsup_bad.out b/test_regress/t/t_queue_bounded_unsup_bad.out index 4f610c1f7..d65628337 100644 --- a/test_regress/t/t_queue_bounded_unsup_bad.out +++ b/test_regress/t/t_queue_bounded_unsup_bad.out @@ -1,4 +1,5 @@ -%Error: t/t_queue_bounded_unsup_bad.v:7: Unsupported: Bounded queues. Suggest use unbounded. +%Warning-UNBOUNDED: t/t_queue_bounded_unsup_bad.v:7: Unsupported: Bounded queues. Converting to unbounded. int q[$ : 3]; ^ + ... Use "/* verilator lint_off UNBOUNDED */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_queue_unsup_bad.out b/test_regress/t/t_queue_unsup_bad.out index 6e37baf6f..b3c20486b 100644 --- a/test_regress/t/t_queue_unsup_bad.out +++ b/test_regress/t/t_queue_unsup_bad.out @@ -6,10 +6,6 @@ : ... In instance t q.delete(1); ^~~~~~ -%Error: t/t_queue_unsup_bad.v:26: Unsupported: Queue .insert method, as is O(n) complexity and slow. - : ... In instance t - q.insert(0, "ins0"); - ^~~~~~ %Error: t/t_queue_unsup_bad.v:27: Unsupported: Queue .insert method, as is O(n) complexity and slow. : ... In instance t q.insert(2, "ins2");