diff --git a/Changes b/Changes index bfbe4c93f..de7add07a 100644 --- a/Changes +++ b/Changes @@ -16,8 +16,12 @@ indicates the contributor was also the author of the fix; Thanks! *** Support "program". +*** Support "package" and $unit. + *** Support typedef. [Donal Casey] +*** Add VARHIDDEN warning when signal name hides module name. + * Verilator 3.720 2009/10/26 ** Support little endian bit vectors ("reg [0:2] x;"). diff --git a/src/V3Ast.h b/src/V3Ast.h index 9c001b5e3..3ced513c8 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1122,17 +1122,18 @@ private: bool m_lvalue; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep; // Varscope for hierarchy + AstPackage* m_packagep; // Package hierarchy string m_name; // Name of variable string m_hiername; // Scope converted into name-> for emitting bool m_hierThis; // Hiername points to "this" function public: AstNodeVarRef(FileLine* fl, const string& name, bool lvalue) : AstNodeMath(fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL), - m_name(name), m_hierThis(false) { + m_packagep(NULL), m_name(name), m_hierThis(false) { } AstNodeVarRef(FileLine* fl, const string& name, AstVar* varp, bool lvalue) : AstNodeMath(fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL), - m_name(name), m_hierThis(false) { + m_packagep(NULL), m_name(name), m_hierThis(false) { // May have varp==NULL if (m_varp) widthSignedFrom((AstNode*)m_varp); } @@ -1152,6 +1153,8 @@ public: void hiername(const string& hn) { m_hiername = hn; } bool hierThis() const { return m_hierThis; } void hierThis(bool flag) { m_hierThis = flag; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep=nodep; } // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { } @@ -1251,10 +1254,11 @@ private: string m_name; // Name of variable string m_dotted; // Dotted part of scope to task or "" string m_inlinedDots; // Dotted hierarchy flattened out + AstPackage* m_packagep; // Package hierarchy public: AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp) :AstNode(fl) - , m_taskp(NULL) { + , m_taskp(NULL), m_packagep(NULL) { setOp1p(namep); addNOp2p(pinsp); } ASTNODE_BASE_FUNCS(NodeFTaskRef) @@ -1272,6 +1276,8 @@ public: void taskp(AstNodeFTask* taskp) { m_taskp=taskp; } virtual void name(const string& name) { m_name = name; } void dotted(const string& name) { m_dotted = name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep=nodep; } // op1 = namep AstNode* namep() const { return op1p(); } // op2 = Pin interconnection list diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 235ec348f..10e4c62dc 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -230,11 +230,12 @@ public: struct AstRefDType : public AstNodeDType { AstTypedef* m_defp; string m_name; + AstPackage* m_packagep; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) - : AstNodeDType(fl), m_defp(NULL), m_name(name) {} + : AstNodeDType(fl), m_defp(NULL), m_name(name), m_packagep(NULL) {} AstRefDType(FileLine* fl, AstTypedef* defp) - : AstNodeDType(fl), m_defp(defp), m_name(defp->name()) { + : AstNodeDType(fl), m_defp(defp), m_name(defp->name()), m_packagep(NULL) { widthSignedFrom(defp); } ASTNODE_NODE_FUNCS(RefDType, REFDTYPE) @@ -261,6 +262,8 @@ public: AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable AstTypedef* defp() const { return m_defp; } void defp(AstTypedef* nodep) { m_defp=nodep; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep=nodep; } }; //###################################################################### @@ -763,6 +766,15 @@ struct AstModule : public AstNodeModule { ASTNODE_NODE_FUNCS(Module, MODULE) }; +struct AstPackage : public AstNodeModule { + // A package declaration + AstPackage(FileLine* fl, const string& name) + : AstNodeModule (fl,name) {} + ASTNODE_NODE_FUNCS(Package, PACKAGE) + static string dollarUnitName() { return AstNode::encodeName("$unit"); } + bool isDollarUnit() const { return name() == dollarUnitName(); } +}; + struct AstCell : public AstNode { // A instantiation cell or interface call (don't know which until link) private: diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index a74181e69..687c29a9b 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -22,6 +22,8 @@ // Remove any unreferenced modules // Remove any unreferenced variables // +// NOTE: If redo this, consider using maybePointedTo()/broken() ish scheme +// instead of needing as many visitors. //************************************************************************* #include "config_build.h" @@ -104,6 +106,21 @@ private: if (nodep->varp()) { nodep->varp()->user1(nodep->varp()->user1() + 1); } + if (nodep->packagep()) { + nodep->packagep()->user1(nodep->packagep()->user1() + 1); + } + } + virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (nodep->packagep()) { + nodep->packagep()->user1(nodep->packagep()->user1() + 1); + } + } + virtual void visit(AstRefDType* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (nodep->packagep()) { + nodep->packagep()->user1(nodep->packagep()->user1() + 1); + } } virtual void visit(AstVarScope* nodep, AstNUser*) { nodep->iterateChildren(*this); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 4c0d9be09..265dafe22 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -101,7 +101,7 @@ private: nodep->name(name); nodep->iterateChildren(*this); } - if (nodep->modp()->user1p()) { // Marked with inline request + if (nodep->modp()->user1()) { // Marked with inline request if (m_cellp) nodep->v3error("Cloning should have already been done bottom-up"); UINFO(5," Inline CELL "<castPackage()) doit = false; UINFO(4, " Inline="<taskp(NULL); + if (!nodep->packagep()) nodep->taskp(NULL); nodep->iterateChildren(*this); } // Nop's to speed up the loop @@ -430,7 +432,7 @@ void V3Inline::inlineAll(AstNetlist* nodep) { AstNodeModule* nextmodp; for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) { nextmodp = modp->nextp()->castNodeModule(); - if (modp->user1p()) { // Was inlined + if (modp->user1()) { // Was inlined modp->unlinkFrBack()->deleteTree(); modp=NULL; } } diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 78d66e7ae..4ce8d4740 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -48,14 +48,15 @@ class LinkVisitor : public AstNVisitor { private: // NODE STATE // Entire netlist: - // AstNodeModule::user1p() // V3SymTable* Module's Symbol table - // AstNodeFTask::user1p() // V3SymTable* Local Symbol table - // AstBegin::user1p() // V3SymTable* Local Symbol table + // AstVar/Module/Task::user1() // AstPackage* Set if inside a package // AstVar::user2p() // bool True if port set for this variable // AstVar/Module::user3p() // V3SymTable* Table used to create this variable - AstUser1InUse m_inuser1; + // AstNodeModule::user4p() // V3SymTable* Module's Symbol table + // AstNodeFTask::user4p() // V3SymTable* Local Symbol table + // AstBegin::user4p() // V3SymTable* Local Symbol table AstUser2InUse m_inuser2; AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; // ENUMS enum IdState { // Which loop through the tree @@ -65,7 +66,8 @@ private: // STATE // Below state needs to be preserved between each module call. - AstNodeModule* m_modp; // Current module + AstPackage* m_packagep; // Current package + AstNodeModule* m_modp; // Current module AstNodeFTask* m_ftaskp; // Current function/task IdState m_idState; // Id linking mode (find or resolve) int m_paramNum; // Parameter number, for position based connection @@ -85,37 +87,52 @@ private: // METHODS V3SymTable* symsFindNew(AstNode* nodep, V3SymTable* upperVarsp) { // Find or create symbol table for this node - if (V3SymTable* symsp = nodep->user1p()->castSymTable()) { + if (V3SymTable* symsp = nodep->user4p()->castSymTable()) { return symsp; } else { V3SymTable* symsp = new V3SymTable(nodep, upperVarsp); m_delSymps.push_back(symsp); - nodep->user1p(symsp); + nodep->user4p(symsp); return symsp; } } + V3SymTable* symsFind(AstNode* nodep) { + // Find or create symbol table for this node + if (V3SymTable* symsp = nodep->user4p()->castSymTable()) { + return symsp; + } else { + nodep->v3fatalSrc("Symbol table not found looking up symbol"); + return NULL; + } + } void symsInsert(const string& name, AstNode* nodep) { // Insert into symbol table, and remember what table the node is in m_curVarsp->insert(name, nodep); nodep->user3p(m_curVarsp); + nodep->user1p(m_packagep); + } + + AstPackage* packageFor(AstNode* nodep) { + if (nodep) return nodep->user1p()->castNode()->castPackage(); // Loaded by symsInsert + else return NULL; } void linkVarName (AstVarRef* nodep) { if (!nodep->varp()) { AstVar* varp = m_curVarsp->findIdUpward(nodep->name())->castVar(); nodep->varp(varp); + nodep->packagep(packageFor(varp)); } } - const char* nodeTextType(AstNode* nodep) { - const char* what = "node"; - if (nodep->castVar()) what = "variable"; - else if (nodep->castCell()) what = "cell"; - else if (nodep->castTask()) what = "task"; - else if (nodep->castFunc()) what = "function"; - else if (nodep->castBegin()) what = "block"; - return what; + string nodeTextType(AstNode* nodep) { + if (nodep->castVar()) return "variable"; + else if (nodep->castCell()) return "cell"; + else if (nodep->castTask()) return "task"; + else if (nodep->castFunc()) return "function"; + else if (nodep->castBegin()) return "block"; + else return nodep->prettyTypeName(); } string ucfirst(const string& text) { @@ -171,13 +188,13 @@ private: // VISITs virtual void visit(AstNetlist* nodep, AstNUser*) { - // Look at all modules, and store pointers to all module names - for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) { - symsFindNew(modp, NULL); - } + // Top scope + m_curVarsp = symsFindNew(nodep, NULL); // And recurse... + // Recurse... m_idState = ID_FIND; nodep->iterateChildren(*this); + if (debug()==9) m_curVarsp->dump(cout,"-curvars: ",true/*user4p_is_table*/); m_idState = ID_PARAM; nodep->iterateChildren(*this); m_idState = ID_RESOLVE; @@ -188,18 +205,30 @@ private: virtual void visit(AstNodeModule* nodep, AstNUser*) { // Module: Create sim table for entire module and iterate UINFO(2,"Link Module: "<v3fatalSrc("NULL"); - m_cellVarsp = NULL; - m_paramNum = 0; - m_beginNum = 0; - m_modBeginNum = 0; - nodep->iterateChildren(*this); - // Prep for next - m_curVarsp = NULL; - m_modp = NULL; + V3SymTable* upperVarsp = m_curVarsp; + { + m_modp = nodep; + if (!m_curVarsp) nodep->v3fatalSrc("NULL"); + if (nodep->castPackage()) m_packagep = nodep->castPackage(); + if (m_packagep && m_packagep->isDollarUnit()) { // $unit goes on "top" + nodep->user4p(m_curVarsp); + // Don't insert dunit itself, or symtable->dump will loop-recurse + } else { + findAndInsertAndCheck(nodep, nodep->name()); + m_curVarsp = symsFindNew(nodep, upperVarsp); + UINFO(9, "New module scope "<iterateChildren(*this); + // Prep for next + m_modp = NULL; + m_packagep = NULL; + } + m_curVarsp = upperVarsp; } virtual void visit(AstGenerate* nodep, AstNUser*) { @@ -231,12 +260,12 @@ private: bool ins=false; if (!foundp) { ins=true; - } else if (!findvarp) { + } else if (!findvarp && m_curVarsp->findIdFlat(nodep->name())) { nodep->v3error("Unsupported in C: Variable has same name as " <prettyName()); } else if (findvarp != nodep) { - UINFO(4,"DupVar: "<user3p() == m_curVarsp) { // Only when on same level + UINFO(4,"DupVar: "<user3p() == m_curVarsp) { // Only when on same level if ((findvarp->isIO() && nodep->isSignal()) || (findvarp->isSignal() && nodep->isIO())) { findvarp->combineType(nodep); @@ -249,9 +278,9 @@ private: } else { // User can disable the message at either point if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN) - && !findvarp->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { + && !foundp->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { nodep->v3warn(VARHIDDEN,"Declaration of signal hides declaration in upper scope: "<name()); - findvarp->v3warn(VARHIDDEN,"... Location of original declaration"); + foundp->v3warn(VARHIDDEN,"... Location of original declaration"); } ins = true; } @@ -368,9 +397,15 @@ private: // NodeFTaskRef: Resolve its reference if (m_idState==ID_RESOLVE && !nodep->taskp()) { if (nodep->dotted() == "") { - AstNodeFTask* taskp = m_curVarsp->findIdUpward(nodep->name())->castNodeFTask(); + AstNodeFTask* taskp; + if (nodep->packagep()) { + taskp = symsFind(nodep->packagep())->findIdUpward(nodep->name())->castNodeFTask(); + } else { + taskp = m_curVarsp->findIdUpward(nodep->name())->castNodeFTask(); + } if (!taskp) { nodep->v3error("Can't find definition of task/function: "<prettyName()); } nodep->taskp(taskp); + nodep->packagep(packageFor(taskp)); } } nodep->iterateChildren(*this); @@ -393,9 +428,15 @@ private: virtual void visit(AstRefDType* nodep, AstNUser*) { // Resolve its reference if (m_idState==ID_RESOLVE && !nodep->defp()) { - AstTypedef* defp = m_curVarsp->findIdUpward(nodep->name())->castTypedef(); + AstTypedef* defp; + if (nodep->packagep()) { + defp = symsFind(nodep->packagep())->findIdFlat(nodep->name())->castTypedef(); + } else { + defp = m_curVarsp->findIdUpward(nodep->name())->castTypedef(); + } if (!defp) { nodep->v3error("Can't find typedef: "<prettyName()); } nodep->defp(defp); + nodep->packagep(packageFor(defp)); } nodep->iterateChildren(*this); } @@ -411,12 +452,14 @@ private: } else { // Need to pass the module info to this cell, so we can link up the pin names - m_cellVarsp = nodep->modp()->user1p()->castSymTable(); - UINFO(4,"(Backto) Link Cell: "<dumpTree(cout,"linkcell:"); } - //if (debug()) { nodep->modp()->dumpTree(cout,"linkcemd:"); } - nodep->iterateChildren(*this); - m_cellVarsp = NULL; + if (m_idState==ID_RESOLVE) { + m_cellVarsp = nodep->modp()->user4p()->castSymTable(); + UINFO(4,"(Backto) Link Cell: "<dumpTree(cout,"linkcell:"); } + //if (debug()) { nodep->modp()->dumpTree(cout,"linkcemd:"); } + nodep->iterateChildren(*this); + m_cellVarsp = NULL; + } } // Parent module inherits child's publicity // This is done bottom up in the LinkBotupVisitor stage @@ -460,6 +503,7 @@ private: virtual void visit(AstPin* nodep, AstNUser*) { // Pin: Link to submodule's pin + // ONLY CALLED by AstCell during ID_RESOLVE state if (!m_cellVarsp) nodep->v3fatalSrc("Pin not under cell?\n"); if (m_idState==ID_RESOLVE && !nodep->modVarp()) { AstVar* refp = m_cellVarsp->findIdFlat(nodep->name())->castVar(); @@ -523,6 +567,7 @@ public: m_cellVarsp = NULL; m_modp = NULL; m_ftaskp = NULL; + m_packagep = NULL; m_paramNum = 0; m_beginNum = 0; m_modBeginNum = 0; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index a2df93419..5d2ef2483 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -210,6 +210,7 @@ public: // METHODS LinkDotCellVertex* insertTopCell(AstNodeModule* nodep, const string& scopename) { + // Only called on the module at the very top of the hierarchy UINFO(9," INSERTcell "<user1p(vxp); @@ -382,6 +383,11 @@ private: // VISITs virtual void visit(AstNetlist* nodep, AstNUser*) { + // Process $unit or other packages + // Not needed - dotted references not allowed from inside packages + //for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) { + // if (nodep->castPackage()) {}} + // The first module in the list is always the top module (sorted before this is called). // This may not be the module with isTop() set, as early in the steps, // wrapTop may have not been created yet. @@ -402,6 +408,8 @@ private: } } virtual void visit(AstNodeModule* nodep, AstNUser*) { + // Called on top module from Netlist, other modules from the cell creating them, + // and packages UINFO(8," "<packagep()) { + // References into packages don't care about cell hierarchy. + } else if (!m_cellVxp) { UINFO(9,"Dead module for "<taskp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later. } else { diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 410413dd1..753ff737a 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -128,4 +128,23 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) { } } } + + wrapTopPackages(netlistp, newmodp); +} + +void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp, AstNodeModule* newmodp) { + // Instantiate all packages under the top wrapper + // This way all later SCOPE based optimizations can ignore packages + for (AstNodeModule* modp = netlistp->modulesp(); modp; modp=modp->nextp()->castNodeModule()) { + if (modp->castPackage()) { + AstCell* cellp = new AstCell(modp->fileline(), + // Could add __03a__03a="::" to prevent conflict + // with module names/"v" + modp->name(), + modp->name(), + NULL, NULL, NULL); + cellp->modp(modp); + newmodp->addStmtp(cellp); + } + } } diff --git a/src/V3LinkLevel.h b/src/V3LinkLevel.h index 2e23670fa..4493a39b3 100644 --- a/src/V3LinkLevel.h +++ b/src/V3LinkLevel.h @@ -30,6 +30,8 @@ //============================================================================ class V3LinkLevel { +private: + static void wrapTopPackages(AstNetlist* nodep, AstNodeModule* newmodp); public: static void modSortByLevel(); static void wrapTop(AstNetlist* nodep); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 2bcf6b4e0..a77dda8a6 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -45,7 +45,7 @@ typedef enum { uniq_NONE, uniq_UNIQUE, uniq_PRIORITY } V3UniqState; struct V3ParseBisonYYSType { FileLine* fl; - //V3SymTable* scp; // Symbol table scope for future lookups + AstNode* scp; // Symbol table scope for future lookups union { V3Number* nump; string* strp; @@ -64,8 +64,10 @@ struct V3ParseBisonYYSType { AstNodeModule* modulep; AstNodeDType* dtypep; AstNodeFTask* ftaskp; + AstNodeFTaskRef* ftaskrefp; AstNodeSenItem* senitemp; AstNodeVarRef* varnodep; + AstPackage* packagep; AstParseRef* parserefp; AstPin* pinp; AstRange* rangep; @@ -88,7 +90,8 @@ private: // MEMBERS static int s_anonNum; // Number of next anonymous object V3SymTable* m_symTableNextId; // Symbol table for next lexer lookup - V3SymTable* m_symCurrentp; // Node with active symbol table for additions/lookups + V3SymTable* m_symCurrentp; // Active symbol table for additions/lookups + V3SymTable* m_symRootp; // Root symbol table SymStack m_sympStack; // Stack of nodes with symbol tables SymStack m_symsp; // All symbol tables, to cleanup @@ -102,6 +105,7 @@ private: public: V3SymTable* nextId() const { return m_symTableNextId; } V3SymTable* symCurrentp() const { return m_symCurrentp; } + V3SymTable* symRootp() const { return m_symRootp; } V3SymTable* findNewTable(AstNode* nodep, V3SymTable* parentp) { if (!nodep->user4p()) { @@ -112,9 +116,14 @@ public: return getTable(nodep); } void nextId(AstNode* entp) { - if (entp) { UINFO(9,"symTableNextId under "<type().ascii()<type().ascii()< AstVarScope replacement for this variable - // AstVarRef::user2p -> bool. True indicates already processed + // AstTask::user2p -> AstTask*. Replacement task AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; @@ -69,15 +69,15 @@ private: AstNodeModule* modp = nodep->topModulep(); if (!modp) { nodep->v3error("No root module specified"); return; } // Operate starting at the top of the hierarchy - AstNode::user2ClearTree(); m_aboveCellp = NULL; m_aboveScopep = NULL; modp->accept(*this); } virtual void visit(AstNodeModule* nodep, AstNUser*) { // Create required blocks and add to module - string scopename = (!m_aboveScopep ? "TOP" - : (m_aboveScopep->name()+"."+m_aboveCellp->name())); + string scopename; + if (!m_aboveScopep) scopename = "TOP"; + else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name(); UINFO(4," MOD AT "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -136,6 +137,7 @@ private: // Add to list of blocks under this scope UINFO(4," Move "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -143,6 +145,7 @@ private: // Add to list of blocks under this scope UINFO(4," Move "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -150,6 +153,7 @@ private: // Add to list of blocks under this scope UINFO(4," Move "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -157,6 +161,7 @@ private: // Add to list of blocks under this scope UINFO(4," Move "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -164,6 +169,7 @@ private: // Add to list of blocks under this scope UINFO(4," Move "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* } @@ -171,8 +177,9 @@ private: // Add to list of blocks under this scope UINFO(4," CFUNC "<cloneTree(false); - clonep->scopep(m_scopep); + nodep->user2p(clonep); m_scopep->addActivep(clonep); + clonep->scopep(m_scopep); // We iterate under the *clone* clonep->iterateChildren(*this); } @@ -180,6 +187,7 @@ private: // Add to list of blocks under this scope UINFO(4," FTASK "<cloneTree(false); + nodep->user2p(clonep); m_scopep->addActivep(clonep); // We iterate under the *clone* clonep->iterateChildren(*this); @@ -196,21 +204,10 @@ private: virtual void visit(AstVarRef* nodep, AstNUser*) { // VarRef needs to point to VarScope // Make sure variable has made user1p. - if (!nodep->user2()) { - nodep->varp()->accept(*this); - AstVarScope* varscp = (AstVarScope*)nodep->varp()->user1p(); - if (!varscp) nodep->v3fatalSrc("Can't locate varref scope"); - nodep->varScopep(varscp); - } - } - virtual void visit(AstVarXRef* nodep, AstNUser*) { - // The crossrefs are dealt with in V3LinkDot - nodep->varp(NULL); - } - virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { - // The crossrefs are dealt with in V3LinkDot - nodep->taskp(NULL); - nodep->iterateChildren(*this); + nodep->varp()->accept(*this); + AstVarScope* varscp = (AstVarScope*)nodep->varp()->user1p(); + if (!varscp) nodep->v3fatalSrc("Can't locate varref scope"); + nodep->varScopep(varscp); } virtual void visit(AstScopeName* nodep, AstNUser*) { // If there's a %m in the display text, we add a special node that will contain the name() @@ -306,6 +303,27 @@ private: movedDeleteOrIterate(nodep); } + virtual void visit(AstVarXRef* nodep, AstNUser*) { + // The crossrefs are dealt with in V3LinkDot + nodep->varp(NULL); + } + virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { + // The crossrefs are dealt with in V3LinkDot + UINFO(9," Old pkg-taskref "<packagep()) { + // Point to the clone + if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked"); + AstNodeFTask* newp = nodep->taskp()->user2p()->castNode()->castNodeFTask(); + if (!newp) nodep->v3fatalSrc("No clone for package function"); + nodep->taskp(newp); + UINFO(9," New pkg-taskref "<taskp(NULL); + UINFO(9," New pkg-taskref "<iterateChildren(*this); + } + //-------------------- // Default virtual void visit(AstNode* nodep, AstNUser*) { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index e45bd8b76..6e09e0df8 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -194,6 +194,7 @@ private: m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL; } // We make multiple edges if a task is called multiple times from another task. + if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked task"); new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp())); } virtual void visit(AstNodeFTask* nodep, AstNUser*) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index c34f30c1d..b76d42aff 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -186,6 +186,7 @@ void process () { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree")); // Add top level wrapper with instance pointing to old top + // Move packages to under new top // Must do this after we know the width of any parameters // We also do it after coverage/assertion insertion so we don't 'cover' the top level. V3LinkLevel::wrapTop(v3Global.rootp()); diff --git a/src/verilog.l b/src/verilog.l index b84b929ee..0bcd33dcd 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -357,6 +357,7 @@ escid \\[^ \t\f\r\n]+ "$onehot0" { FL; return yD_ONEHOT0; } "$warning" { FL; return yD_WARNING; } /* SV2005 Keywords */ + "$unit" { FL; return yD_UNIT; } /* Yes, a keyword, not task */ "always_comb" { FL; return yALWAYS; } "always_ff" { FL; return yALWAYS; } "always_latch" { FL; return yALWAYS; } @@ -365,6 +366,7 @@ escid \\[^ \t\f\r\n]+ "clocking" { FL; return yCLOCKING; } "do" { FL; return yDO; } "endclocking" { FL; return yENDCLOCKING; } + "endpackage" { FL; return yENDPACKAGE; } "endprogram" { FL; return yENDPROGRAM; } "endproperty" { FL; return yENDPROPERTY; } "final" { FL; return yFINAL; } @@ -372,6 +374,7 @@ escid \\[^ \t\f\r\n]+ "int" { FL; return yINT; } "logic" { FL; return yLOGIC; } "longint" { FL; return yLONGINT; } + "package" { FL; return yPACKAGE; } "priority" { FL; return yPRIORITY; } "program" { FL; return yPROGRAM; } "shortint" { FL; return ySHORTINT; } @@ -385,7 +388,6 @@ escid \\[^ \t\f\r\n]+ /* Generic unsupported warnings */ /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */ "$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "$unit" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "alias" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } @@ -403,7 +405,6 @@ escid \\[^ \t\f\r\n]+ "endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "endpackage" { 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); } @@ -426,7 +427,6 @@ escid \\[^ \t\f\r\n]+ "modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "package" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "packed" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "pure" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } @@ -888,13 +888,13 @@ int V3ParseImp::lexToken() { //if (debug()>=9) SYMP->symCurrentp()->dump(cout," -findtree: ",true); scp = SYMP->symCurrentp()->findIdUpward(*(yylval.strp)); } + yylval.scp = scp; if (scp) { UINFO(7," lexToken: Found "<scp = scp; if (scp->castTypedef()) token = yaID__aTYPE; else if (scp->castTypedefFwd()) token = yaID__aTYPE; + else if (scp->castPackage()) token = yaID__aPACKAGE; //UNSUP else if (scp->castClass()) token = yaID__aCLASS; - //UNSUP else if (scp->castPackage()) token = yaID__aPACKAGE; //UNSUP else if (scp->castCoverGroup()) token = yaID__aCOVERGROUP; else token = yaID__ETC; } else { // Not found diff --git a/src/verilog.y b/src/verilog.y index 3cbecdd92..4b682ef3a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -44,6 +44,10 @@ extern void yyerrorf(const char* format, ...); //====================================================================== // Statics (for here only) +#define PARSEP V3ParseImp::parsep() +#define SYMP PARSEP->symp() +#define GRAMMARP V3ParseGrammar::singletonp() + class V3ParseGrammar { public: bool m_impliedDecl; // Allow implied wire declarations @@ -96,6 +100,18 @@ public: if (m_varDTypep) { m_varDTypep->deleteTree(); m_varDTypep=NULL; } // It was cloned, so this is safe. m_varDTypep = dtypep; } + AstPackage* unitPackage(FileLine* fl) { + // Find one made earlier? + AstPackage* pkgp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName())->castPackage(); + if (!pkgp) { + 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 + PARSEP->rootp()->addModulep(pkgp); + SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global + } + return pkgp; + } AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp) { if (!rangesp) { return dtypep; @@ -117,10 +133,6 @@ public: string deQuote(FileLine* fileline, string text); }; -#define PARSEP V3ParseImp::parsep() -#define SYMP PARSEP->symp() -#define GRAMMARP V3ParseGrammar::singletonp() - const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT; @@ -166,6 +178,7 @@ class AstSenTree; // package_identifier, type_identifier, variable_identifier, %token yaID__ETC "IDENTIFIER" %token yaID__LEX "IDENTIFIER-in-lex" +%token yaID__aPACKAGE "PACKAGE-IDENTIFIER" %token yaID__aTYPE "TYPE-IDENTIFIER" // IEEE: integral_number @@ -246,6 +259,7 @@ class AstSenTree; %token yENDFUNCTION "endfunction" %token yENDGENERATE "endgenerate" %token yENDMODULE "endmodule" +%token yENDPACKAGE "endpackage" %token yENDPROGRAM "endprogram" %token yENDPROPERTY "endproperty" %token yENDSPECIFY "endspecify" @@ -275,6 +289,7 @@ class AstSenTree; %token yNOTIF1 "notif1" %token yOR "or" %token yOUTPUT "output" +%token yPACKAGE "package" %token yPARAMETER "parameter" %token yPOSEDGE "posedge" %token yPRIORITY "priority" @@ -337,6 +352,7 @@ class AstSenTree; %token yD_STIME "$stime" %token yD_STOP "$stop" %token yD_TIME "$time" +%token yD_UNIT "$unit" %token yD_UNSIGNED "$unsigned" %token yD_WARNING "$warning" %token yD_WRITE "$write" @@ -472,6 +488,11 @@ 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 +// Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -508,8 +529,8 @@ description: // ==IEEE: description module_declaration { } //UNSUP interface_declaration { } | program_declaration { } - //UNSUP package_declaration { } - //UNSUP package_item { } + | package_declaration { } + | package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); } //UNSUP bind_directive { } // unsupported // IEEE: config_declaration | error { } @@ -523,6 +544,38 @@ timeunits_declaration: // ==IEEE: timeunits_declaration //********************************************************************** // Packages +package_declaration: // ==IEEE: package_declaration + packageFront package_itemListE yENDPACKAGE endLabelE + { $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc + if ($2) $1->addStmtp($2); + SYMP->popScope($1); } + ; + +packageFront: + yPACKAGE idAny ';' + { $$ = new AstPackage($1,*$2); + $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" + $$->modTrace(v3Global.opt.trace()); + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); } + ; + +package_itemListE: // IEEE: [{ package_item }] + /* empty */ { $$ = NULL; } + | package_itemList { $$ = $1; } + ; + +package_itemList: // IEEE: { package_item } + package_item { $$ = $1; } + | package_itemList package_item { $$ = $1->addNextNull($2); } + ; + +package_item: // ==IEEE: package_item + package_or_generate_item_declaration { $$ = $1; } + //UNSUP anonymous_program { $$ = $1; } + | timeunits_declaration { $$ = $1; } + ; + package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration net_declaration { $$ = $1; } | data_declaration { $$ = $1; } @@ -1762,14 +1815,17 @@ for_step: // IEEE: for_step //************************************************ // Functions/tasks -taskRef: // IEEE: part of tf_call +taskRef: // IEEE: part of tf_call idDotted { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),NULL);} | idDotted '(' list_of_argumentsE ')' { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),$3);} + //UNSUP: package_scopeIdFollows idDotted { $$ = new AstTaskRef(CRELINE(),new AstParseRef($2->fileline(), AstParseRefExp::TASK, $2),NULL);} + //UNSUP: package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { $$ = new AstTaskRef(CRELINE(),new AstParseRef($2->fileline(), AstParseRefExp::TASK, $2),$4);} //UNSUP: idDotted is really just id to allow dotted method calls ; -funcRef: // IEEE: part of tf_call +funcRef: // IEEE: part of tf_call idDotted '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2,new AstParseRef($1->fileline(), AstParseRefExp::FUNC, $1), $3); } + | package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { $$ = new AstFuncRef($3,new AstParseRef($2->fileline(), AstParseRefExp::FUNC, $2), $4); $$->packagep($1); } //UNSUP: idDotted is really just id to allow dotted method calls ; @@ -2448,8 +2504,8 @@ id: idAny: // Any kind of identifier //UNSUP yaID__aCLASS { $$ = $1; $$=$1; } //UNSUP yaID__aCOVERGROUP { $$ = $1; $$=$1; } - //UNSUP yaID__aPACKAGE { $$ = $1; $$=$1; } - yaID__aTYPE { $$ = $1; $$=$1; } + yaID__aPACKAGE { $$ = $1; $$=$1; } + | yaID__aTYPE { $$ = $1; $$=$1; } | yaID__ETC { $$ = $1; $$=$1; } ; @@ -2605,22 +2661,31 @@ immediate_assert_statement: // ==IEEE: immediate_assert_statement // must be included in the rules below. // Each of these must end with {symsPackageDone | symsClassDone} -ps_id_etc: // package_scope + general id - package_scopeIdFollowsE id { $$ = $2; } +ps_id_etc: // package_scope + general id + package_scopeIdFollowsE id { } ; ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier // Even though we looked up the type and have a AstNode* to it, // we can't fully resolve it because it may have been just a forward definition. - package_scopeIdFollowsE yaID__aTYPE { $$ = new AstRefDType($1, *$2); } + package_scopeIdFollowsE yaID__aTYPE { $$ = new AstRefDType($2, *$2); $$->castRefDType()->packagep($1); } ; //=== Below rules assume special scoping per above -package_scopeIdFollowsE: // IEEE: [package_scope] +package_scopeIdFollowsE: // IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package - /* empty */ { } - //UNSUP package_scopeIdFollows { UNSUP } + /* empty */ { $$ = NULL; } + | package_scopeIdFollows { $$ = $1; } + ; + +package_scopeIdFollows: // IEEE: package_scope + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token + yD_UNIT { SYMP->nextId(PARSEP->rootp()); } + /*cont*/ yP_COLONCOLON { $$ = GRAMMARP->unitPackage($1); } + | yaID__aPACKAGE { SYMP->nextId($1); } + /*cont*/ yP_COLONCOLON { $$ = $1->castPackage(); } ; //************************************************ diff --git a/test_regress/t/t_flag_bboxsys.v b/test_regress/t/t_flag_bboxsys.v index 789a29d3e..fc75228a2 100644 --- a/test_regress/t/t_flag_bboxsys.v +++ b/test_regress/t/t_flag_bboxsys.v @@ -3,7 +3,7 @@ // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2008 by Wilson Snyder. -module a; +module t; reg a; initial begin $unknown_sys_task_call_to_be_bbox("blah"); diff --git a/test_regress/t/t_inst_mnpipe.v b/test_regress/t/t_inst_mnpipe.v index 4d4973aca..1839e7bec 100644 --- a/test_regress/t/t_inst_mnpipe.v +++ b/test_regress/t/t_inst_mnpipe.v @@ -63,9 +63,9 @@ module MxN_pipeline (in, out, clk); //wire [M*(N-1):1] t; //dffn #(M) p[N:1] ({out,t},{t,in},clk); - wire [M*(N-1):1] t; + wire [M*(N-1):1] w; wire [M*N:1] q; - dffn #(M) p[N:1] (q,{t,in},clk); - assign {out,t} = q; + dffn #(M) p[N:1] (q,{w,in},clk); + assign {out,w} = q; endmodule diff --git a/test_regress/t/t_mem_fifo.v b/test_regress/t/t_mem_fifo.v index a7285273d..a84389d04 100644 --- a/test_regress/t/t_mem_fifo.v +++ b/test_regress/t/t_mem_fifo.v @@ -87,7 +87,9 @@ module fifo (/*AUTOARG*/ reg [65:0] outData; + // verilator lint_off VARHIDDEN reg [65:0] fifo[0:fifoDepth-1]; + // verilator lint_on VARHIDDEN reg [`PTRBITSM1:0] wrPtr, rdPtr; //reg [65:0] temp; diff --git a/test_regress/t/t_package.pl b/test_regress/t/t_package.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_package.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_package.v b/test_regress/t/t_package.v new file mode 100644 index 000000000..2f4f531d8 --- /dev/null +++ b/test_regress/t/t_package.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +typedef int unit_type_t; + +function [3:0] unit_plusone(input [3:0] i); + unit_plusone = i+1; +endfunction + +package p; + typedef int package_type_t; + function [3:0] plusone(input [3:0] i); + plusone = i+1; + endfunction +endpackage + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + unit_type_t vu; + $unit::unit_type_t vdu; + p::package_type_t vp; + + initial begin + if (unit_plusone(1) !== 2) $stop; + if ($unit::unit_plusone(1) !== 2) $stop; + if (p::plusone(1) !== 2) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_typedef_port.v b/test_regress/t/t_typedef_port.v index 4245f7d1b..0bc651432 100644 --- a/test_regress/t/t_typedef_port.v +++ b/test_regress/t/t_typedef_port.v @@ -3,7 +3,7 @@ // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2009 by Wilson Snyder. -//UNSUPtypedef reg [2:0] three_t; +typedef reg [2:0] threeansi_t; module t (/*AUTOARG*/ // Inputs @@ -11,7 +11,7 @@ module t (/*AUTOARG*/ ); input clk; - typedef reg [2:0] three_t; //UNSUP remove + typedef reg [2:0] three_t; integer cyc=0; reg [63:0] crc; @@ -22,6 +22,7 @@ module t (/*AUTOARG*/ /*AUTOWIRE*/ // Beginning of automatic wires (for undeclared instantiated-module outputs) + threeansi_t outa; // From testa of TestAnsi.v three_t outna; // From test of TestNonAnsi.v // End of automatics @@ -32,14 +33,12 @@ module t (/*AUTOARG*/ .clk (clk), .in (in)); -//UNSUP -// TestAnsi testa (// Outputs -// .out (outa), -// /*AUTOINST*/ -// // Inputs -// .clk (clk), -// .in (in)); - wire [2:0] outa = outna; + TestAnsi testa (// Outputs + .out (outa), + /*AUTOINST*/ + // Inputs + .clk (clk), + .in (in)); // Aggregate outputs into a single result vector wire [63:0] result = {57'h0, outna, 1'b0, outa}; @@ -92,21 +91,16 @@ module TestNonAnsi (/*AUTOARG*/ end endmodule -`ifndef verilator //UNSUPPORTED -typedef reg [2:0] three_t; - module TestAnsi ( input clk, - input three_t in, - output three_t out + input threeansi_t in, + output threeansi_t out ); always @(posedge clk) begin out <= ~in; end endmodule -`endif - // Local Variables: // verilog-typedef-regexp: "_t$" // End: diff --git a/test_regress/t/t_var_bad_hide2.pl b/test_regress/t/t_var_bad_hide2.pl new file mode 100755 index 000000000..3503ede3c --- /dev/null +++ b/test_regress/t/t_var_bad_hide2.pl @@ -0,0 +1,21 @@ +#!/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 ( + v_flags2 => ["--lint-only"], + fails=>$Self->{v3}, + expect=> +'%Warning-VARHIDDEN: t/t_var_bad_hide2.v:\d+: Declaration of signal hides declaration in upper scope: t +.* +%Warning-VARHIDDEN: t/t_var_bad_hide2.v:\d+: ... Location of original declaration +%Error: Exiting due to.*', + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_bad_hide2.v b/test_regress/t/t_var_bad_hide2.v new file mode 100644 index 000000000..b5f5d01d1 --- /dev/null +++ b/test_regress/t/t_var_bad_hide2.v @@ -0,0 +1,10 @@ +// 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; + + integer t; + +endmodule