From dbce06500d185551656545b1ee9e52d345d51686 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 27 Dec 2009 08:29:55 -0500 Subject: [PATCH] Support enums --- Changes | 2 +- src/V3AstNodes.cpp | 6 +++ src/V3AstNodes.h | 58 ++++++++++++++++++++++ src/V3Const.cpp | 17 +++++++ src/V3Link.cpp | 55 ++++++++++++++++++--- src/V3LinkParse.cpp | 23 +++++++++ src/V3Signed.cpp | 4 ++ src/V3Width.cpp | 52 ++++++++++++++++++++ src/verilog.l | 2 +- src/verilog.y | 49 ++++++++++++++++++- test_regress/t/t_enum.pl | 18 +++++++ test_regress/t/t_enum.v | 56 +++++++++++++++++++++ test_regress/t/t_enum_int.pl | 18 +++++++ test_regress/t/t_enum_int.v | 73 ++++++++++++++++++++++++++++ test_regress/t/t_enum_overlap_bad.pl | 20 ++++++++ test_regress/t/t_enum_overlap_bad.v | 18 +++++++ 16 files changed, 460 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_enum.pl create mode 100644 test_regress/t/t_enum.v create mode 100755 test_regress/t/t_enum_int.pl create mode 100644 test_regress/t/t_enum_int.v create mode 100755 test_regress/t/t_enum_overlap_bad.pl create mode 100644 test_regress/t/t_enum_overlap_bad.v diff --git a/Changes b/Changes index 90a982632..c5f90280e 100644 --- a/Changes +++ b/Changes @@ -10,7 +10,7 @@ indicates the contributor was also the author of the fix; Thanks! ** Support "program", "package", "import" and $unit. -** Support typedef. [Donal Casey] +** Support typedef and enum. [by Donal Casey] ** Support direct programming interface (DPI) "import" and "export". diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 93e4abbbd..6cd163a5c 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -467,6 +467,12 @@ void AstDisplay::dump(ostream& str) { this->AstNode::dump(str); //str<<" "<AstNode::dump(str); + str<<" -> "; + if (itemp()) { itemp()->dump(str); } + else { str<<"UNLINKED"; } +} void AstPin::dump(ostream& str) { this->AstNode::dump(str); if (modVarp()) { str<<" -> "; modVarp()->dump(str); } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index bd6cce8a8..8fb34ab6e 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -285,6 +285,64 @@ public: void packagep(AstPackage* nodep) { m_packagep=nodep; } }; +struct AstEnumItem : public AstNode { +private: + string m_name; +public: + // Parents: ENUM + AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) + : AstNode(fl), m_name(name) + { addNOp1p(rangep); addNOp2p(initp); } + ASTNODE_NODE_FUNCS(EnumItem, ENUMITEM) + virtual string name() const { return m_name; } + virtual bool maybePointedTo() const { return true; } + void name(const string& flag) { m_name = flag; } + AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range for name appending + void rangep(AstNode* nodep) { addOp1p(nodep); } + AstNode* initp() const { return op2p(); } // op2 = Value + void initp(AstNode* nodep) { addOp2p(nodep); } +}; + +struct AstEnumItemRef : public AstNodeMath { +private: + AstEnumItem* m_itemp; // [AfterLink] Pointer to item +public: + AstEnumItemRef(FileLine* fl, AstEnumItem* itemp) + : AstNodeMath(fl), m_itemp(itemp) { + if (m_itemp) widthSignedFrom(m_itemp); + } + ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF) + virtual void dump(ostream& str); + virtual string name() const { return itemp()->name(); } + virtual bool broken() const { return !itemp(); } + virtual int instrCount() const { return 0; } + virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); } + virtual bool same(AstNode* samep) const { + return itemp()==samep->castEnumItemRef()->itemp(); } + AstEnumItem* itemp() const { return m_itemp; } + virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() { return true; } +}; + +struct AstEnumDType : public AstNodeDType { + // Parents: TYPEDEF/MODULE + // Children: ENUMVALUEs + AstEnumDType(FileLine* fl, AstNodeDType* dtypep, AstNode* itemsp) + : AstNodeDType(fl) + { setOp1p(dtypep); addNOp2p(itemsp); } + ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE) + AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Data type + void dtypep(AstNodeDType* nodep) { setOp1p(nodep); } + AstEnumItem* itemsp() const { return op2p()->castEnumItem(); } // op2 = AstEnumItem's + void addValuesp(AstNode* nodep) { addOp2p(nodep); } + // METHODS + virtual AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return dtypep()->widthAlignBytes(); } +}; + //###################################################################### struct AstArraySel : public AstNodeSel { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index b99410f5e..acba056d8 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1073,6 +1073,23 @@ private: nodep->v3error("Expecting expression to be constant, but variable isn't const: "<varp()->prettyName()); } } + virtual void visit(AstEnumItemRef* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (!nodep->itemp()) nodep->v3fatalSrc("Not linked"); + bool did=false; + if (nodep->itemp()->initp()) { + //if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: "); + nodep->itemp()->initp()->iterateAndNext(*this); + if (AstConst* initp = nodep->itemp()->initp()->castConst()) { + const V3Number& num = initp->num(); + replaceNum(nodep, num); nodep=NULL; + did=true; + } + } + if (!did && m_required) { + nodep->v3error("Expecting expression to be constant, but variable isn't const: "<itemp()->prettyName()); + } + } virtual void visit(AstAttrOf* nodep, AstNUser*) { // Don't iterate children, don't want to loose VarRef. if (nodep->attrType()==AstAttrType::BITS) { diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 512350b28..962dc8304 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -118,12 +118,22 @@ private: else return NULL; } - void linkVarName (AstVarRef* nodep) { + bool linkVarName (AstVarRef* nodep) { + // Return true if changed, and caller should end processing if (!nodep->varp()) { - AstVar* varp = m_curVarsp->findIdUpward(nodep->name())->castVar(); - nodep->varp(varp); - nodep->packagep(packageFor(varp)); + AstNode* foundp = m_curVarsp->findIdUpward(nodep->name()); + if (AstVar* varp = foundp->castVar()) { + nodep->varp(varp); + nodep->packagep(packageFor(varp)); + } + else if (AstEnumItem* valuep = foundp->castEnumItem()) { + AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep); + nodep->replaceWith(newp); + nodep->deleteTree(); nodep=NULL; + return true; // Edited + } } + return false; } string nodeTextType(AstNode* nodep) { @@ -170,7 +180,7 @@ private: void createImplicitVar (AstVarRef* forrefp, bool noWarn) { // Create implicit after warning - linkVarName(forrefp); + if (linkVarName(forrefp)) { forrefp=NULL; return; } if (!forrefp->varp()) { if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<prettyName()); AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE, @@ -301,19 +311,50 @@ private: } virtual void visit(AstVarRef* nodep, AstNUser*) { // VarRef: Resolve its reference + nodep->iterateChildren(*this); if (m_idState==ID_RESOLVE && !nodep->varp()) { - linkVarName(nodep); + if (linkVarName(nodep)) { nodep=NULL; return; } if (!nodep->varp()) { nodep->v3error("Can't find definition of signal: "<prettyName()); createImplicitVar (nodep, true); // So only complain once } } - nodep->iterateChildren(*this); } //virtual void visit(AstVarXRef* nodep, AstNUser*) { // See LinkDotVisitor //} + virtual void visit(AstEnumItem* nodep, AstNUser*) { + // EnumItem: Remember its name for later resolution + nodep->iterateChildren(*this); + if (m_idState==ID_FIND) { + // Find under either a task or the module's vars + AstNode* foundp = m_curVarsp->findIdUpward(nodep->name()); + AstEnumItem* findvarp = foundp->castEnumItem(); + bool ins=false; + if (!foundp) { + ins=true; + } else if (findvarp != nodep) { + UINFO(4,"DupVar: "<user3p() == m_curVarsp) { // Only when on same level + nodep->v3error("Duplicate declaration of enum value: "<prettyName()); + findvarp->v3error("... Location of original declaration"); + } else { + // User can disable the message at either point + if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN) + && !foundp->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { + nodep->v3warn(VARHIDDEN,"Declaration of enum value hides declaration in upper scope: "<name()); + foundp->v3warn(VARHIDDEN,"... Location of original declaration"); + } + ins = true; + } + } + if (ins) { + symsInsert(nodep->name(), nodep); + } + } + } + virtual void visit(AstNodeFTask* nodep, AstNUser*) { // NodeTask: Remember its name for later resolution if (!m_curVarsp) nodep->v3fatalSrc("Function/Task not under module??\n"); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 71d0eb833..ceceabfbe 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -226,6 +226,29 @@ private: } } } + virtual void visit(AstEnumItem* nodep, AstNUser*) { + // Expand ranges + nodep->iterateChildren(*this); + if (nodep->rangep()) { + if (!nodep->rangep()->msbp()->castConst() + || !nodep->rangep()->lsbp()->castConst()) nodep->v3error("Enum ranges must be integral, per spec"); + int msb = nodep->rangep()->msbConst(); + int lsb = nodep->rangep()->lsbConst(); + int increment = (msb > lsb) ? -1 : 1; + int offset_from_init = 0; + AstNode* addp = NULL; + for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) { + string name = nodep->name() + cvtToStr(i); + AstNode* initp = NULL; + if (nodep->initp()) initp = new AstAdd(nodep->fileline(), nodep->initp()->cloneTree(true), + new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init)); + addp = addp->addNextNull(new AstEnumItem(nodep->fileline(), name, NULL, initp)); + } + nodep->replaceWith(addp); + nodep->deleteTree(); + } + } + virtual void visit(AstVar* nodep, AstNUser*) { m_varp = nodep; diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 6f59e4695..0d17e0941 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -152,6 +152,10 @@ private: nodep->varp()->iterate(*this); nodep->signedFrom(nodep->varp()); } + virtual void visit(AstEnumItemRef* nodep, AstNUser*) { + nodep->itemp()->iterate(*this); + nodep->signedFrom(nodep->itemp()); + } virtual void visit(AstConst* nodep, AstNUser*) { // The node got setup with the signed state of the node. // However a later operation may have changed the node->signed w/o changing diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 5ee399e13..24f58173c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -575,6 +575,58 @@ private: } //if (debug()>=9) nodep->dumpTree(cout," VRout "); } + + virtual void visit(AstEnumDType* nodep, AstNUser* vup) { + nodep->dtypep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + nodep->widthFrom(nodep->dtypep()); + // Assign widths + nodep->itemsp()->iterateAndNext(*this,WidthVP(nodep->width(),nodep->widthMin(),BOTH).p()); + // Assign missing values + V3Number num (nodep->fileline(), nodep->width(), 0); + V3Number one (nodep->fileline(), nodep->width(), 1); + map inits; + for (AstEnumItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castEnumItem()) { + if (itemp->initp()) { + if (debug()>=9) { UINFO(0,"EnumInit "<initp()->dumpTree(cout,"-EnumInit: "); } + V3Const::constifyParamsEdit(itemp->initp()); // itemp may change + if (!itemp->initp()->castConst()) { + itemp->initp()->v3error("Enum value isn't a constant"); + itemp->initp()->unlinkFrBack()->deleteTree(); + } + } + if (!itemp->initp()) itemp->initp(new AstConst(itemp->fileline(), num)); + num.opAssign(itemp->initp()->castConst()->num()); + // Look for duplicates + if (inits.find(num) != inits.end()) { + itemp->v3error("Overlapping enumeration value: "<prettyName()); + inits.find(num)->second->v3error("... Location of original declaration"); + } else { + inits.insert(make_pair(num,itemp)); + } + num.opAdd(one, itemp->initp()->castConst()->num()); + } + } + virtual void visit(AstEnumItem* nodep, AstNUser* vup) { + int width = vup->c()->width(); + int mwidth = vup->c()->widthMin(); + nodep->width(width, mwidth); + if (nodep->initp()) { + nodep->initp()->iterateAndNext(*this,WidthVP(width,mwidth,BOTH).p()); + widthCheck(nodep,"Enum value",nodep->initp(),width,mwidth); + } + } + virtual void visit(AstEnumItemRef* nodep, AstNUser* vup) { + if (nodep->itemp()->width()==0) { + // We need to do the whole enum en-mass + AstNode* enump = nodep; + for (; enump; enump=enump->backp()) { + if (enump->castEnumDType()) break; + } + if (!enump) nodep->v3fatalSrc("EnumItem not under a Enum"); + enump->iterate(*this); + } + nodep->widthFrom(nodep->itemp()->initp()); + } virtual void visit(AstPslClocked* nodep, AstNUser*) { nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p()); nodep->sensesp()->iterateAndNext(*this); diff --git a/src/verilog.l b/src/verilog.l index 3ee913653..6c35d6a4c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -375,6 +375,7 @@ escid \\[^ \t\f\r\n]+ "endpackage" { FL; return yENDPACKAGE; } "endprogram" { FL; return yENDPROGRAM; } "endproperty" { FL; return yENDPROPERTY; } + "enum" { FL; return yENUM; } "export" { FL; return yEXPORT; } "final" { FL; return yFINAL; } "iff" { FL; return yIFF; } @@ -414,7 +415,6 @@ escid \\[^ \t\f\r\n]+ "endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "enum" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "extern" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } diff --git a/src/verilog.y b/src/verilog.y index 24139780d..5988988c6 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -279,6 +279,7 @@ class AstSenTree; %token yENDSPECIFY "endspecify" %token yENDTABLE "endtable" %token yENDTASK "endtask" +%token yENUM "enum" %token yEXPORT "export" %token yFINAL "final" %token yFOR "for" @@ -1058,7 +1059,7 @@ data_typeNoRef: // ==IEEE: data_type, excluding class_type etc referenc //UNSUP { UNSUP } //UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionListE //UNSUP { UNSUP } - //UNSUP enumDecl { UNSUP } + | enumDecl { $$ = $1; } | ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); } | yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); } //UNSUP yEVENT { UNSUP } @@ -1138,6 +1139,50 @@ variable_dimension: // ==IEEE: variable_dimension // // '[' '$' ':' expr ']' -- anyrange:expr:$ ; +//************************************************ +// enum + +// IEEE: part of data_type +enumDecl: + yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,$2,$4); } + ; + +enum_base_typeE: // IEEE: enum_base_type + /* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); } + // // Not in spec, but obviously "enum [1:0]" should work + // // implicit_type expanded, without empty + | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); } + | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } + // + | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } + | integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); } + | yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2); } + ; + +enum_nameList: + enum_name_declaration { $$ = $1; } + | enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); } + ; + +enum_name_declaration: // ==IEEE: enum_name_declaration + idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($1, *$1, $2, $3); } + ; + +enumNameRangeE: // IEEE: second part of enum_name_declaration + /* empty */ { $$ = NULL; } + | '[' intnumAsConst ']' { $$ = new AstRange($1,new AstConst($1,0), $2); } + | '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); } + ; + +enumNameStartE: // IEEE: third part of enum_name_declaration + /* empty */ { $$ = NULL; } + | '=' constExpr { $$ = $2; } + ; + +intnumAsConst: + yaINTNUM { $$ = new AstConst($1,*$1); } + ; + //************************************************ // Typedef @@ -1188,7 +1233,7 @@ type_declaration: // ==IEEE: type_declaration // // Combines into above "data_type id" rule // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned | yTYPEDEF id ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } - //UNSUP yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$3); SYMP->reinsert($$); } + | yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$3); SYMP->reinsert($$); } //UNSUP yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$3); SYMP->reinsert($$); } //UNSUP yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$3); SYMP->reinsert($$); } //UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$3); SYMP->reinsert($$); } diff --git a/test_regress/t/t_enum.pl b/test_regress/t/t_enum.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_enum.pl @@ -0,0 +1,18 @@ +#!/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. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum.v b/test_regress/t/t_enum.v new file mode 100644 index 000000000..a9f1f9aed --- /dev/null +++ b/test_regress/t/t_enum.v @@ -0,0 +1,56 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t (/*AUTOARG*/); + + localparam FIVE = 5; + + enum { e0, + e1, + e3=3, + e5=FIVE, + e10_[2] = 10, + e20_[5:7] = 25, + e20_z, + e30_[7:5] = 30, + e30_z + } EN; + + enum { + z5 = e5 + } ZN; + + typedef enum [2:0] { ONES=~0 } three_t; + three_t three = ONES; + + var logic [ONES:0] sized_based_on_enum; + + initial begin + if (e0 !== 0) $stop; + if (e1 !== 1) $stop; + if (e3 !== 3) $stop; + if (e5 !== 5) $stop; + if (e10_0 !== 10) $stop; + if (e10_1 !== 11) $stop; + if (e20_5 !== 25) $stop; + if (e20_6 !== 26) $stop; + if (e20_7 !== 27) $stop; + if (e20_z !== 28) $stop; + if (e30_7 !== 30) $stop; + if (e30_6 !== 31) $stop; + if (e30_5 !== 32) $stop; + if (e30_z !== 33) $stop; + + if (z5 !== 5) $stop; + + if (three != 3'b111) $stop; + + if ($bits(sized_based_on_enum) != 8) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_enum_int.pl b/test_regress/t/t_enum_int.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_enum_int.pl @@ -0,0 +1,18 @@ +#!/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. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_int.v b/test_regress/t/t_enum_int.v new file mode 100644 index 000000000..814872ea3 --- /dev/null +++ b/test_regress/t/t_enum_int.v @@ -0,0 +1,73 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + enum integer { + + EP_State_IDLE , + EP_State_CMDSHIFT0 , + EP_State_CMDSHIFT13 , + EP_State_CMDSHIFT14 , + EP_State_CMDSHIFT15 , + EP_State_CMDSHIFT16 , + EP_State_DWAIT , + EP_State_DSHIFT0 , + EP_State_DSHIFT1 , + EP_State_DSHIFT15 } m_state_xr; + + // Beginning of automatic ASCII enum decoding + reg [79:0] m_stateAscii_xr; // Decode of m_state_xr + always @(m_state_xr) begin + case ({m_state_xr}) + EP_State_IDLE: m_stateAscii_xr = "idle "; + EP_State_CMDSHIFT0: m_stateAscii_xr = "cmdshift0 "; + EP_State_CMDSHIFT13: m_stateAscii_xr = "cmdshift13"; + EP_State_CMDSHIFT14: m_stateAscii_xr = "cmdshift14"; + EP_State_CMDSHIFT15: m_stateAscii_xr = "cmdshift15"; + EP_State_CMDSHIFT16: m_stateAscii_xr = "cmdshift16"; + EP_State_DWAIT: m_stateAscii_xr = "dwait "; + EP_State_DSHIFT0: m_stateAscii_xr = "dshift0 "; + EP_State_DSHIFT1: m_stateAscii_xr = "dshift1 "; + EP_State_DSHIFT15: m_stateAscii_xr = "dshift15 "; + default: m_stateAscii_xr = "%Error "; + endcase + end + // End of automatics + + integer cyc; initial cyc=1; + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + //$write("%d %x %x %x\n", cyc, data, wrapcheck_a, wrapcheck_b); + if (cyc==1) begin + m_state_xr <= EP_State_IDLE; + end + if (cyc==2) begin + if (m_stateAscii_xr != "idle ") $stop; + m_state_xr <= EP_State_CMDSHIFT13; + end + if (cyc==3) begin + if (m_stateAscii_xr != "cmdshift13") $stop; + m_state_xr <= EP_State_CMDSHIFT16; + end + if (cyc==4) begin + if (m_stateAscii_xr != "cmdshift16") $stop; + m_state_xr <= EP_State_DWAIT; + end + if (cyc==9) begin + if (m_stateAscii_xr != "dwait ") $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule diff --git a/test_regress/t/t_enum_overlap_bad.pl b/test_regress/t/t_enum_overlap_bad.pl new file mode 100755 index 000000000..1b2cb1858 --- /dev/null +++ b/test_regress/t/t_enum_overlap_bad.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 2008 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. + +compile ( + v_flags2 => ["--lint-only"], + fails=>$Self->{v3}, + expect=> +'%Error: t/t_enum_overlap_bad.v:\d+: Overlapping enumeration value: e1b +%Error: t/t_enum_overlap_bad.v:\d+: ... Location of original declaration +%Error: Exiting due to', + ) if $Self->{v3}; + +ok(1); +1; diff --git a/test_regress/t/t_enum_overlap_bad.v b/test_regress/t/t_enum_overlap_bad.v new file mode 100644 index 000000000..bc3b8a25d --- /dev/null +++ b/test_regress/t/t_enum_overlap_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t (/*AUTOARG*/); + + enum { e0, + e1, + e2, + e1b=1 + } BAD1; + + initial begin + $stop; + end + +endmodule