From 72bd91c7f16004448fa82616c4231a91adbda8e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 7 May 2020 21:09:14 -0400 Subject: [PATCH] Support $isunbounded and parameter $. (#2104) --- Changes | 2 ++ src/V3AstNodes.h | 26 ++++++++++++++++++++++++-- src/V3Const.cpp | 9 +++++++++ src/V3Param.cpp | 3 ++- src/V3Width.cpp | 13 ++++++++++++- src/verilog.l | 1 + src/verilog.y | 4 +++- test_regress/t/t_queue_unsup_bad.out | 4 ---- test_regress/t/t_unbounded.pl | 21 +++++++++++++++++++++ test_regress/t/t_unbounded.v | 23 +++++++++++++++++++++++ 10 files changed, 97 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_unbounded.pl create mode 100644 test_regress/t/t_unbounded.v diff --git a/Changes b/Changes index 0ce774704..6d94edf3d 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.035 devel +**** Support $isunbounded and parameter $. (#2104) + **** Fix FST tracing of little bit endian signals. [Geza Lore] **** Fix +: and -: on unpacked arrays. (#2304) [engr248] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 235125f93..55e98c362 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2886,14 +2886,18 @@ public: AstNode* rhsp() const { return op2p(); } }; -class AstUnbounded : public AstNode { +class AstUnbounded : public AstNodeMath { // A $ in the parser, used for unbounded and queues + // Due to where is used, treated as Signed32 public: explicit AstUnbounded(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER(fl) { + dtypeSetSigned32(); + } ASTNODE_NODE_FUNCS(Unbounded) virtual string emitVerilog() { return "$"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return true; } }; //###################################################################### @@ -5449,6 +5453,24 @@ public: virtual bool cleanLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } }; +class AstIsUnbounded : public AstNodeUniop { + // True if is unmbounded ($) +public: + AstIsUnbounded(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } + ASTNODE_NODE_FUNCS(IsUnbounded) + virtual void numberOperate(V3Number& out, const V3Number&) { + // Any constant isn't unbounded + out.setZero(); + } + virtual string emitVerilog() { return "%f$isunbounded(%l)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool sizeMattersLhs() const { return false; } +}; class AstOneHot : public AstNodeUniop { // True if only single bit set in vector public: diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 7db3b5647..924ce8c9a 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1629,6 +1629,11 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); did = true; + } else if (nodep->varp()->isParam() && VN_IS(valuep, Unbounded)) { + AstNode* newp = valuep->cloneTree(false); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + did = true; } } } @@ -2141,6 +2146,7 @@ private: } virtual void visit(AstInitArray* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstInitItem* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstUnbounded* nodep) VL_OVERRIDE { iterateChildren(nodep); } // These are converted by V3Param. Don't constify as we don't want the // from() VARREF to disappear, if any. // If output of a presel didn't get consted, chances are V3Param didn't visit properly @@ -2531,6 +2537,9 @@ private: TREEOPC("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); TREEOPC("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())"); + // Custom + // Implied by AstIsUnbounded::numberOperate: V("AstIsUnbounded{$lhsp.castConst}", "replaceNum(nodep, 0)"); + TREEOPV("AstIsUnbounded{$lhsp.castUnbounded}", "replaceNum(nodep, 1)"); // clang-format on // Possible futures: diff --git a/src/V3Param.cpp b/src/V3Param.cpp index d50433cdd..830d0227b 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -301,7 +301,8 @@ private: << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ()); } else { V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init() - if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array + if (!VN_IS(nodep->valuep(), Const) + && !VN_IS(nodep->valuep(), Unbounded)) { // Complex init, like an array // Make a new INITIAL to set the value. // This allows the normal array/struct handling code to properly // initialize the parameter. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 382160da3..2ac427dc5 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1045,7 +1045,18 @@ private: } } virtual void visit(AstUnbounded* nodep) VL_OVERRIDE { - nodep->v3error("Unsupported/illegal unbounded ('$') in this context."); + nodep->dtypeSetSigned32(); // Used in int context + if (!VN_IS(nodep->backp(), IsUnbounded) + && !(VN_IS(nodep->backp(), Var) + && VN_CAST(nodep->backp(), Var)->isParam())) { + nodep->v3error("Unsupported/illegal unbounded ('$') in this context."); + } + } + virtual void visit(AstIsUnbounded* nodep) VL_OVERRIDE { + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); + nodep->dtypeSetLogicBool(); + } } virtual void visit(AstUCFunc* nodep) VL_OVERRIDE { // Give it the size the user wants. diff --git a/src/verilog.l b/src/verilog.l index 77b30e29d..56aa5c59f 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -441,6 +441,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$high" { FL; return yD_HIGH; } "$increment" { FL; return yD_INCREMENT; } "$info" { FL; return yD_INFO; } + "$isunbounded" { FL; return yD_ISUNBOUNDED; } "$isunknown" { FL; return yD_ISUNKNOWN; } "$left" { FL; return yD_LEFT; } "$low" { FL; return yD_LOW; } diff --git a/src/verilog.y b/src/verilog.y index 7227e84e3..06f21b7ec 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -595,6 +595,7 @@ class AstSenTree; %token yD_HYPOT "$hypot" %token yD_INCREMENT "$increment" %token yD_INFO "$info" +%token yD_ISUNBOUNDED "$isunbounded" %token yD_ISUNKNOWN "$isunknown" %token yD_ITOR "$itor" %token yD_LEFT "$left" @@ -3408,7 +3409,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD($1,$3,$5); } | yD_INCREMENT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,NULL); } | yD_INCREMENT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,$5); } - | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); } + | yD_ISUNBOUNDED '(' expr ')' { $$ = new AstIsUnbounded($1, $3); } + | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1, $3); } | yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); } | yD_LEFT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,NULL); } | yD_LEFT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,$5); } diff --git a/test_regress/t/t_queue_unsup_bad.out b/test_regress/t/t_queue_unsup_bad.out index 8c82b034b..7ba5976d4 100644 --- a/test_regress/t/t_queue_unsup_bad.out +++ b/test_regress/t/t_queue_unsup_bad.out @@ -34,10 +34,6 @@ : ... In instance t 38 | q = {q[0], q[2:$]}; | ^ -%Error: t/t_queue_unsup_bad.v:38:22: Expecting expression to be constant, but can't convert a UNBOUNDED to constant. - : ... In instance t - 38 | q = {q[0], q[2:$]}; - | ^ %Error: t/t_queue_unsup_bad.v:38:22: First value of [a:b] isn't a constant, maybe you want +: or -: : ... In instance t 38 | q = {q[0], q[2:$]}; diff --git a/test_regress/t/t_unbounded.pl b/test_regress/t/t_unbounded.pl new file mode 100755 index 000000000..f60fd309f --- /dev/null +++ b/test_regress/t/t_unbounded.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unbounded.v b/test_regress/t/t_unbounded.v new file mode 100644 index 000000000..a8b6d3bba --- /dev/null +++ b/test_regress/t/t_unbounded.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2014 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + + localparam UNB = $; + localparam int UNB2 = $; + localparam SIX = 6; + + initial begin + if ($bits($isunbounded(0)) !== 1) $stop; + if ($isunbounded(0) !== 1'b0) $stop; + if ($isunbounded(SIX) !== 0) $stop; + if ($isunbounded($) !== 1) $stop; + if ($isunbounded(UNB) !== 1) $stop; + if ($isunbounded(UNB2) !== 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule