diff --git a/Changes b/Changes index f2bc5176e..b6c01536c 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.883 devel +** Support parameter type, bug376. [Alan Hunter, et al] + * Verilator 3.882 2016-03-01 @@ -2715,5 +2717,5 @@ Version 2.0. Local variables: mode: outline -paragraph-separate: "[ \f\n]*$" +paragraph-separate: "[ \f\n]*$" end: diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index f98752d50..b5ccb1626 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -158,6 +158,39 @@ public: //###################################################################### //==== Data Types +class AstParamTypeDType : public AstNodeDType { + // Parents: MODULE + // A parameter type statement; much like a var or typedef +private: + AstVarType m_varType; // Type of variable (for localparam vs. param) + string m_name; // Name of variable +public: + AstParamTypeDType(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) + : AstNodeDType(fl), m_varType(type), m_name(name) { + childDTypep(dtp); // Only for parser + dtypep(NULL); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(ParamTypeDType, PARAMTYPEDTYPE) + AstNodeDType* getChildDTypep() const { return childDTypep(); } + AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); } + virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); } + virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); } + // METHODS + virtual string name() const { return m_name; } + virtual bool maybePointedTo() const { return true; } + virtual bool hasDType() const { return true; } + void name(const string& flag) { m_name = flag; } + AstVarType varType() const { return m_varType; } // * = Type of variable + bool isParam() const { return true; } + bool isGParam() const { return (varType()==AstVarType::GPARAM); } +}; + class AstTypedef : public AstNode { private: string m_name; @@ -689,6 +722,23 @@ public: virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; +struct AstParseTypeDType : public AstNodeDType { + // Parents: VAR + // During parsing, this indicates the type of a parameter is a "parameter type" + // e.g. the data type is a container of any data type + AstParseTypeDType(FileLine* fl) + : AstNodeDType(fl) {} + ASTNODE_NODE_FUNCS(ParseTypeDType, PARSETYPEDTYPE) + AstNodeDType* dtypep() const { return NULL; } + // METHODS + virtual AstBasicDType* basicp() const { return NULL; } + virtual AstNodeDType* skipRefp() const { return NULL; } + virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { return 0; } + virtual int widthTotalBytes() const { return 0; } +}; + //###################################################################### class AstArraySel : public AstNodeSel { @@ -1333,6 +1383,7 @@ private: int m_pinNum; // Pin number string m_name; // Pin name, or "" for number based interconnect AstVar* m_modVarp; // Input/output this pin connects to on submodule. + AstParamTypeDType* m_modPTypep; // Param type this pin connects to on submodule. bool m_param; // Pin connects to parameter bool m_svImplicit; // Pin is SystemVerilog .name'ed public: @@ -1341,6 +1392,7 @@ public: ,m_name(name), m_param(false), m_svImplicit(false) { m_pinNum = pinNum; m_modVarp = NULL; + m_modPTypep = NULL; setNOp1p(exprp); } AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) @@ -1348,11 +1400,15 @@ public: m_name = varname->name(); m_pinNum = pinNum; m_modVarp = NULL; + m_modPTypep = NULL; setNOp1p(exprp); } ASTNODE_NODE_FUNCS(Pin, PIN) virtual void dump(ostream& str); - virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); + BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); + return NULL; } virtual string name() const { return m_name; } // * = Pin name, ""=go by number virtual void name(const string& name) { m_name = name; } virtual string prettyOperatorName() const { return modVarp() @@ -1363,7 +1419,9 @@ public: void exprp(AstNode* nodep) { addOp1p(nodep); } AstNode* exprp() const { return op1p()->castNode(); } // op1 = Expression connected to pin, NULL if unconnected AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable - void modVarp(AstVar* varp) { m_modVarp=varp; } + void modVarp(AstVar* nodep) { m_modVarp=nodep; } + AstParamTypeDType* modPTypep() const { return m_modPTypep; } // [After Link] Pointer to variable + void modPTypep(AstParamTypeDType* nodep) { m_modPTypep=nodep; } bool param() const { return m_param; } void param(bool flag) { m_param=flag; } bool svImplicit() const { return m_svImplicit; } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 245fb8871..2e8636b9e 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -242,6 +242,10 @@ private: // No cleaning, or would loose pointer to enum nodep->iterateChildren(*this); } + virtual void visit(AstParamTypeDType* nodep, AstNUser*) { + // No cleaning, or would loose pointer to enum + nodep->iterateChildren(*this); + } // Control flow operators virtual void visit(AstNodeCond* nodep, AstNUser*) { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 90d5069d4..a6e4538ee 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2260,8 +2260,12 @@ private: virtual void visit(AstNode* nodep, AstNUser*) { // Default: Just iterate if (m_required) { - nodep->v3error("Expecting expression to be constant, but can't convert a " - <prettyTypeName()<<" to constant."); + if (nodep->castNodeDType() || nodep->castRange()) { + // Ignore dtypes for parameter type pins + } else { + nodep->v3error("Expecting expression to be constant, but can't convert a " + <prettyTypeName()<<" to constant."); + } } else { // Calculate the width of this operation if (m_params && !nodep->width()) { diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp index 82862e435..6becdba5c 100644 --- a/src/V3Hashed.cpp +++ b/src/V3Hashed.cpp @@ -90,6 +90,7 @@ private: // Default: Just iterate virtual void visit(AstVar*, AstNUser*) {} virtual void visit(AstTypedef*, AstNUser*) {} + virtual void visit(AstParamTypeDType*, AstNUser*) {} virtual void visit(AstNode* nodep, AstNUser*) { nodeHashIterate(nodep); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0391f191d..663741f16 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -194,6 +194,7 @@ public: else if (nodep->castFunc()) return "function"; else if (nodep->castBegin()) return "block"; else if (nodep->castIface()) return "interface"; + else if (nodep->castParamTypeDType()) return "parameter type"; else return nodep->prettyTypeName(); } @@ -893,6 +894,11 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->iterateChildren(*this); m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); } + virtual void visit(AstParamTypeDType* nodep, AstNUser*) { + if (!m_curSymp) nodep->v3fatalSrc("Parameter type not under module??\n"); + nodep->iterateChildren(*this); + m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); + } virtual void visit(AstCFunc* nodep, AstNUser*) { // For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist if (m_statep->forScopeCreation()) nodep->v3fatalSrc("No CFuncs expected in tree yet"); @@ -1539,6 +1545,10 @@ private: markAndCheckPinDup(nodep, refp, whatp); } } + else if (AstParamTypeDType* refp = foundp->nodep()->castParamTypeDType()) { + nodep->modPTypep(refp); + markAndCheckPinDup(nodep, refp, whatp); + } else { nodep->v3error(ucfirst(whatp)<<" not found: "<prettyName()); } @@ -2099,7 +2109,12 @@ private: if (AstTypedef* defp = foundp ? foundp->nodep()->castTypedef() : NULL) { nodep->refDTypep(defp->subDTypep()); nodep->packagep(foundp->packagep()); - } else { + } + else if (AstParamTypeDType* defp = foundp ? foundp->nodep()->castParamTypeDType() : NULL) { + nodep->refDTypep(defp); + nodep->packagep(foundp->packagep()); + } + else { nodep->v3error("Can't find typedef: "<prettyName()); } } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index ba71d4bce..a022f7a84 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -140,6 +140,21 @@ private: virtual void visit(AstVar* nodep, AstNUser*) { cleanFileline(nodep); + if (nodep->subDTypep()->castParseTypeDType()) { + // It's a parameter type. Use a different node type for this. + AstNodeDType* dtypep = nodep->valuep()->castNodeDType(); + if (!dtypep) { + nodep->v3error("Parameter type's initial value isn't a type: "<prettyName()); + nodep->unlinkFrBack(); + } else { + dtypep->unlinkFrBack(); + AstNode* newp = new AstParamTypeDType(nodep->fileline(), nodep->varType(), nodep->name(), + VFlagChildDType(), dtypep); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } + return; + } + // We used modTrace before leveling, and we may now // want to turn it off now that we know the levelizations if (v3Global.opt.traceDepth() diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 0c9d5cbd2..091292c1e 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -177,6 +177,12 @@ private: clonemapp->insert(make_pair(oldvarp, varp)); } } + else if (AstParamTypeDType* ptp = stmtp->castParamTypeDType()) { + if (ptp->isGParam()) { + AstParamTypeDType* oldptp = ptp->clonep()->castParamTypeDType(); + clonemapp->insert(make_pair(oldptp, ptp)); + } + } } } void relinkPins(CloneMap* clonemapp, AstPin* startpinp) { @@ -188,6 +194,11 @@ private: UASSERT(cloneiter != clonemapp->end(), "Couldn't find pin in clone list"); pinp->modVarp(cloneiter->second->castVar()); } + else if (pinp->modPTypep()) { + CloneMap::iterator cloneiter = clonemapp->find(pinp->modPTypep()); + UASSERT(cloneiter != clonemapp->end(), "Couldn't find pin in clone list"); + pinp->modPTypep(cloneiter->second->castParamTypeDType()); + } else { pinp->v3fatalSrc("Not linked?\n"); } @@ -499,6 +510,24 @@ void ParamVisitor::visitCell(AstCell* nodep) { any_overrides = true; } } + } else if (AstParamTypeDType* modvarp = pinp->modPTypep()) { + AstNodeDType* exprp = pinp->exprp()->castNodeDType(); + AstNodeDType* origp = modvarp->subDTypep(); + if (!exprp) { + pinp->v3error("Parameter type pin value isn't a type: Param "<prettyName()<<" of "<prettyName()); + } else if (!origp) { + pinp->v3error("Parameter type variable isn't a type: Param "<prettyName()); + } else { + UINFO(9,"Parameter type assignment expr="<sameTree(origp)) { + // Setting parameter to its default value. Just ignore it. + // This prevents making additional modules, and makes coverage more + // obvious as it won't show up under a unique module page name. + } else { + longname += "_" + paramSmallName(nodep->modp(),modvarp)+paramValueNumber(exprp); + any_overrides = true; + } + } } else { pinp->v3error("Parameter not found in sub-module: Param "<prettyName()<<" of "<prettyName()); } @@ -624,6 +653,15 @@ void ParamVisitor::visitCell(AstCell* nodep) { // Set this parameter to value requested by cell modvarp->valuep(constp->cloneTree(false)); } + else if (AstParamTypeDType* modptp = pinp->modPTypep()) { + AstNodeDType* dtypep = pinp->exprp()->castNodeDType(); + if (!dtypep) pinp->v3fatalSrc("unlinked param dtype"); + if (modptp->childDTypep()) pushDeletep(modptp->childDTypep()->unlinkFrBack()); + // Set this parameter to value requested by cell + modptp->childDTypep(dtypep->cloneTree(false)); + // Later V3LinkDot will convert the ParamDType to a Typedef + // Not done here as may be localparams, etc, that also need conversion + } } } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index afa19a5c0..5223c9569 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -151,6 +151,26 @@ ostream& operator<<(ostream& str, const WidthVP* vup) { //###################################################################### +class WidthClearVisitor { + // Rather than a AstNVisitor, can just quickly touch every node + void clearWidthRecurse(AstNode* nodep) { + nodep->didWidth(false); + if (nodep->op1p()) clearWidthRecurse(nodep->op1p()); + if (nodep->op2p()) clearWidthRecurse(nodep->op2p()); + if (nodep->op3p()) clearWidthRecurse(nodep->op3p()); + if (nodep->op4p()) clearWidthRecurse(nodep->op4p()); + if (nodep->nextp()) clearWidthRecurse(nodep->nextp()); + } +public: + // CONSTUCTORS + explicit WidthClearVisitor(AstNetlist* nodep) { + clearWidthRecurse(nodep); + } + virtual ~WidthClearVisitor() {} +}; + +//###################################################################### + class WidthVisitor : public AstNVisitor { private: // TYPES @@ -913,6 +933,9 @@ private: // calculation would return identical values. Therefore we can directly replace the width nodep->widthForce(nodep->rangep()->elementsConst(), nodep->rangep()->elementsConst()); } + else if (nodep->isRanged()) { + nodep->widthForce(nodep->nrange().elements(), nodep->nrange().elements()); + } else if (nodep->implicit()) { // Parameters may notice implicitness and change to different dtype nodep->widthForce(1,1); @@ -951,6 +974,13 @@ private: nodep->iterateChildren(*this); nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep())); } + virtual void visit(AstParamTypeDType* nodep, AstNUser*) { + if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); + nodep->iterateChildren(*this); + nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->widthFromSub(nodep->subDTypep()); + } virtual void visit(AstCastParse* nodep, AstNUser* vup) { // nodep->dtp could be data type, or a primary_constant // Don't iterate lhsp, will deal with that once convert the type @@ -2724,6 +2754,7 @@ private: if (nodep->width()==0) nodep->v3fatalSrc("Under node "<prettyTypeName()<<" has no expected width?? Missing Visitor func?"); if (expWidth==0) nodep->v3fatalSrc("Node "<prettyTypeName()<<" has no expected width?? Missing Visitor func?"); if (expWidthMin==0) expWidthMin = expWidth; + if (nodep->dtypep()->width() == expWidth) return false; if (nodep->dtypep()->widthSized() && nodep->width() != expWidthMin) return true; if (!nodep->dtypep()->widthSized() && nodep->widthMin() > expWidthMin) return true; return false; @@ -3528,6 +3559,7 @@ int V3Width::debug() { void V3Width::width(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); nodep->clearCache(); } + virtual void visit(AstParamTypeDType* nodep, AstNUser*) { + if (nodep->user1SetOnce()) return; // Process once + visitIterateNodeDType(nodep); + // Move to type table as all dtype pointers must resolve there + nodep->unlinkFrBack(); // Make non-child + v3Global.rootp()->typeTablep()->addTypesp(nodep); + } void visitIterateNodeDType(AstNodeDType* nodep) { // Rather than use dtypeChg which may make new nodes, we simply edit in place, // as we don't need to preserve any widthMin's, and every dtype with the same width diff --git a/src/verilog.l b/src/verilog.l index 0b128aa50..80ab93596 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -459,6 +459,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "struct" { FL; return ySTRUCT; } "timeprecision" { FL; return yTIMEPRECISION; } "timeunit" { FL; return yTIMEUNIT; } + "type" { FL; return yTYPE; } "typedef" { FL; return yTYPEDEF; } "union" { FL; return yUNION; } "unique" { FL; return yUNIQUE; } @@ -508,7 +509,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "tagged" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "this" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "throughout" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "type" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "virtual" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "wait_order" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "wildcard" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } diff --git a/src/verilog.y b/src/verilog.y index a01ade64a..88742b0a9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -421,6 +421,7 @@ class AstSenTree; %token yTRI0 "tri0" %token yTRI1 "tri1" %token yTRUE "true" +%token yTYPE "type" %token yTYPEDEF "typedef" %token yUNION "union" %token yUNIQUE "unique" @@ -1140,14 +1141,14 @@ local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assig // // Front must execute first so VARDTYPE is ready before list of vars varLParamReset implicit_typeE { /*VARRESET-in-varLParam*/ VARDTYPE($2); } | varLParamReset data_type { /*VARRESET-in-varLParam*/ VARDTYPE($2); } - //UNSUP varLParamReset yTYPE { /*VARRESET-in-varLParam*/ VARDTYPE(new AstParseTypeDType($2)); } + | varLParamReset yTYPE { /*VARRESET-in-varLParam*/ VARDTYPE(new AstParseTypeDType($2)); } ; parameter_declarationFront: // IEEE: parameter_declaration w/o assignment // // Front must execute first so VARDTYPE is ready before list of vars varGParamReset implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($2); } | varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); } - //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); } + | varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); } ; parameter_port_declarationFrontE: // IEEE: parameter_port_declaration w/o assignment @@ -1155,10 +1156,10 @@ parameter_port_declarationFrontE: // IEEE: parameter_port_declaration w/o assign // // Front must execute first so VARDTYPE is ready before list of vars varGParamReset implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($2); } | varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); } - //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); } + | varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); } | implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($1); } | data_type { /*VARRESET-in-varGParam*/ VARDTYPE($1); } - //UNSUP yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($1)); } + | yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($1)); } ; net_declaration: // IEEE: net_declaration - excluding implict @@ -1993,7 +1994,7 @@ param_assignment: // ==IEEE: param_assignment // // IEEE: constant_param_expression // // constant_param_expression: '$' is in expr // // note exptOrDataType being a data_type is only for yPARAMETER yTYPE - id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' expr + id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType /**/ { $$ = VARDONEA($1,*$1, $2, $3); $$->valuep($5); } ; @@ -2704,6 +2705,12 @@ system_f_call: // IEEE: system_tf_call (as func) | yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); } ; +exprOrDataType: // expr | data_type: combined to prevent conflicts + expr { $$ = $1; } + // // data_type includes id that overlaps expr, so special flavor + | data_type { $$ = $1; } + ; + list_of_argumentsE: // IEEE: [list_of_arguments] argsDottedList { $$ = $1; } | argsExprListE { if ($1->castArg() && $1->castArg()->emptyConnectNoNext()) { $1->deleteTree(); $$ = NULL; } // Mis-created when have 'func()' @@ -3795,6 +3802,12 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange if (GRAMMARP->m_varDecl == AstVarType::SUPPLY1) { nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1)); } + if (dtypep->castParseTypeDType()) { + // Parser needs to know what is a type + AstNode* newp = new AstTypedefFwd(fileline, name); + nodep->addNext(newp); + SYMP->reinsert(newp); + } // Don't set dtypep in the ranging; // We need to autosize parameters and integers separately // diff --git a/test_regress/t/t_param_type.pl b/test_regress/t/t_param_type.pl index ea02c60a4..f91289753 100755 --- a/test_regress/t/t_param_type.pl +++ b/test_regress/t/t_param_type.pl @@ -7,14 +7,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. -$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug376"); - compile ( - ); + ); execute ( - check_finished=>1, - ); + check_finished=>1, + ); ok(1); 1; diff --git a/test_regress/t/t_param_type2.pl b/test_regress/t/t_param_type2.pl new file mode 100755 index 000000000..ab1195fb5 --- /dev/null +++ b/test_regress/t/t_param_type2.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_param_type2.v b/test_regress/t/t_param_type2.v new file mode 100644 index 000000000..e103c1c2a --- /dev/null +++ b/test_regress/t/t_param_type2.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2012 by Iztok Jeras. + +package tt_pkg; + typedef enum logic [1:0] {L0, L1, L2, L3} test_t; +endpackage + +module t (/*AUTOARG*/ + // Outputs + ob + ); + + output [1:0] ob; + + import tt_pkg::*; + + test_t a; + test_t b; + + assign a = L0; + assign ob = b; + + tt_buf #(.T_t(test_t)) + u_test + (.i(a), .o(b)); + +endmodule + +module tt_buf + #( + parameter type T_t = logic [0:0] + ) + ( + input T_t i, + output T_t o + ); + assign o = i; +endmodule diff --git a/test_regress/t/t_typedef_param.pl b/test_regress/t/t_typedef_param.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_typedef_param.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_typedef_param.v b/test_regress/t/t_typedef_param.v new file mode 100644 index 000000000..4cbba8f20 --- /dev/null +++ b/test_regress/t/t_typedef_param.v @@ -0,0 +1,107 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +typedef reg [2:0] threeansi_t; + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [2:0] in = crc[2:0]; + + localparam type three_t = reg [2:0]; + + three_t outna; + three_t outa; + + TestNonAnsi #( .p_t (reg [2:0]) ) + test (// Outputs + .out (outna), + /*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[2:0])); + + TestAnsi #( .p_t (reg [2:0])) + testa (// Outputs + .out (outa), + /*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[2:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {57'h0, outna, 1'b0, outa}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= 64'h0; + end + else if (cyc<10) begin + sum <= 64'h0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h018decfea0a8828a + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module TestNonAnsi (/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in + ); + parameter type p_t = shortint; + + input clk; + input p_t in; + output p_t out; + + always @(posedge clk) begin + out <= ~in; + end +endmodule + +module TestAnsi + #( parameter type p_t = shortint ) + ( + input clk, + input p_t in, + output p_t out + ); + always @(posedge clk) begin + out <= ~in; + end +endmodule + +// Local Variables: +// verilog-typedef-regexp: "_t$" +// End: