From 68fa82fb14772a3694228c3495080dfb8295d993 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 26 Jan 2020 13:21:25 -0500 Subject: [PATCH] Support $typename, and use to cleanup error messages. --- Changes | 2 +- include/verilatedos.h | 2 ++ src/V3Ast.h | 7 ++++- src/V3AstNodes.cpp | 34 ++++++++++++++++++++++++ src/V3AstNodes.h | 7 +++++ src/V3Width.cpp | 29 +++++++++++++------- src/verilog.l | 1 + src/verilog.y | 2 ++ test_regress/t/t_assoc_pattern_unsup.out | 2 +- test_regress/t/t_queue_unsup_bad.out | 18 ++++++------- test_regress/t/t_typename.pl | 20 ++++++++++++++ test_regress/t/t_typename.v | 34 ++++++++++++++++++++++++ test_regress/t/t_unpacked_concat_bad.out | 4 +-- test_regress/t/t_var_ref_bad1.out | 2 +- 14 files changed, 139 insertions(+), 25 deletions(-) create mode 100755 test_regress/t/t_typename.pl create mode 100644 test_regress/t/t_typename.v diff --git a/Changes b/Changes index d5982a285..484c74fd1 100644 --- a/Changes +++ b/Changes @@ -15,7 +15,7 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support $readmem/$writemem with assoc arrarys, #2100. [agrobman] -**** Support type(expression) operator, #1650. +**** Support type(expression) operator and $typename, #1650. **** Support left justified $display, #2101. [Pieter Kapsenberg] diff --git a/include/verilatedos.h b/include/verilatedos.h index abe5fff0c..6628c5584 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -184,12 +184,14 @@ # define VL_INCLUDE_UNORDERED_MAP # define VL_INCLUDE_UNORDERED_SET # endif +# define VL_FINAL final # define VL_OVERRIDE override #else # define VL_EQ_DELETE # define vl_unique_ptr std::auto_ptr # define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h" # define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h" +# define VL_FINAL # define VL_OVERRIDE #endif diff --git a/src/V3Ast.h b/src/V3Ast.h index 860a4bea1..14ba42da5 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -307,6 +307,8 @@ public: // MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes // + TYPENAME, // V3Width processes + // VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn @@ -330,6 +332,7 @@ public: "ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "MEMBER_BASE", + "TYPENAME", "VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER", @@ -1305,7 +1308,7 @@ public: static string vcdName(const string& namein); // Name for printing out to vcd files string prettyName() const { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } - string prettyTypeName() const; // "VARREF" for error messages + string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name) virtual string prettyOperatorName() const { return "operator "+prettyTypeName(); } FileLine* fileline() const { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } @@ -1950,6 +1953,8 @@ public: virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function virtual bool isFourstate() const; + virtual string prettyDTypeName() const { return prettyTypeName(); } // Ideally an IEEE $typename + string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } // // Changing the width may confuse the data type resolution, so must clear // TypeTable cache after use. diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 539319243..8b2f93b3b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -943,6 +943,14 @@ void AstBasicDType::dump(std::ostream& str) const { str<<" kwd="<AstNode::dump(str); str<<" sz"<AstNodeDType::dump(str); str<<" "<prettyDTypeName() << declRange(); + return os.str(); +} +string AstUnpackArrayDType::prettyDTypeName() const { + std::ostringstream os; + string ranges = cvtToStr(declRange()); + // Unfortunately we need a single $ for the first unpacked, and all + // dimensions shown in "reverse" order + AstNodeDType* subp = subDTypep()->skipRefp(); + while (AstUnpackArrayDType* adtypep = VN_CAST(subp, UnpackArrayDType)) { + ranges += cvtToStr(adtypep->declRange()); + subp = adtypep->subDTypep()->skipRefp(); + } + os << subp->prettyDTypeName() << "$" << ranges; + return os.str(); +} void AstNodeModule::dump(std::ostream& str) const { this->AstNode::dump(str); str<<" L"<AstNodeDType::dumpSmall(str); str<<"[assoc-"<<(void*)keyDTypep()<<"]"; } +string AstAssocArrayDType::prettyDTypeName() const { + return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]"; +} void AstQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str<<"[queue]"; } +string AstQueueDType::prettyDTypeName() const { + string str = subDTypep()->prettyDTypeName() + "[$"; + if (boundConst()) str += ":" + cvtToStr(boundConst()); + return str + "]"; +} void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str<<"[]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4724e4f29..11f9541cf 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -425,6 +425,7 @@ public: 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(); } @@ -473,6 +474,7 @@ public: widthForce(width, width); } ASTNODE_NODE_FUNCS(PackArrayDType) + virtual string prettyDTypeName() const; }; class AstUnpackArrayDType : public AstNodeArrayDType { @@ -500,6 +502,7 @@ public: widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(UnpackArrayDType) + virtual string prettyDTypeName() const; }; class AstUnsizedArrayDType : public AstNodeDType { @@ -623,6 +626,7 @@ public: virtual bool similarDType(AstNodeDType* samep) const { return type()==samep->type() && same(samep); } virtual string name() const { return m.m_keyword.ascii(); } + virtual string prettyDTypeName() const; virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; } AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable void rangep(AstRange* nodep) { setNOp1p(nodep); } @@ -827,6 +831,7 @@ public: } virtual void dumpSmall(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } + virtual string prettyDTypeName() const; AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -880,6 +885,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep), V3Hash(m_packagep)); } virtual void dump(std::ostream& str=std::cout) const; virtual string name() const { return m_name; } + virtual string prettyDTypeName() const { + return subDTypep() ? subDTypep()->name() : prettyName(); } virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; } virtual AstNodeDType* skipRefp() const { // Skip past both the Ref and the Typedef diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a37d5fec4..eed6e7536 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -449,7 +449,8 @@ private: if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType))) { - nodep->v3error("Unsupported: Concatenation to form "<prettyTypeName()); + nodep->v3error("Unsupported: Concatenation to form " + << vdtypep->prettyDTypeNameQ() << "data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -524,10 +525,11 @@ private: // width: value(LHS) * width(RHS) if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); - if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) - || VN_IS(vdtypep, QueueDType) - || VN_IS(vdtypep, UnpackArrayDType))) { - nodep->v3error("Unsupported: Replication to form "<prettyTypeName()); + if (vdtypep + && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType) + || VN_IS(vdtypep, UnpackArrayDType))) { + nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() + << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); @@ -1148,6 +1150,13 @@ private: } break; } + case AstAttrType::TYPENAME: { + UASSERT_OBJ(nodep->fromp(), nodep, "Unprovided expression"); + string result = nodep->fromp()->dtypep()->prettyDTypeName(); + AstNode* newp = new AstConst(nodep->fileline(), AstConst::String(), result); + nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + break; + } default: { // Everything else resolved earlier nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::UNSIGNED); // Approximation, unsized 32 @@ -2331,8 +2340,8 @@ private: && VN_CAST(dtypep, BasicDType)->isRanged()) { VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep); } else { - nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: " - <prettyTypeName()); + nodep->v3error("Unsupported: Assignment pattern applies against non struct/union data type: " + << dtypep->prettyDTypeNameQ()); } } } @@ -3041,9 +3050,9 @@ private: if (nodep->modVarp()->direction() == VDirection::REF) { nodep->v3error("Ref connection "<modVarp()->prettyNameQ() <<" requires matching types;" - <<" ref requires "<prettyTypeName() - <<" but connection is " - <prettyTypeName()<<"."<prettyDTypeNameQ() + <<" data type but connection is " + <prettyDTypeNameQ()<<" data type."<modVarp()->isTristate()) { if (pinwidth != conwidth) { nodep->v3error("Unsupported: "<prettyOperatorName()) diff --git a/src/verilog.l b/src/verilog.l index a1ca07e26..e9082d34c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -251,6 +251,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$test$plusargs" { FL; return yD_TESTPLUSARGS; } "$time" { FL; return yD_TIME; } "$timeskew" { FL; return yaTIMINGSPEC; } + "$typename" { FL; return yD_TYPENAME; } "$ungetc" { FL; return yD_UNGETC; } "$value$plusargs" { FL; return yD_VALUEPLUSARGS; } "$width" { FL; return yaTIMINGSPEC; } diff --git a/src/verilog.y b/src/verilog.y index ed976fda3..85957bb89 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -608,6 +608,7 @@ class AstSenTree; %token yD_TANH "$tanh" %token yD_TESTPLUSARGS "$test$plusargs" %token yD_TIME "$time" +%token yD_TYPENAME "$typename" %token yD_UNGETC "$ungetc" %token yD_UNIT "$unit" %token yD_UNPACKED_DIMENSIONS "$unpacked_dimensions" @@ -3277,6 +3278,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } | yD_TIME parenE { $$ = new AstTime($1); } + | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, AstAttrType::TYPENAME, $3); } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); } | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); } diff --git a/test_regress/t/t_assoc_pattern_unsup.out b/test_regress/t/t_assoc_pattern_unsup.out index 33981b55b..51f4430cd 100644 --- a/test_regress/t/t_assoc_pattern_unsup.out +++ b/test_regress/t/t_assoc_pattern_unsup.out @@ -1,4 +1,4 @@ -%Error: t/t_assoc_pattern_unsup.v:18: Unsupported: Assignment pattern applies against non struct/union: ASSOCARRAYDTYPE +%Error: t/t_assoc_pattern_unsup.v:18: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]' : ... In instance t a = '{ "f": "fooed", "b": "bared", default: "defaulted" }; ^~ diff --git a/test_regress/t/t_queue_unsup_bad.out b/test_regress/t/t_queue_unsup_bad.out index b3c20486b..f629a16c9 100644 --- a/test_regress/t/t_queue_unsup_bad.out +++ b/test_regress/t/t_queue_unsup_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_queue_unsup_bad.v:20: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:20: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {"q", "b", "c", "d", "e", "f"}; ^ @@ -10,23 +10,23 @@ : ... In instance t q.insert(2, "ins2"); ^~~~~~ -%Error: t/t_queue_unsup_bad.v:33: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:33: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {q, "f1"}; ^ -%Error: t/t_queue_unsup_bad.v:34: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:34: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {q, "f2"}; ^ -%Error: t/t_queue_unsup_bad.v:35: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:35: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {"b1", q}; ^ -%Error: t/t_queue_unsup_bad.v:36: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:36: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {"b2", q}; ^ -%Error: t/t_queue_unsup_bad.v:37: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:37: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = {q[0], q[2:$]}; ^ @@ -46,15 +46,15 @@ : ... In instance t q = {q[0], q[2:$]}; ^ -%Error: t/t_queue_unsup_bad.v:41: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:41: Unsupported: Replication to form 'string[$]' data type : ... In instance t string ai[$] = { "Foo", "Bar" }; ^ -%Error: t/t_queue_unsup_bad.v:46: Unsupported: Assignment pattern applies against non struct/union: QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:46: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' : ... In instance t q = '{ "BB", "CC" }; ^~ -%Error: t/t_queue_unsup_bad.v:49: Unsupported: Replication to form QUEUEDTYPE +%Error: t/t_queue_unsup_bad.v:49: Unsupported: Replication to form 'string[$]' data type : ... In instance t q = { "BB", "CC" }; ^ diff --git a/test_regress/t/t_typename.pl b/test_regress/t/t_typename.pl new file mode 100755 index 000000000..b1acebe26 --- /dev/null +++ b/test_regress/t/t_typename.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 2004 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_typename.v b/test_regress/t/t_typename.v new file mode 100644 index 000000000..7edda4a3a --- /dev/null +++ b/test_regress/t/t_typename.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. + +`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*/); + + real r; + logic l; + typedef bit mybit_t; + mybit_t [2:0] bitp20; + mybit_t bitu32 [3:2]; + mybit_t bitu31 [3:1][4:5]; + + initial begin + `checks($typename(real), "real"); + `checks($typename(bit), "bit"); + `checks($typename(int), "int"); + `checks($typename(logic), "logic"); + `checks($typename(string), "string"); + + `checks($typename(r), "real"); + `checks($typename(l), "logic"); + `checks($typename(mybit_t), "bit"); + `checks($typename(bitp20), "bit[2:0]"); + `checks($typename(bitu32), "bit$[3:2]"); + `checks($typename(bitu31), "bit$[3:1][4:5]"); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index a1f4b32d9..53dcbfdee 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_unpacked_concat_bad.v:16: Unsupported: Replication to form UNPACKARRAYDTYPE +%Error: t/t_unpacked_concat_bad.v:16: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type : ... In instance t localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; ^ @@ -7,7 +7,7 @@ localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; ^~~~~ ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. -%Error: t/t_unpacked_concat_bad.v:17: Unsupported: Replication to form UNPACKARRAYDTYPE +%Error: t/t_unpacked_concat_bad.v:17: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type : ... In instance t localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; ^ diff --git a/test_regress/t/t_var_ref_bad1.out b/test_regress/t/t_var_ref_bad1.out index 09c425e98..32bece252 100644 --- a/test_regress/t/t_var_ref_bad1.out +++ b/test_regress/t/t_var_ref_bad1.out @@ -1,4 +1,4 @@ -%Error: t/t_var_ref_bad1.v:13: Ref connection 'bad_sub_ref' requires matching types; ref requires BASICDTYPE 'real' but connection is BASICDTYPE 'bit'. +%Error: t/t_var_ref_bad1.v:13: Ref connection 'bad_sub_ref' requires matching types; ref requires 'real' data type but connection is 'bit' data type. : ... In instance t (.bad_sub_ref(bad_parent)); ^~~~~~~~~~~