From eb63c8dcb8aaed817baf2ccda387b9d2a9c6a92f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 6 Jan 2010 19:04:20 -0500 Subject: [PATCH] Fix multiple declarations on one enum, bug199 --- src/V3AstNodes.h | 27 +++++++++++++++++++++++++ src/V3LinkParse.cpp | 39 +++++++++++++++++++++++++++++++++++++ src/verilog.y | 11 ++++++++++- test_regress/t/t_enum_int.v | 10 +++++++++- 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 428953760..e626bbf42 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -147,6 +147,33 @@ public: virtual string name() const { return m_name; } }; +struct AstDefImplicitDType : public AstNodeDType { + // For parsing enum/struct/unions that are declared with a variable rather than typedef + // This allows "var enum {...} a,b" to share the enum definition for both variables + // After link, these become typedefs +private: + string m_name; + void* m_containerp; // In what scope is the name unique, so we can know what are duplicate definitions (arbitrary value) +public: + AstDefImplicitDType(FileLine* fl, const string& name, AstNode* containerp, AstNodeDType* dtypep) + : AstNodeDType(fl), m_name(name), m_containerp(containerp) { + setOp1p(dtypep); + widthSignedFrom(dtypep); + } + ASTNODE_NODE_FUNCS(DefImplicitDType, DEFIMPLICITDTYPE) + AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable + void dtypep(AstNodeDType* nodep) { setOp1p(nodep); } + void* containerp() const { return m_containerp; } + // 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()->widthTotalBytes(); } + virtual string name() const { return m_name; } + void name(const string& flag) { m_name = flag; } +}; + struct AstArrayDType : public AstNodeDType { // Array data type, ie "some_dtype var_name [2:0]" AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 0be60379a..999558fe4 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -50,12 +50,16 @@ private: // AstNode::user() -> bool. True if processed AstUser1InUse m_inuser1; + // TYPES + typedef map ,AstTypedef*> ImplTypedefMap; + // STATE string m_dotText; // Dotted module text we are building for a dotted node, passed up bool m_inModDot; // We're inside module part of dotted name AstParseRefExp m_exp; // Type of data we're looking for AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref AstVar* m_varp; // Variable we're under + ImplTypedefMap m_implTypedef; // Created typedefs for each // METHODS static int debug() { @@ -285,6 +289,41 @@ private: } } + virtual void visit(AstDefImplicitDType* nodep, AstNUser*) { + UINFO(8," DEFIMPLICIT "<containerp(), nodep->name())); + if (it != m_implTypedef.end()) { + defp = it->second; + } else { + // Definition must be inserted right after the variable (etc) that needed it + // AstVar, AstTypedef, AstNodeFTask are common containers + AstNode* backp = nodep->backp(); + for (; backp; backp=nodep->backp()) { + if (backp->castVar()) break; + else if (backp->castTypedef()) break; + else if (backp->castNodeFTask()) break; + } + if (!backp) nodep->v3fatalSrc("Implicit enum/struct type created under unexpected node type"); + AstNodeDType* dtypep = nodep->dtypep(); dtypep->unlinkFrBack(); + if (backp->castTypedef()) { // A typedef doesn't need us to make yet another level of typedefing + // For typedefs just remove the AstRefDType level of abstraction + nodep->replaceWith(dtypep); + nodep->deleteTree(); nodep=NULL; + return; + } else { + defp = new AstTypedef(nodep->fileline(), nodep->name(), dtypep); + m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp)); + backp->addNextHere(defp); + } + } + nodep->replaceWith(new AstRefDType(nodep->fileline(), defp->name())); + nodep->deleteTree(); nodep=NULL; + } + virtual void visit(AstNode* nodep, AstNUser*) { // Default: Just iterate checkExpected(nodep); // So we detect node types we forgot to list here diff --git a/src/verilog.y b/src/verilog.y index 2a99f113b..3cff31871 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -59,6 +59,8 @@ public: int m_pinNum; // Pin number currently parsing string m_instModule; // Name of module referenced for instantiations AstPin* m_instParamp; // Parameters for instantiations + AstNodeModule* m_modp; // Module + int m_modTypeImpNum; // Implicit type number, incremented each module int m_uniqueAttr; // Bitmask of unique/priority keywords // CONSTRUCTORS @@ -70,6 +72,8 @@ public: m_pinNum = -1; m_instModule; m_instParamp = NULL; + m_modp = NULL; + m_modTypeImpNum = 0; m_varAttrp = NULL; m_caseAttrp = NULL; } @@ -107,6 +111,7 @@ public: pkgp = new AstPackage(fl, AstPackage::dollarUnitName()); pkgp->inLibrary(true); // packages are always libraries; don't want to make them a "top" pkgp->modTrace(false); // may reconsider later + GRAMMARP->m_modp = pkgp; GRAMMARP->m_modTypeImpNum = 0; PARSEP->rootp()->addModulep(pkgp); SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global } @@ -583,6 +588,7 @@ packageFront: { $$ = new AstPackage($1,*$2); $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" $$->modTrace(v3Global.opt.trace()); + GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0; PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -669,6 +675,7 @@ modFront: yMODULE lifetimeE idAny { $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine()); $$->modTrace(v3Global.opt.trace()); + GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0; PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -679,6 +686,7 @@ udpFront: $$->modTrace(false); $$->addStmtp(new AstPragma($1,AstPragmaType::INLINE_MODULE)); PARSEP->fileline()->tracingOn(false); + GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0; PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -834,6 +842,7 @@ pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ { $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine()); $$->modTrace(v3Global.opt.trace()); + GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0; PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -1060,7 +1069,7 @@ data_typeNoRef: // ==IEEE: data_type, excluding class_type etc referenc //UNSUP { UNSUP } //UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionListE //UNSUP { UNSUP } - | enumDecl { $$ = $1; } + | enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->m_modTypeImpNum++),GRAMMARP->m_modp,$1); } | ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); } | yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); } //UNSUP yEVENT { UNSUP } diff --git a/test_regress/t/t_enum_int.v b/test_regress/t/t_enum_int.v index 814872ea3..042a0047a 100644 --- a/test_regress/t/t_enum_int.v +++ b/test_regress/t/t_enum_int.v @@ -21,7 +21,7 @@ module t (/*AUTOARG*/ EP_State_DWAIT , EP_State_DSHIFT0 , EP_State_DSHIFT1 , - EP_State_DSHIFT15 } m_state_xr; + EP_State_DSHIFT15 } m_state_xr, m_state2_xr; // Beginning of automatic ASCII enum decoding reg [79:0] m_stateAscii_xr; // Decode of m_state_xr @@ -49,21 +49,29 @@ module t (/*AUTOARG*/ //$write("%d %x %x %x\n", cyc, data, wrapcheck_a, wrapcheck_b); if (cyc==1) begin m_state_xr <= EP_State_IDLE; + m_state2_xr <= EP_State_IDLE; end if (cyc==2) begin if (m_stateAscii_xr != "idle ") $stop; m_state_xr <= EP_State_CMDSHIFT13; + if (m_state2_xr != EP_State_IDLE) $stop; + m_state2_xr <= EP_State_CMDSHIFT13; end if (cyc==3) begin if (m_stateAscii_xr != "cmdshift13") $stop; m_state_xr <= EP_State_CMDSHIFT16; + if (m_state2_xr != EP_State_CMDSHIFT13) $stop; + m_state2_xr <= EP_State_CMDSHIFT16; end if (cyc==4) begin if (m_stateAscii_xr != "cmdshift16") $stop; m_state_xr <= EP_State_DWAIT; + if (m_state2_xr != EP_State_CMDSHIFT16) $stop; + m_state2_xr <= EP_State_DWAIT; end if (cyc==9) begin if (m_stateAscii_xr != "dwait ") $stop; + if (m_state2_xr != EP_State_DWAIT) $stop; $write("*-* All Finished *-*\n"); $finish; end