From 696660639a7a08e21991309facaf920484a0d009 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 2 Jul 2011 12:45:26 -0400 Subject: [PATCH] Support 'const' variables in limited cases; similar to enums. --- Changes | 2 ++ bin/verilator | 4 ++-- src/V3AstNodes.cpp | 3 ++- src/V3AstNodes.h | 21 ++++++++++++++++++++- src/V3EmitV.cpp | 4 ++++ src/V3LinkLValue.cpp | 11 +++++++++++ src/V3LinkResolve.cpp | 3 +++ src/V3Width.cpp | 4 ++++ src/verilog.l | 11 ++++++++--- src/verilog.y | 21 ++++++++++++--------- test_regress/t/t_var_const.pl | 18 ++++++++++++++++++ test_regress/t/t_var_const.v | 21 +++++++++++++++++++++ test_regress/t/t_var_const_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_var_const_bad.v | 22 ++++++++++++++++++++++ 14 files changed, 148 insertions(+), 16 deletions(-) create mode 100755 test_regress/t/t_var_const.pl create mode 100644 test_regress/t/t_var_const.v create mode 100755 test_regress/t/t_var_const_bad.pl create mode 100644 test_regress/t/t_var_const_bad.v diff --git a/Changes b/Changes index 7d6c128b4..8f39ef14f 100644 --- a/Changes +++ b/Changes @@ -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. diff --git a/bin/verilator b/bin/verilator index 927de82bd..40da3e063 100755 --- a/bin/verilator +++ b/bin/verilator @@ -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. diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 198444d34..19ca280d9 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e0ea77c94..83978cfed 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index e17b563a5..2b1be6293 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -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()); } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 7bdce5e5d..747050d47 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -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: "<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: "<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() {} diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index e4d2d6bb6..608b56875 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -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 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 93f2a5527..1f21e776d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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); diff --git a/src/verilog.l b/src/verilog.l index 6bcb92e59..c07083e40 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -478,12 +478,12 @@ word [a-zA-Z0-9_]+ { /* 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"<newString("global"); } // Avoid 2009 "global" conflicting with old code when we can } diff --git a/src/verilog.y b/src/verilog.y index e284ea022..28d6c4214 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -274,6 +274,8 @@ class AstSenTree; %token yCASEZ "casez" %token yCHANDLE "chandle" %token yCLOCKING "clocking" +%token yCONST__ETC "const" +%token yCONST__LEX "const-in-lex" %token yCMOS "cmos" %token yCONTEXT "context" %token yCONTINUE "continue" @@ -1269,23 +1271,24 @@ data_declarationVar: // 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($2, LOGIC_IMPLICIT)); } - | constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4),$5,false)); } + /**/ yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); } + | /**/ yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } + | /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($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($1, $4)); } + | yCONST__ETC yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($1, new AstBasicDType($2, LOGIC_IMPLICIT))); } + | yCONST__ETC yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($1, GRAMMARP->addRange(new AstBasicDType($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($1, $3)); } // // = class_new is in variable_decl_assignment ; -constE: // IEEE: part of data_declaration - /* empty */ { } - //UNSUP yCONST__ETC { UNSUP } - ; - implicit_typeE: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration /* empty */ { $$ = NULL; } diff --git a/test_regress/t/t_var_const.pl b/test_regress/t/t_var_const.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_var_const.pl @@ -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; diff --git a/test_regress/t/t_var_const.v b/test_regress/t/t_var_const.v new file mode 100644 index 000000000..6a3808445 --- /dev/null +++ b/test_regress/t/t_var_const.v @@ -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 diff --git a/test_regress/t/t_var_const_bad.pl b/test_regress/t/t_var_const_bad.pl new file mode 100755 index 000000000..9ceccf307 --- /dev/null +++ b/test_regress/t/t_var_const_bad.pl @@ -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; diff --git a/test_regress/t/t_var_const_bad.v b/test_regress/t/t_var_const_bad.v new file mode 100644 index 000000000..f37a58213 --- /dev/null +++ b/test_regress/t/t_var_const_bad.v @@ -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