Support enums

This commit is contained in:
Wilson Snyder 2009-12-27 08:29:55 -05:00
parent 7a81dd3378
commit dbce06500d
16 changed files with 460 additions and 11 deletions

View File

@ -10,7 +10,7 @@ indicates the contributor was also the author of the fix; Thanks!
** Support "program", "package", "import" and $unit.
** Support typedef. [Donal Casey]
** Support typedef and enum. [by Donal Casey]
** Support direct programming interface (DPI) "import" and "export".

View File

@ -467,6 +467,12 @@ void AstDisplay::dump(ostream& str) {
this->AstNode::dump(str);
//str<<" "<<displayType().ascii();
}
void AstEnumItemRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }

View File

@ -285,6 +285,64 @@ public:
void packagep(AstPackage* nodep) { m_packagep=nodep; }
};
struct AstEnumItem : public AstNode {
private:
string m_name;
public:
// Parents: ENUM
AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp)
: AstNode(fl), m_name(name)
{ addNOp1p(rangep); addNOp2p(initp); }
ASTNODE_NODE_FUNCS(EnumItem, ENUMITEM)
virtual string name() const { return m_name; }
virtual bool maybePointedTo() const { return true; }
void name(const string& flag) { m_name = flag; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range for name appending
void rangep(AstNode* nodep) { addOp1p(nodep); }
AstNode* initp() const { return op2p(); } // op2 = Value
void initp(AstNode* nodep) { addOp2p(nodep); }
};
struct AstEnumItemRef : public AstNodeMath {
private:
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
public:
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp)
: AstNodeMath(fl), m_itemp(itemp) {
if (m_itemp) widthSignedFrom(m_itemp);
}
ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF)
virtual void dump(ostream& str);
virtual string name() const { return itemp()->name(); }
virtual bool broken() const { return !itemp(); }
virtual int instrCount() const { return 0; }
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); }
virtual bool same(AstNode* samep) const {
return itemp()==samep->castEnumItemRef()->itemp(); }
AstEnumItem* itemp() const { return m_itemp; }
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() { return true; }
};
struct AstEnumDType : public AstNodeDType {
// Parents: TYPEDEF/MODULE
// Children: ENUMVALUEs
AstEnumDType(FileLine* fl, AstNodeDType* dtypep, AstNode* itemsp)
: AstNodeDType(fl)
{ setOp1p(dtypep); addNOp2p(itemsp); }
ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE)
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Data type
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstEnumItem* itemsp() const { return op2p()->castEnumItem(); } // op2 = AstEnumItem's
void addValuesp(AstNode* nodep) { addOp2p(nodep); }
// METHODS
virtual AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthAlignBytes(); }
};
//######################################################################
struct AstArraySel : public AstNodeSel {

View File

@ -1073,6 +1073,23 @@ private:
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->varp()->prettyName());
}
}
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (!nodep->itemp()) nodep->v3fatalSrc("Not linked");
bool did=false;
if (nodep->itemp()->initp()) {
//if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: ");
nodep->itemp()->initp()->iterateAndNext(*this);
if (AstConst* initp = nodep->itemp()->initp()->castConst()) {
const V3Number& num = initp->num();
replaceNum(nodep, num); nodep=NULL;
did=true;
}
}
if (!did && m_required) {
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->itemp()->prettyName());
}
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
// Don't iterate children, don't want to loose VarRef.
if (nodep->attrType()==AstAttrType::BITS) {

View File

@ -118,12 +118,22 @@ private:
else return NULL;
}
void linkVarName (AstVarRef* nodep) {
bool linkVarName (AstVarRef* nodep) {
// Return true if changed, and caller should end processing
if (!nodep->varp()) {
AstVar* varp = m_curVarsp->findIdUpward(nodep->name())->castVar();
nodep->varp(varp);
nodep->packagep(packageFor(varp));
AstNode* foundp = m_curVarsp->findIdUpward(nodep->name());
if (AstVar* varp = foundp->castVar()) {
nodep->varp(varp);
nodep->packagep(packageFor(varp));
}
else if (AstEnumItem* valuep = foundp->castEnumItem()) {
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep);
nodep->replaceWith(newp);
nodep->deleteTree(); nodep=NULL;
return true; // Edited
}
}
return false;
}
string nodeTextType(AstNode* nodep) {
@ -170,7 +180,7 @@ private:
void createImplicitVar (AstVarRef* forrefp, bool noWarn) {
// Create implicit after warning
linkVarName(forrefp);
if (linkVarName(forrefp)) { forrefp=NULL; return; }
if (!forrefp->varp()) {
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
@ -301,19 +311,50 @@ private:
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// VarRef: Resolve its reference
nodep->iterateChildren(*this);
if (m_idState==ID_RESOLVE && !nodep->varp()) {
linkVarName(nodep);
if (linkVarName(nodep)) { nodep=NULL; return; }
if (!nodep->varp()) {
nodep->v3error("Can't find definition of signal: "<<nodep->prettyName());
createImplicitVar (nodep, true); // So only complain once
}
}
nodep->iterateChildren(*this);
}
//virtual void visit(AstVarXRef* nodep, AstNUser*) {
// See LinkDotVisitor
//}
virtual void visit(AstEnumItem* nodep, AstNUser*) {
// EnumItem: Remember its name for later resolution
nodep->iterateChildren(*this);
if (m_idState==ID_FIND) {
// Find under either a task or the module's vars
AstNode* foundp = m_curVarsp->findIdUpward(nodep->name());
AstEnumItem* findvarp = foundp->castEnumItem();
bool ins=false;
if (!foundp) {
ins=true;
} else if (findvarp != nodep) {
UINFO(4,"DupVar: "<<nodep<<" ;; "<<foundp<<endl);
if (findvarp && findvarp->user3p() == m_curVarsp) { // Only when on same level
nodep->v3error("Duplicate declaration of enum value: "<<nodep->prettyName());
findvarp->v3error("... Location of original declaration");
} else {
// User can disable the message at either point
if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)
&& !foundp->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) {
nodep->v3warn(VARHIDDEN,"Declaration of enum value hides declaration in upper scope: "<<nodep->name());
foundp->v3warn(VARHIDDEN,"... Location of original declaration");
}
ins = true;
}
}
if (ins) {
symsInsert(nodep->name(), nodep);
}
}
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
// NodeTask: Remember its name for later resolution
if (!m_curVarsp) nodep->v3fatalSrc("Function/Task not under module??\n");

View File

@ -226,6 +226,29 @@ private:
}
}
}
virtual void visit(AstEnumItem* nodep, AstNUser*) {
// Expand ranges
nodep->iterateChildren(*this);
if (nodep->rangep()) {
if (!nodep->rangep()->msbp()->castConst()
|| !nodep->rangep()->lsbp()->castConst()) nodep->v3error("Enum ranges must be integral, per spec");
int msb = nodep->rangep()->msbConst();
int lsb = nodep->rangep()->lsbConst();
int increment = (msb > lsb) ? -1 : 1;
int offset_from_init = 0;
AstNode* addp = NULL;
for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) {
string name = nodep->name() + cvtToStr(i);
AstNode* initp = NULL;
if (nodep->initp()) initp = new AstAdd(nodep->fileline(), nodep->initp()->cloneTree(true),
new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
addp = addp->addNextNull(new AstEnumItem(nodep->fileline(), name, NULL, initp));
}
nodep->replaceWith(addp);
nodep->deleteTree();
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
m_varp = nodep;

View File

@ -152,6 +152,10 @@ private:
nodep->varp()->iterate(*this);
nodep->signedFrom(nodep->varp());
}
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
nodep->itemp()->iterate(*this);
nodep->signedFrom(nodep->itemp());
}
virtual void visit(AstConst* nodep, AstNUser*) {
// The node got setup with the signed state of the node.
// However a later operation may have changed the node->signed w/o changing

View File

@ -575,6 +575,58 @@ private:
}
//if (debug()>=9) nodep->dumpTree(cout," VRout ");
}
virtual void visit(AstEnumDType* nodep, AstNUser* vup) {
nodep->dtypep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->widthFrom(nodep->dtypep());
// Assign widths
nodep->itemsp()->iterateAndNext(*this,WidthVP(nodep->width(),nodep->widthMin(),BOTH).p());
// Assign missing values
V3Number num (nodep->fileline(), nodep->width(), 0);
V3Number one (nodep->fileline(), nodep->width(), 1);
map<V3Number,AstEnumItem*> inits;
for (AstEnumItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castEnumItem()) {
if (itemp->initp()) {
if (debug()>=9) { UINFO(0,"EnumInit "<<itemp<<endl); itemp->initp()->dumpTree(cout,"-EnumInit: "); }
V3Const::constifyParamsEdit(itemp->initp()); // itemp may change
if (!itemp->initp()->castConst()) {
itemp->initp()->v3error("Enum value isn't a constant");
itemp->initp()->unlinkFrBack()->deleteTree();
}
}
if (!itemp->initp()) itemp->initp(new AstConst(itemp->fileline(), num));
num.opAssign(itemp->initp()->castConst()->num());
// Look for duplicates
if (inits.find(num) != inits.end()) {
itemp->v3error("Overlapping enumeration value: "<<itemp->prettyName());
inits.find(num)->second->v3error("... Location of original declaration");
} else {
inits.insert(make_pair(num,itemp));
}
num.opAdd(one, itemp->initp()->castConst()->num());
}
}
virtual void visit(AstEnumItem* nodep, AstNUser* vup) {
int width = vup->c()->width();
int mwidth = vup->c()->widthMin();
nodep->width(width, mwidth);
if (nodep->initp()) {
nodep->initp()->iterateAndNext(*this,WidthVP(width,mwidth,BOTH).p());
widthCheck(nodep,"Enum value",nodep->initp(),width,mwidth);
}
}
virtual void visit(AstEnumItemRef* nodep, AstNUser* vup) {
if (nodep->itemp()->width()==0) {
// We need to do the whole enum en-mass
AstNode* enump = nodep;
for (; enump; enump=enump->backp()) {
if (enump->castEnumDType()) break;
}
if (!enump) nodep->v3fatalSrc("EnumItem not under a Enum");
enump->iterate(*this);
}
nodep->widthFrom(nodep->itemp()->initp());
}
virtual void visit(AstPslClocked* nodep, AstNUser*) {
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
nodep->sensesp()->iterateAndNext(*this);

View File

@ -375,6 +375,7 @@ escid \\[^ \t\f\r\n]+
"endpackage" { FL; return yENDPACKAGE; }
"endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; }
"enum" { FL; return yENUM; }
"export" { FL; return yEXPORT; }
"final" { FL; return yFINAL; }
"iff" { FL; return yIFF; }
@ -414,7 +415,6 @@ escid \\[^ \t\f\r\n]+
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"enum" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extern" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }

View File

@ -279,6 +279,7 @@ class AstSenTree;
%token<fl> yENDSPECIFY "endspecify"
%token<fl> yENDTABLE "endtable"
%token<fl> yENDTASK "endtask"
%token<fl> yENUM "enum"
%token<fl> yEXPORT "export"
%token<fl> yFINAL "final"
%token<fl> yFOR "for"
@ -1058,7 +1059,7 @@ data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc referenc
//UNSUP { UNSUP }
//UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionListE
//UNSUP { UNSUP }
//UNSUP enumDecl { UNSUP }
| enumDecl { $$ = $1; }
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
| yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
//UNSUP yEVENT { UNSUP }
@ -1138,6 +1139,50 @@ variable_dimension<rangep>: // ==IEEE: variable_dimension
// // '[' '$' ':' expr ']' -- anyrange:expr:$
;
//************************************************
// enum
// IEEE: part of data_type
enumDecl<dtypep>:
yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,$2,$4); }
;
enum_base_typeE<dtypep>: // IEEE: enum_base_type
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
// // Not in spec, but obviously "enum [1:0]" should work
// // implicit_type expanded, without empty
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); }
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
//
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2); }
;
enum_nameList<nodep>:
enum_name_declaration { $$ = $1; }
| enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); }
;
enum_name_declaration<nodep>: // ==IEEE: enum_name_declaration
idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($<fl>1, *$1, $2, $3); }
;
enumNameRangeE<nodep>: // IEEE: second part of enum_name_declaration
/* empty */ { $$ = NULL; }
| '[' intnumAsConst ']' { $$ = new AstRange($1,new AstConst($1,0), $2); }
| '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); }
;
enumNameStartE<nodep>: // IEEE: third part of enum_name_declaration
/* empty */ { $$ = NULL; }
| '=' constExpr { $$ = $2; }
;
intnumAsConst<nodep>:
yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
;
//************************************************
// Typedef
@ -1188,7 +1233,7 @@ type_declaration<nodep>: // ==IEEE: type_declaration
// // Combines into above "data_type id" rule
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
| yTYPEDEF id ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$2); SYMP->reinsert($$); }
//UNSUP yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
| yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
//UNSUP yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
//UNSUP yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }

18
test_regress/t/t_enum.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;

56
test_regress/t/t_enum.v Normal file
View File

@ -0,0 +1,56 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/);
localparam FIVE = 5;
enum { e0,
e1,
e3=3,
e5=FIVE,
e10_[2] = 10,
e20_[5:7] = 25,
e20_z,
e30_[7:5] = 30,
e30_z
} EN;
enum {
z5 = e5
} ZN;
typedef enum [2:0] { ONES=~0 } three_t;
three_t three = ONES;
var logic [ONES:0] sized_based_on_enum;
initial begin
if (e0 !== 0) $stop;
if (e1 !== 1) $stop;
if (e3 !== 3) $stop;
if (e5 !== 5) $stop;
if (e10_0 !== 10) $stop;
if (e10_1 !== 11) $stop;
if (e20_5 !== 25) $stop;
if (e20_6 !== 26) $stop;
if (e20_7 !== 27) $stop;
if (e20_z !== 28) $stop;
if (e30_7 !== 30) $stop;
if (e30_6 !== 31) $stop;
if (e30_5 !== 32) $stop;
if (e30_z !== 33) $stop;
if (z5 !== 5) $stop;
if (three != 3'b111) $stop;
if ($bits(sized_based_on_enum) != 8) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

18
test_regress/t/t_enum_int.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,73 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
enum integer {
EP_State_IDLE ,
EP_State_CMDSHIFT0 ,
EP_State_CMDSHIFT13 ,
EP_State_CMDSHIFT14 ,
EP_State_CMDSHIFT15 ,
EP_State_CMDSHIFT16 ,
EP_State_DWAIT ,
EP_State_DSHIFT0 ,
EP_State_DSHIFT1 ,
EP_State_DSHIFT15 } m_state_xr;
// Beginning of automatic ASCII enum decoding
reg [79:0] m_stateAscii_xr; // Decode of m_state_xr
always @(m_state_xr) begin
case ({m_state_xr})
EP_State_IDLE: m_stateAscii_xr = "idle ";
EP_State_CMDSHIFT0: m_stateAscii_xr = "cmdshift0 ";
EP_State_CMDSHIFT13: m_stateAscii_xr = "cmdshift13";
EP_State_CMDSHIFT14: m_stateAscii_xr = "cmdshift14";
EP_State_CMDSHIFT15: m_stateAscii_xr = "cmdshift15";
EP_State_CMDSHIFT16: m_stateAscii_xr = "cmdshift16";
EP_State_DWAIT: m_stateAscii_xr = "dwait ";
EP_State_DSHIFT0: m_stateAscii_xr = "dshift0 ";
EP_State_DSHIFT1: m_stateAscii_xr = "dshift1 ";
EP_State_DSHIFT15: m_stateAscii_xr = "dshift15 ";
default: m_stateAscii_xr = "%Error ";
endcase
end
// End of automatics
integer cyc; initial cyc=1;
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
//$write("%d %x %x %x\n", cyc, data, wrapcheck_a, wrapcheck_b);
if (cyc==1) begin
m_state_xr <= EP_State_IDLE;
end
if (cyc==2) begin
if (m_stateAscii_xr != "idle ") $stop;
m_state_xr <= EP_State_CMDSHIFT13;
end
if (cyc==3) begin
if (m_stateAscii_xr != "cmdshift13") $stop;
m_state_xr <= EP_State_CMDSHIFT16;
end
if (cyc==4) begin
if (m_stateAscii_xr != "cmdshift16") $stop;
m_state_xr <= EP_State_DWAIT;
end
if (cyc==9) begin
if (m_stateAscii_xr != "dwait ") $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
end
endmodule

View File

@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Error: t/t_enum_overlap_bad.v:\d+: Overlapping enumeration value: e1b
%Error: t/t_enum_overlap_bad.v:\d+: ... Location of original declaration
%Error: Exiting due to',
) if $Self->{v3};
ok(1);
1;

View File

@ -0,0 +1,18 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/);
enum { e0,
e1,
e2,
e1b=1
} BAD1;
initial begin
$stop;
end
endmodule