diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7d93abeb6..0391f191d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1440,6 +1440,15 @@ private: m_modp->addStmtp(varp); return varp; } + void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) { + if (refp->user5p() && refp->user5p()->castNode()!=nodep) { + nodep->v3error("Duplicate "<prettyName()<user5p()->castNode()->warnMore() + <<"... Location of original "<user5p(nodep); + } + } // VISITs virtual void visit(AstNetlist* nodep, AstNUser* vup) { @@ -1513,27 +1522,26 @@ private: if (!nodep->modVarp()) { if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n"); VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name()); - AstVar* refp = foundp ? foundp->nodep()->castVar() : NULL; const char* whatp = nodep->param() ? "parameter pin" : "pin"; - if (!refp) { + if (!foundp) { if (nodep->name() == "__paramNumber1" && m_cellp->modp()->castPrimitive()) { // Primitive parameter is really a delay we can just ignore nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); return; } nodep->v3error(ucfirst(whatp)<<" not found: "<prettyName()); - } else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { - nodep->v3error(ucfirst(whatp)<<" is not an in/out/inout/param/interface: "<prettyName()); - } else { - nodep->modVarp(refp); - if (refp->user5p() && refp->user5p()->castNode()!=nodep) { - nodep->v3error("Duplicate "<prettyName()<user5p()->castNode()->warnMore() - <<"... Location of original "<nodep()->castVar()) { + if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { + nodep->v3error(ucfirst(whatp)<<" is not an in/out/inout/param/interface: "<prettyName()); } else { - refp->user5p(nodep); + nodep->modVarp(refp); + markAndCheckPinDup(nodep, refp, whatp); } } + else { + nodep->v3error(ucfirst(whatp)<<" not found: "<prettyName()); + } } // Early return() above when deleted } diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 529baba2d..0c9d5cbd2 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -84,10 +84,10 @@ private: typedef deque > IfaceRefRefs; // Note may have duplicate entries // STATE - typedef map VarCloneMap; + typedef map CloneMap; struct ModInfo { AstNodeModule* m_modp; // Module with specified name - VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp + CloneMap m_cloneMap; // Map of old-varp -> new cloned varp explicit ModInfo(AstNodeModule* modp) { m_modp=modp; } }; typedef map ModNameMap; @@ -131,7 +131,7 @@ private: } } } - string paramSmallName(AstNodeModule* modp, AstVar* varp) { + string paramSmallName(AstNodeModule* modp, AstNode* varp) { if (varp->user4()<=1) { makeSmallNames(modp); } @@ -145,7 +145,7 @@ private: return st; } string paramValueNumber(AstNode* nodep) { - // Given a compilcated object create a number to use for param module assignment + // Given a complicated object create a number to use for param module assignment // Ideally would be relatively stable if design changes (not use pointer value), // and must return same value given same input node // Return must presently be numeric so doesn't collide with 'small' alphanumeric parameter names @@ -166,14 +166,31 @@ private: return (string)"z"+cvtToStr(num); } } - void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) { + void collectPins(CloneMap* clonemapp, AstNodeModule* modp) { + // Grab all I/O so we can remap our pins later + for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstVar* varp = stmtp->castVar()) { + if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { + // Cloning saved a pointer to the new node for us, so just follow that link. + AstVar* oldvarp = varp->clonep()->castVar(); + //UINFO(8,"Clone list 0x"< 0x"<<(uint32_t)varp<insert(make_pair(oldvarp, varp)); + } + } + } + } + void relinkPins(CloneMap* clonemapp, AstPin* startpinp) { for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) { - if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n"); - // Find it in the clone structure - //UINFO(8,"Clone find 0x"<modVarp()<find(pinp->modVarp()); - UASSERT(cloneiter != clonemapp->end(), "Couldn't find pin in clone list"); - pinp->modVarp(cloneiter->second); + if (pinp->modVarp()) { + // Find it in the clone structure + //UINFO(8,"Clone find 0x"<modVarp()<find(pinp->modVarp()); + UASSERT(cloneiter != clonemapp->end(), "Couldn't find pin in clone list"); + pinp->modVarp(cloneiter->second->castVar()); + } + else { + pinp->v3fatalSrc("Not linked?\n"); + } } } void visitCell(AstCell* nodep); @@ -458,31 +475,32 @@ void ParamVisitor::visitCell(AstCell* nodep) { if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t"); for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) { if (!pinp->exprp()) continue; // No-connect - AstVar* modvarp = pinp->modVarp(); - if (!modvarp) { - pinp->v3error("Parameter not found in sub-module: Param "<name()<<" of "<prettyName()); - } else if (!modvarp->isGParam()) { - pinp->v3error("Attempted parameter setting of non-parameter: Param "<name()<<" of "<prettyName()); - } else { - AstConst* constp = pinp->exprp()->castConst(); - AstConst* origconstp = modvarp->valuep()->castConst(); - if (!constp) { - //if (debug()) pinp->dumpTree(cout,"error:"); - pinp->v3error("Can't convert defparam value to constant: Param "<name()<<" of "<prettyName()); - pinp->exprp()->replaceWith(new AstConst(pinp->fileline(), V3Number(pinp->fileline(), modvarp->width(), 0))); - } else if (origconstp && constp->sameTree(origconstp)) { - // 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 if (constp->num().isDouble() - || constp->num().isString() - || constp->num().isFourState()) { - longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(constp); - any_overrides = true; + if (AstVar* modvarp = pinp->modVarp()) { + if (!modvarp->isGParam()) { + pinp->v3error("Attempted parameter setting of non-parameter: Param "<prettyName()<<" of "<prettyName()); } else { - longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+constp->num().ascii(false); - any_overrides = true; + AstConst* exprp = pinp->exprp()->castConst(); + AstConst* origp = modvarp->valuep()->castConst(); + if (!exprp) { + //if (debug()) pinp->dumpTree(cout,"error:"); + pinp->v3error("Can't convert defparam value to constant: Param "<name()<<" of "<prettyName()); + pinp->exprp()->replaceWith(new AstConst(pinp->fileline(), V3Number(pinp->fileline(), modvarp->width(), 0))); + } else if (origp && exprp->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 if (exprp->num().isDouble() + || exprp->num().isString() + || exprp->num().isFourState()) { + longname += "_" + paramSmallName(nodep->modp(),modvarp)+paramValueNumber(exprp); + any_overrides = true; + } else { + longname += "_" + paramSmallName(nodep->modp(),modvarp)+exprp->num().ascii(false); + any_overrides = true; + } } + } else { + pinp->v3error("Parameter not found in sub-module: Param "<prettyName()<<" of "<prettyName()); } } IfaceRefRefs ifaceRefRefs; @@ -573,22 +591,12 @@ void ParamVisitor::visitCell(AstCell* nodep) { m_modNameMap.insert(make_pair(modp->name(), ModInfo(modp))); iter = m_modNameMap.find(newname); - VarCloneMap* clonemapp = &(iter->second.m_cloneMap); + CloneMap* clonemapp = &(iter->second.m_cloneMap); UINFO(4," De-parameterize to new: "<stmtsp(); stmtp; stmtp = stmtp->nextp()) { - if (AstVar* varp = stmtp->castVar()) { - if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { - // Cloning saved a pointer to the new node for us, so just follow that link. - AstVar* oldvarp = varp->clonep()->castVar(); - //UINFO(8,"Clone list 0x"< 0x"<<(uint32_t)varp<insert(make_pair(oldvarp, varp)); - } - } - } - + collectPins(clonemapp, modp); // Relink parameter vars to the new module relinkPins(clonemapp, nodep->paramsp()); @@ -608,15 +616,17 @@ void ParamVisitor::visitCell(AstCell* nodep) { // Assign parameters to the constants specified // DOES clone() so must be finished with module clonep() before here for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) { - AstVar* modvarp = pinp->modVarp(); - if (modvarp && pinp->exprp()) { - AstConst* constp = pinp->exprp()->castConst(); - // Remove any existing parameter - if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); - // Set this parameter to value requested by cell - modvarp->valuep(constp->cloneTree(false)); + if (pinp->exprp()) { + if (AstVar* modvarp = pinp->modVarp()) { + AstConst* constp = pinp->exprp()->castConst(); + // Remove any existing parameter + if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); + // Set this parameter to value requested by cell + modvarp->valuep(constp->cloneTree(false)); + } } } + } else { UINFO(4," De-parameterize to old: "<modName(newname); // We need to relink the pins to the new module - VarCloneMap* clonemapp = &(iter->second.m_cloneMap); + CloneMap* clonemapp = &(iter->second.m_cloneMap); relinkPins(clonemapp, nodep->pinsp()); UINFO(8," Done with "<dtypeFrom(nodep->varp()); if (nodep->backp()->castNodeAssign() && nodep->lvalue()) { // On LHS - if (!nodep->widthMin()) v3fatalSrc("LHS var should be size complete"); + if (!nodep->widthMin()) nodep->v3fatalSrc("LHS var should be size complete"); } //if (debug()>=9) nodep->dumpTree(cout," VRout "); if (nodep->lvalue() && nodep->varp()->isConst() diff --git a/src/verilog.y b/src/verilog.y index a3b365cd4..a01ade64a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -805,7 +805,7 @@ udpFront: parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] /* empty */ { $$ = NULL; } - | '#' '(' cellpinList ')' { $$ = $3; } + | '#' '(' cellparamList ')' { $$ = $3; } // // Parentheses are optional around a single parameter | '#' yaINTNUM { $$ = new AstPin($1,1,"",new AstConst($1,*$2)); } | '#' yaFLOATNUM { $$ = new AstPin($1,1,"",new AstConst($1,AstConst::Unsized32(),(int)(($2<0)?($2-0.5):($2+0.5)))); } @@ -1123,6 +1123,7 @@ genvar_identifierDecl: // IEEE: genvar_identifier (for declaration) local_parameter_declaration: // IEEE: local_parameter_declaration // // See notes in parameter_declaration + // // Front must execute first so VARDTYPE is ready before list of vars local_parameter_declarationFront list_of_param_assignments { $$ = $2; } ; @@ -1131,30 +1132,33 @@ parameter_declaration: // IEEE: parameter_declaration // // Instead of list_of_type_assignments // // we use list_of_param_assignments because for port handling // // it already must accept types, so simpler to have code only one place + // // Front must execute first so VARDTYPE is ready before list of vars parameter_declarationFront list_of_param_assignments { $$ = $2; } ; local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment + // // 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($2); } + //UNSUP 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($2); } + //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($2)); } ; parameter_port_declarationFrontE: // IEEE: parameter_port_declaration w/o assignment // // IEEE: parameter_declaration (minus 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)); } | implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($1); } | data_type { /*VARRESET-in-varGParam*/ VARDTYPE($1); } - //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE($2); } - //UNSUP data_type { VARDTYPE($1); } - //UNSUP yTYPE { VARDTYPE($1); } + //UNSUP yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE(new AstParseTypeDType($1)); } ; net_declaration: // IEEE: net_declaration - excluding implict @@ -1988,9 +1992,9 @@ packed_dimension: // ==IEEE: packed_dimension 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 /**/ { $$ = VARDONEA($1,*$1, $2, $3); $$->valuep($5); } - //UNSUP: exprOrDataType instead of expr ; list_of_param_assignments: // ==IEEE: list_of_param_assignments @@ -2067,16 +2071,25 @@ instRangeE: | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } ; +cellparamList: + {VARRESET_LIST(UNKNOWN);} cellparamItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } + ; + cellpinList: {VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; -cellpinItList: // IEEE: list_of_port_connections + list_of_parameter_assignmente +cellparamItList: // IEEE: list_of_parameter_assignmente + cellparamItemE { $$ = $1; } + | cellparamItList ',' cellparamItemE { $$ = $1->addNextNull($3)->castPin(); } + ; + +cellpinItList: // IEEE: list_of_port_connections cellpinItemE { $$ = $1; } | cellpinItList ',' cellpinItemE { $$ = $1->addNextNull($3)->castPin(); } ; -cellpinItemE: // IEEE: named_port_connection + named_parameter_assignment + empty +cellparamItemE: // IEEE: named_parameter_assignment + empty // Note empty can match either () or (,); V3LinkCells cleans up () /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(),PINNUMINC(),"",NULL); } | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",NULL); } @@ -2088,9 +2101,26 @@ cellpinItemE: // IEEE: named_port_connection + named_parameter_assignment //UNSUP '.' idAny '(' expr ':' expr ')' { } //UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { } // // For parameters - //UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); } + | '.' idAny '(' data_type ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); } // // For parameters - //UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); } + | data_type { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); } + // + | expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); } + //UNSUP expr ':' expr { } + //UNSUP expr ':' expr ':' expr { } + ; + +cellpinItemE: // IEEE: named_port_connection + empty + // Note empty can match either () or (,); V3LinkCells cleans up () + /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(),PINNUMINC(),"",NULL); } + | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",NULL); } + | '.' idSVKwd { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);} + | '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);} + | '.' idAny '(' ')' { $$ = new AstPin($1,PINNUMINC(),*$2,NULL); } + // // mintypmax is expanded here, as it might be a UDP or gate primitive + | '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); } + //UNSUP '.' idAny '(' expr ':' expr ')' { } + //UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { } // | expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); } //UNSUP expr ':' expr { } diff --git a/test_regress/t/t_param_type.v b/test_regress/t/t_param_type.v index 02fb2513f..7820f6e5c 100644 --- a/test_regress/t/t_param_type.v +++ b/test_regress/t/t_param_type.v @@ -55,10 +55,12 @@ module mod_typ #( parameter type TYP = byte )( input logic clk, - output TYP cnt = 0, + output TYP cnt, output int siz ); + initial cnt = 0; + always @ (posedge clk) cnt <= cnt + 1;