Support parameter type, bug376.

This commit is contained in:
Wilson Snyder 2016-03-14 21:51:31 -04:00
parent cef097b7b7
commit 9ae40d64f0
17 changed files with 388 additions and 17 deletions

View File

@ -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:

View File

@ -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; }

View File

@ -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*) {

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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()

View File

@ -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
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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); }

View File

@ -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
//

View File

@ -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
View 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;

View 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

View 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;

View 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: