diff --git a/src/V3Ast.h b/src/V3Ast.h index 19a1fd6dc..a9f533f2b 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -94,6 +94,32 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o //###################################################################### +class VLifetime { +public: + enum en { NONE, AUTOMATIC, STATIC }; + enum en m_e; + const char* ascii() const { + static const char* const names[] = {"NONE", "VAUTOM", "VSTATIC"}; + return names[m_e]; + } + inline VLifetime() + : m_e(NONE) {} + // cppcheck-suppress noExplicitConstructor + inline VLifetime(en _e) + : m_e(_e) {} + explicit inline VLifetime(int _e) + : m_e(static_cast(_e)) {} + operator en() const { return m_e; } + bool isNone() const { return m_e == NONE; } + bool isAutomatic() const { return m_e == AUTOMATIC; } + bool isStatic() const { return m_e == STATIC; } +}; +inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; } + +//###################################################################### + class VSigning { public: enum en { @@ -2575,6 +2601,7 @@ private: bool m_dpiTask : 1; // DPI import task (vs. void function) bool m_isConstructor : 1; // Class constructor bool m_pure : 1; // DPI import pure (vs. virtual pure) + VLifetime m_lifetime; // Lifetime public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode(t, fl) @@ -2639,6 +2666,8 @@ public: bool isConstructor() const { return m_isConstructor; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } }; class AstNodeFTaskRef : public AstNodeStmt { @@ -2715,6 +2744,7 @@ private: int m_level; // 1=top module, 2=cell off top module, ... int m_varNum; // Incrementing variable number int m_typeNum; // Incrementing implicit type number + VLifetime m_lifetime; // Lifetime VTimescale m_timeunit; // Global time unit VOptionBool m_unconnectedDrive; // State of `unconnected_drive public: @@ -2766,6 +2796,8 @@ public: bool recursive() const { return m_recursive; } void recursiveClone(bool flag) { m_recursiveClone = flag; } bool recursiveClone() const { return m_recursiveClone; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8cb89dc5e..c7fb643c2 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1437,6 +1437,7 @@ void AstVar::dump(std::ostream& str) const { } if (isDpiOpenArray()) str << " [DPIOPENA]"; if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] "; + if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; str << " " << varType(); } void AstSenTree::dump(std::ostream& str) const { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 602148564..cab07a6c6 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1780,7 +1780,7 @@ private: bool m_attrSplitVar : 1; // declared with split_var metacomment bool m_fileDescr : 1; // File descriptor bool m_isConst : 1; // Table contains constant data - bool m_isStatic : 1; // Static variable + bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) bool m_isPulldown : 1; // Tri0 bool m_isPullup : 1; // Tri1 bool m_isIfaceParent : 1; // dtype is reference to interface present in this module @@ -1788,6 +1788,7 @@ private: bool m_noReset : 1; // Do not do automated reset/randomization bool m_noSubst : 1; // Do not substitute out references bool m_trace : 1; // Trace this variable + VLifetime m_lifetime; // Lifetime VVarAttrClocker m_attrClocker; MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var @@ -2037,6 +2038,8 @@ public: bool attrIsolateAssign() const { return m_attrIsolateAssign; } VVarAttrClocker attrClocker() const { return m_attrClocker; } virtual string verilogKwd() const; + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } void propagateAttrFrom(AstVar* fromp) { // This is getting connected to fromp; keep attributes // Note the method below too diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0f0aa5ad2..d5c821922 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1006,6 +1006,7 @@ class LinkDotFindVisitor : public AstNVisitor { AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::VAR, nodep->name(), VFlagChildDType(), dtypep); // Not dtype resolved yet newvarp->direction(VDirection::OUTPUT); + newvarp->lifetime(VLifetime::AUTOMATIC); newvarp->funcReturn(true); newvarp->trace(false); // Not user visible newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 35ea685db..90752c815 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -53,6 +53,7 @@ private: AstClass* m_classp; // Class we're inside AstNodeFTask* m_ftaskp; // Function or task we're inside AstNodeCoverOrAssert* m_assertp; // Current assertion + VLifetime m_lifetime; // Propagating lifetime int m_senitemCvtNum; // Temporary signal counter // METHODS @@ -67,14 +68,30 @@ private: UINFO(8, "MODULE " << nodep << endl); if (nodep->dead()) return; AstNodeModule* origModp = m_modp; + VLifetime origLifetime = m_lifetime; int origSenitemCvtNum = m_senitemCvtNum; { m_modp = nodep; m_senitemCvtNum = 0; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::STATIC; iterateChildren(nodep); } m_modp = origModp; m_senitemCvtNum = origSenitemCvtNum; + m_lifetime = origLifetime; + } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + AstClass* origClassp = m_classp; + VLifetime origLifetime = m_lifetime; + { + m_classp = nodep; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; + iterateChildren(nodep); + } + m_classp = origClassp; + m_lifetime = origLifetime; } virtual void visit(AstInitial* nodep) VL_OVERRIDE { iterateChildren(nodep); @@ -90,19 +107,12 @@ private: iterateChildren(nodep); m_assertp = NULL; } - virtual void visit(AstClass* nodep) VL_OVERRIDE { - AstClass* origClassp = m_classp; - { - m_classp = nodep; - iterateChildren(nodep); - } - m_classp = origClassp; - } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_classp && !nodep->isParam()) nodep->varType(AstVarType::MEMBER); if (m_classp && nodep->isParam()) nodep->v3error("Unsupported: class parameter"); if (m_ftaskp) nodep->funcLocal(true); + if (nodep->lifetime().isNone()) nodep->lifetime(m_lifetime); if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute m_modp->modPublic(true); // Avoid flattening if signals are exposed @@ -119,9 +129,15 @@ private: // NodeTask: Remember its name for later resolution // Remember the existing symbol table scope if (m_classp) nodep->classMethod(true); - m_ftaskp = nodep; - iterateChildren(nodep); + VLifetime origLifetime = m_lifetime; + { + if (!nodep->lifetime().isNone()) m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; + m_ftaskp = nodep; + iterateChildren(nodep); + } m_ftaskp = NULL; + m_lifetime = origLifetime; if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); } } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { @@ -472,13 +488,13 @@ private: public: // CONSTRUCTORS - explicit LinkResolveVisitor(AstNetlist* rootp) { + explicit LinkResolveVisitor(AstNetlist* rootp) + : m_lifetime(VLifetime::STATIC) { // Static outside a module/class m_classp = NULL; m_ftaskp = NULL; m_modp = NULL; m_assertp = NULL; m_senitemCvtNum = 0; - // iterate(rootp); } virtual ~LinkResolveVisitor() {} diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 805b10974..9385ef4b1 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -183,6 +183,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, nodep->addAttrsp(attrsp); nodep->ansi(m_pinAnsi); nodep->declTyped(m_varDeclTyped); + nodep->lifetime(m_varLifetime); if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varIO != VDirection::NONE) { nodep->declDirection(GRAMMARP->m_varIO); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 1a079b604..975ddaebe 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -59,6 +59,7 @@ struct V3ParseBisonYYSType { VSigning::en signstate; V3ErrorCode::en errcodeen; AstAttrType::en attrtypeen; + VLifetime::en lifetime; AstNode* nodep; diff --git a/src/verilog.y b/src/verilog.y index ea727f021..2274068e9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -50,6 +50,7 @@ public: AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) bool m_varDeclTyped; // Var got reg/wire for dedup check VDirection m_varIO; // Direction for next signal declaration (reg/wire/etc) + VLifetime m_varLifetime; // Static/Automatic for next signal AstVar* m_varAttrp; // Current variable for attribute adding AstRange* m_gateRangep; // Current range for gate declarations AstCase* m_caseAttrp; // Current case statement for attribute adding @@ -194,9 +195,11 @@ int V3ParseGrammar::s_modTypeImpNum = 0; #define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; GRAMMARP->m_pinAnsi=false; \ VARRESET(); VARDECL(decl); } // Not in a pinlist #define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE_NDECL(NULL); \ + GRAMMARP->m_varLifetime = VLifetime::NONE; \ GRAMMARP->m_varDeclTyped = false; } #define VARDECL(type) { GRAMMARP->setVarDecl(AstVarType::type); } #define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; } +#define VARLIFE(flag) { GRAMMARP->m_varLifetime = flag; } #define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); GRAMMARP->m_varDeclTyped = true; } #define VARDTYPE_NDECL(dtypep) { GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl) @@ -794,6 +797,8 @@ class AstSenTree; // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -852,6 +857,7 @@ packageFront: yPACKAGE lifetimeE idAny ';' { $$ = new AstPackage($3, *$3); $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" + $$->lifetime($2); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulep($$); @@ -967,6 +973,7 @@ modFront: // // any formal arguments, as the arguments must land in the new scope. yMODULE lifetimeE idAny { $$ = new AstModule($3,*$3); + $$->lifetime($2); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); @@ -985,6 +992,7 @@ importsAndParametersE: // IEEE: common part of module_declaration, interf udpFront: yPRIMITIVE lifetimeE idAny { $$ = new AstPrimitive($3, *$3); $$->inLibrary(true); + $$->lifetime($2); $$->modTrace(false); $$->addStmtp(new AstPragma($3, AstPragmaType::INLINE_MODULE)); GRAMMARP->m_tracingParse = false; @@ -1167,6 +1175,7 @@ intFront: yINTERFACE lifetimeE idAny/*new_interface*/ { $$ = new AstIface($3, *$3); $$->inLibrary(true); + $$->lifetime($2); PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -1253,6 +1262,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ { $$ = new AstModule($3,*$3); + $$->lifetime($2); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); @@ -1885,19 +1895,33 @@ data_declarationVarFront: // IEEE: part of data_declaration // // // Expanded: "constE yVAR lifetimeE data_type" // // implicit_type expanded into /*empty*/ or "signingE rangeList" - /**/ yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); } - | /**/ yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } - | /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } + /**/ yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | /**/ yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } + | /**/ yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARLIFE($2); + VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } // // // implicit_type expanded into /*empty*/ or "signingE rangeList" - | yCONST__ETC yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } - | yCONST__ETC yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } - | yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } + | yCONST__ETC yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } + | yCONST__ETC yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } + | yCONST__ETC yVAR lifetimeE signingE rangeList + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), + GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } // // // Expanded: "constE lifetimeE data_type" | /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } - | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARDTYPE($2); } - | yCONST__ETC lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } + | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARLIFE($1); VARDTYPE($2); } + | yCONST__ETC lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } // // = class_new is in variable_decl_assignment ; @@ -1905,9 +1929,11 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_prop // // VARRESET called before this rule // // yCONST is removed, added to memberQual rules // // implicit_type expanded into /*empty*/ or "signingE rangeList" - yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); } - | yVAR lifetimeE { VARRESET_NONLIST(VAR); } - | yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } + yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | yVAR lifetimeE { VARRESET_NONLIST(VAR); VARLIFE($2); } + | yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); + VARLIFE($2); } // // // Expanded: "constE lifetimeE data_type" | data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } @@ -3484,6 +3510,7 @@ list_of_argumentsE: // IEEE: [list_of_arguments] task_declaration: // ==IEEE: task_declaration yTASK lifetimeE taskId tfGuts yENDTASK endLabelE { $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); + $$->lifetime($2); GRAMMARP->endLabel($6,$$,$6); } ; @@ -3495,10 +3522,12 @@ task_prototype: // ==IEEE: task_prototype function_declaration: // IEEE: function_declaration + function_body_declaration yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); SYMP->popScope($$); GRAMMARP->endLabel($7,$$,$7); } | yFUNCTION lifetimeE funcIdNew funcIsolateE tfGuts yENDFUNCTION endLabelE { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); SYMP->popScope($$); GRAMMARP->endLabel($7,$$,$7); } ; @@ -3523,15 +3552,15 @@ method_prototype: | function_prototype { } ; -lifetimeE: // IEEE: [lifetime] - /* empty */ { } - | lifetime { } +lifetimeE: // IEEE: [lifetime] + /* empty */ { $$ = VLifetime::NONE; } + | lifetime { $$ = $1; } ; -lifetime: // ==IEEE: lifetime +lifetime: // ==IEEE: lifetime // // Note lifetime used by members is instead under memberQual - ySTATIC__ETC { BBUNSUP($1, "Unsupported: Static in this context"); } - | yAUTOMATIC { } + ySTATIC__ETC { $$ = VLifetime::STATIC; BBUNSUP($1, "Unsupported: Static in this context"); } + | yAUTOMATIC { $$ = VLifetime::AUTOMATIC; } ; taskId: @@ -5481,10 +5510,12 @@ class_declaration: // ==IEEE: part of class_declaration classFront: // IEEE: part of class_declaration classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); + $$->lifetime($3); SYMP->pushNew($$); } // // IEEE: part of interface_class_declaration | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); + $$->lifetime($3); SYMP->pushNew($$); BBUNSUP($2, "Unsupported: interface classes"); } ;