Support 'const' variables in limited cases; similar to enums.

This commit is contained in:
Wilson Snyder 2011-07-02 12:45:26 -04:00
parent da4323062d
commit 696660639a
14 changed files with 148 additions and 16 deletions

View File

@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.814****
*** Support 'const' variables in limited cases; similar to enums. [Alex Solomatnikov]
*** Support disable for loop escapes.
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.

View File

@ -1661,7 +1661,7 @@ please file a bug if a feature you need is missing.
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
do-while, enum, export, final, import, int, logic, longint, package,
const, do-while, enum, export, final, import, int, logic, longint, package,
program, shortint, time, typedef, var, void, priority case/if, and unique
case/if.
@ -2261,7 +2261,7 @@ specified as illegal on chandles.
=item disable
Disable statements may be used only if the block being disabled is a block
the disable statement itself is inside. This is commonly used to provide
the disable statement itself is inside. This was commonly used to provide
loop break and continue functionality before SystemVerilog added the break
and continue keywords.

View File

@ -608,7 +608,8 @@ void AstVar::dump(ostream& str) {
else if (isInput()) str<<" [I]";
else if (isOutput()) str<<" [O]";
}
if (isUsedClock()) str<<" [C]";
if (isConst()) str<<" [CONST]";
if (isUsedClock()) str<<" [CLK]";
if (isSigPublic()) str<<" [P]";
if (isUsedLoopIdx()) str<<" [LOOP]";
if (attrClockEn()) str<<" [aCLKEN]";

View File

@ -300,6 +300,25 @@ public:
void implicit(bool flag) { m_implicit = flag; }
};
struct AstConstDType : public AstNodeDType {
// const data type, ie "const some_dtype var_name [2:0]"
// ConstDType are removed in V3LinkLValue and become AstVar::isConst.
// When more generic types are supported AstConstDType will be propagated further.
AstConstDType(FileLine* fl, AstNodeDType* dtypep)
: AstNodeDType(fl) {
setOp1p(dtypep);
widthSignedFrom(dtypep);
}
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
void dtypep(AstNodeDType* nodep) { setOp1p(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()->widthTotalBytes(); }
};
struct AstRefDType : public AstNodeDType {
private:
AstTypedef* m_defp;
@ -677,7 +696,7 @@ public:
bool isToggleCoverable() const { return ((isIO() || isSignal())
&& (isIO() || isBitLogic())
// Wrapper would otherwise duplicate wrapped module's coverage
&& !isSc() && !isPrimaryIO()); }
&& !isSc() && !isPrimaryIO() && !isConst()); }
bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); }
bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); }
bool isPure() const { return (varType()==AstVarType::XTEMP); }

View File

@ -483,6 +483,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep,nodep->prettyName());
if (nodep->rangep()) { puts(" "); nodep->rangep()->iterateAndNext(*this); puts(" "); }
}
virtual void visit(AstConstDType* nodep, AstNUser*) {
putfs(nodep,"const ");
nodep->dtypep()->iterateAndNext(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
else { putfs(nodep,nodep->prettyName()); }

View File

@ -45,6 +45,7 @@ private:
// STATE
bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
AstInitial* m_initialp; // In an initial block
AstNodeFTask* m_ftaskp; // Function or task we're inside
// METHODS
@ -67,6 +68,10 @@ private:
nodep->v3error("Assigning to input variable: "<<nodep->prettyName());
}
}
if (nodep->lvalue() && nodep->varp()->isConst()
&& !m_initialp) { // Too loose, but need to allow our generated first assignment
nodep->v3error("Assigning to const variable: "<<nodep->prettyName());
}
}
nodep->iterateChildren(*this);
}
@ -222,6 +227,11 @@ private:
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstInitial* nodep, AstNUser*) {
m_initialp = nodep;
nodep->iterateChildren(*this);
m_initialp = NULL;
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
m_ftaskp = nodep;
nodep->iterateChildren(*this);
@ -259,6 +269,7 @@ public:
LinkLValueVisitor(AstNode* nodep, bool start) {
m_setRefLvalue = start;
m_ftaskp = NULL;
m_initialp = NULL;
nodep->accept(*this);
}
virtual ~LinkLValueVisitor() {}

View File

@ -95,6 +95,9 @@ private:
nodep->dtypeSkipRefp()->castArrayDType())) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
}
if (nodep->dtypeSkipRefp()->castConstDType()) {
nodep->isConst(true);
}
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute

View File

@ -488,6 +488,10 @@ private:
// else width in node is correct; it was set based on keyword().width()
// at construction time
}
virtual void visit(AstConstDType* nodep, AstNUser* vup) {
nodep->iterateChildren(*this, vup);
nodep->widthFrom(nodep->dtypep());
}
virtual void visit(AstRefDType* nodep, AstNUser* vup) {
nodep->iterateChildren(*this, vup);
if (nodep->defp()) nodep->defp()->iterate(*this,vup);

View File

@ -478,12 +478,12 @@ word [a-zA-Z0-9_]+
<S05,S09>{
/* Keywords */
"assert" { FL; return yASSERT; }
"const" { FL; return yCONST__LEX; }
"cover" { FL; return yCOVER; }
"property" { FL; return yPROPERTY; }
/* Generic unsupported warnings */
"assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"const" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"union" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
@ -964,7 +964,8 @@ int V3ParseImp::lexToken() {
//yylval // Set by yylexThis()
}
// If a paren, read another
if (token == yGLOBAL__LEX
if (token == yCONST__LEX
|| token == yGLOBAL__LEX
// Never put yID_* here; below symbol table resolution would break
) {
if (debugFlex()) { cout<<" lexToken: reading ahead to find possible strength"<<endl; }
@ -975,7 +976,11 @@ int V3ParseImp::lexToken() {
m_aheadVal = yylval;
yylval = curValue;
// Now potentially munge the current token
if (token == yGLOBAL__LEX) {
if (token == yCONST__LEX) {
//UNSUP if (nexttok == yREF) token = yCONST__REF;
token = yCONST__ETC;
}
else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) token = yGLOBAL__CLOCKING;
else { token = yaID__LEX; yylval.strp = PARSEP->newString("global"); } // Avoid 2009 "global" conflicting with old code when we can
}

View File

@ -274,6 +274,8 @@ class AstSenTree;
%token<fl> yCASEZ "casez"
%token<fl> yCHANDLE "chandle"
%token<fl> yCLOCKING "clocking"
%token<fl> yCONST__ETC "const"
%token<fl> yCONST__LEX "const-in-lex"
%token<fl> yCMOS "cmos"
%token<fl> yCONTEXT "context"
%token<fl> yCONTINUE "continue"
@ -1269,23 +1271,24 @@ data_declarationVar<nodep>: // IEEE: part of data_declaration
;
data_declarationVarFront: // IEEE: part of data_declaration
// // Expanded: "constE yVAR lifetimeE data_type"
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); }
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); }
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5,false)); }
/**/ yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); }
| /**/ yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
| /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,false)); }
//
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
| yCONST__ETC yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, $4)); }
| yCONST__ETC yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, new AstBasicDType($<fl>2, LOGIC_IMPLICIT))); }
| yCONST__ETC yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,false))); }
//
// // Expanded: "constE lifetimeE data_type"
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
| /**/ lifetime data_type { /*VARRESET-in-ddVar*/ VARDTYPE($2); }
//UNSUP yCONST__ETC lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); }
| yCONST__ETC lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, $3)); }
// // = class_new is in variable_decl_assignment
;
constE: // IEEE: part of data_declaration
/* empty */ { }
//UNSUP yCONST__ETC { UNSUP }
;
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
// // Also expanded in data_declaration
/* empty */ { $$ = NULL; }

18
test_regress/t/t_var_const.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,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
const logic [2:0] five = 3'd5;
always @ (posedge clk) begin
if (five !== 3'd5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2005 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=>1,
expect=>
'%Error: t/t_var_const_bad.v:\d+: Assigning to const variable: five
%Error: Exiting due to.*',
) if $Self->{v3};
ok(1);
1;

View File

@ -0,0 +1,22 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
const logic [2:0] five = 3'd5;
always @ (posedge clk) begin
five = 3'd4;
if (five !== 3'd5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule