forked from github/verilator
Support parameter type, bug376.
This commit is contained in:
parent
cef097b7b7
commit
9ae40d64f0
4
Changes
4
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:
|
||||
|
@ -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; }
|
||||
|
@ -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*) {
|
||||
|
@ -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 "
|
||||
<<nodep->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 "
|
||||
<<nodep->prettyTypeName()<<" to constant.");
|
||||
}
|
||||
} else {
|
||||
// Calculate the width of this operation
|
||||
if (m_params && !nodep->width()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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: "<<nodep->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: "<<nodep->prettyName());
|
||||
}
|
||||
}
|
||||
|
@ -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: "<<nodep->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()
|
||||
|
@ -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 "<<pinp->prettyName()<<" of "<<nodep->prettyName());
|
||||
} else if (!origp) {
|
||||
pinp->v3error("Parameter type variable isn't a type: Param "<<modvarp->prettyName());
|
||||
} else {
|
||||
UINFO(9,"Parameter type assignment expr="<<exprp<<" to "<<origp<<endl);
|
||||
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 {
|
||||
longname += "_" + paramSmallName(nodep->modp(),modvarp)+paramValueNumber(exprp);
|
||||
any_overrides = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pinp->v3error("Parameter not found in sub-module: Param "<<pinp->prettyName()<<" of "<<nodep->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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->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__<<": "<<endl);
|
||||
// We should do it in bottom-up module order, but it works in any order.
|
||||
WidthClearVisitor cvisitor (nodep);
|
||||
WidthVisitor visitor (false, false);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
WidthRemoveVisitor rvisitor;
|
||||
|
@ -128,9 +128,17 @@ private:
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeClassDType* nodep, AstNUser*) {
|
||||
if (nodep->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
|
||||
|
@ -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); }
|
||||
|
@ -421,6 +421,7 @@ class AstSenTree;
|
||||
%token<fl> yTRI0 "tri0"
|
||||
%token<fl> yTRI1 "tri1"
|
||||
%token<fl> yTRUE "true"
|
||||
%token<fl> yTYPE "type"
|
||||
%token<fl> yTYPEDEF "typedef"
|
||||
%token<fl> yUNION "union"
|
||||
%token<fl> 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<nodep>: // IEEE: net_declaration - excluding implict
|
||||
@ -1993,7 +1994,7 @@ param_assignment<varp>: // ==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($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
||||
;
|
||||
|
||||
@ -2704,6 +2705,12 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
|
||||
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
|
||||
;
|
||||
|
||||
exprOrDataType<nodep>: // 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<nodep>: // 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
|
||||
//
|
||||
|
@ -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;
|
||||
|
18
test_regress/t/t_param_type2.pl
Executable file
18
test_regress/t/t_param_type2.pl
Executable file
@ -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;
|
40
test_regress/t/t_param_type2.v
Normal file
40
test_regress/t/t_param_type2.v
Normal file
@ -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
|
18
test_regress/t/t_typedef_param.pl
Executable file
18
test_regress/t/t_typedef_param.pl
Executable file
@ -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;
|
107
test_regress/t/t_typedef_param.v
Normal file
107
test_regress/t/t_typedef_param.v
Normal file
@ -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:
|
Loading…
Reference in New Issue
Block a user