diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 010916da1..7419335f0 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -46,6 +46,9 @@ if (! GetOptions ( defined $Opt_A or die "%Error: No old diff filename\n"; defined $Opt_B or die "%Error: No new diff filename\n"; +-e $Opt_A or die "%Error: No old diff filename found: $Opt_A\n"; +-e $Opt_B or die "%Error: No new diff filename found: $Opt_B\n"; + if (-d $Opt_A && -d $Opt_B) { diff_dir ($Opt_A, $Opt_B); } elsif (-f $Opt_A && -f $Opt_B) { diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index afaf12987..f48a9f877 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -142,6 +142,7 @@ RAW_OBJS = \ V3LinkCells.o \ V3LinkDot.o \ V3LinkLevel.o \ + V3LinkLValue.o \ V3LinkResolve.o \ V3Localize.o \ V3Name.o \ diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp new file mode 100644 index 000000000..ba17dd5ae --- /dev/null +++ b/src/V3LinkLValue.cpp @@ -0,0 +1,174 @@ +// $Id$ +//************************************************************************* +// DESCRIPTION: Verilator: LValue module/signal name references +// +// Code available from: http://www.veripool.com/verilator +// +// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli +// +//************************************************************************* +// +// Copyright 2003-2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// General Public License or the Perl Artistic License. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* +// LinkLValue TRANSFORMATIONS: +// Top-down traversal +// Set lvalue() attributes on appropriate VARREFs. +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" +#include +#include +#include +#include +#include +#include + +#include "V3Global.h" +#include "V3LinkLValue.h" +#include "V3Ast.h" + +//###################################################################### +// Link state, as a visitor of each AstNode + +class LinkLValueVisitor : public AstNVisitor { +private: + // NODE STATE + + // STATE + bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments + + //int debug() { return 9; } + + // METHODS + + // VISITs + // Result handing + virtual void visit(AstNodeVarRef* nodep, AstNUser*) { + // VarRef: LValue its reference + if (m_setRefLvalue) { + nodep->lvalue(true); + } + if (nodep->varp()) { + if (nodep->lvalue() && nodep->varp()->isInOnly()) { + nodep->v3error("Assigning to input variable: "<prettyName()); + } + } + nodep->iterateChildren(*this); + } + + // Nodes that start propagating down lvalues + virtual void visit(AstPin* nodep, AstNUser*) { + if (nodep->modVarp() && nodep->modVarp()->isOutput()) { + // When the varref's were created, we didn't know the I/O state + // Now that we do, and it's from a output, we know it's a lvalue + m_setRefLvalue = true; + nodep->iterateChildren(*this); + m_setRefLvalue = false; + } else { + nodep->iterateChildren(*this); + } + } + virtual void visit(AstNodeAssign* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + nodep->lhsp()->iterateAndNext(*this); + m_setRefLvalue = false; + nodep->rhsp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstFOpen* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + nodep->filep()->iterateAndNext(*this); + m_setRefLvalue = false; + nodep->filenamep()->iterateAndNext(*this); + nodep->modep()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstFClose* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + nodep->filep()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstReadMem* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + nodep->memp()->iterateAndNext(*this); + m_setRefLvalue = false; + nodep->filenamep()->iterateAndNext(*this); + nodep->lsbp()->iterateAndNext(*this); + nodep->msbp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + + // Nodes that change LValue state + virtual void visit(AstSel* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + nodep->lhsp()->iterateAndNext(*this); + // Only set lvalues on the from + m_setRefLvalue = false; + nodep->rhsp()->iterateAndNext(*this); + nodep->thsp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstNodeSel* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { // Only set lvalues on the from + nodep->lhsp()->iterateAndNext(*this); + m_setRefLvalue = false; + nodep->rhsp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstNodePreSel* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { // Only set lvalues on the from + nodep->lhsp()->iterateAndNext(*this); + m_setRefLvalue = false; + nodep->rhsp()->iterateAndNext(*this); + nodep->thsp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } + + virtual void visit(AstNode* nodep, AstNUser*) { + // Default: Just iterate + nodep->iterateChildren(*this); + } + +public: + // CONSTUCTORS + LinkLValueVisitor(AstNetlist* rootp) { + m_setRefLvalue = false; + rootp->accept(*this); + } + virtual ~LinkLValueVisitor() {} +}; + +//###################################################################### +// Link class functions + +void V3LinkLValue::linkLValue(AstNetlist* rootp) { + UINFO(4,__FUNCTION__<<": "<varp()) { nodep->varp()->usedParam(true); - if (nodep->lvalue() && nodep->varp()->isInOnly()) { - nodep->v3error("Assigning to input variable: "<prettyName()); - } - } - if (m_setRefLvalue) { - nodep->lvalue(true); } nodep->iterateChildren(*this); } @@ -104,46 +97,8 @@ private: m_ftaskp = NULL; } - virtual void visit(AstPin* nodep, AstNUser*) { - if (nodep->modVarp() && nodep->modVarp()->isOutput()) { - // When the varref's were created, we didn't know the I/O state - // Now that we do, and it's from a output, we know it's a lvalue - m_setRefLvalue = true; - nodep->iterateChildren(*this); - m_setRefLvalue = false; - } else { - nodep->iterateChildren(*this); - } - } - - virtual void visit(AstSel* nodep, AstNUser*) { - nodep->lhsp()->iterateAndNext(*this); - { // Only set lvalues on the from - bool last_setRefLvalue = m_setRefLvalue; - m_setRefLvalue = false; - nodep->rhsp()->iterateAndNext(*this); - nodep->thsp()->iterateAndNext(*this); - m_setRefLvalue = last_setRefLvalue; - } - } - virtual void visit(AstArraySel* nodep, AstNUser*) { - nodep->lhsp()->iterateAndNext(*this); - { // Only set lvalues on the from - bool last_setRefLvalue = m_setRefLvalue; - m_setRefLvalue = false; - nodep->rhsp()->iterateAndNext(*this); - m_setRefLvalue = last_setRefLvalue; - } - } void iterateSelTriop(AstNodePreSel* nodep) { - nodep->lhsp()->iterateAndNext(*this); - { // Only set lvalues on the from - bool last_setRefLvalue = m_setRefLvalue; - m_setRefLvalue = false; - nodep->rhsp()->iterateAndNext(*this); - nodep->thsp()->iterateAndNext(*this); - m_setRefLvalue = last_setRefLvalue; - } + nodep->iterateChildren(*this); } AstNode* newSubAttrOf(AstNode* underp, AstNode* fromp, AstAttrType attrType) { @@ -362,7 +317,6 @@ public: LinkResolveVisitor(AstNetlist* rootp) { m_ftaskp = NULL; m_modp = NULL; - m_setRefLvalue = false; // rootp->accept(*this); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 7704f2901..8019d9fe2 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -58,6 +58,7 @@ #include "V3LinkCells.h" #include "V3LinkDot.h" #include "V3LinkLevel.h" +#include "V3LinkLValue.h" #include "V3LinkResolve.h" #include "V3Localize.h" #include "V3Name.h" @@ -110,8 +111,10 @@ void process () { V3Link::link(v3Global.rootp()); // Cross-link dotted hierarchical references V3LinkDot::linkDotPrearrayed(v3Global.rootp()); - // Correct state we couldn't know at parse time, repair SEL's, set lvalue's + // Correct state we couldn't know at parse time, repair SEL's V3LinkResolve::linkResolve(v3Global.rootp()); + // Set Lvalue's in variable refs + V3LinkLValue::linkLValue(v3Global.rootp()); v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree")); V3Error::abortIfErrors(); diff --git a/src/verilog.y b/src/verilog.y index 25c3f11d2..3dc507e23 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -248,13 +248,11 @@ class AstSenTree; %type pathDotted %type idVarRef %type idVarXRef -%type lhIdVarRef -%type lhIdVarXRef %type taskRef %type funcRef -%type idRanged lhIdRanged -%type idArrayed lhIdArrayed -%type strAsInt strAsText lhConcIdList +%type idRanged +%type idArrayed +%type strAsInt strAsText concIdList %type taskDecl %type varDeclList funcDecl funcVarList funcVar %type funcRange @@ -460,7 +458,7 @@ genItem: modOrGenItem { $$ = $1; } | yCASE '(' expr ')' genCaseList yENDCASE { $$ = new AstGenCase($1,$3,$5); } | yIF expr genItemBlock %prec yLOWER_THAN_ELSE { $$ = new AstGenIf($1,$2,$3,NULL); } | yIF expr genItemBlock yELSE genItemBlock { $$ = new AstGenIf($1,$2,$3,$5); } - | yFOR '(' lhIdVarRef '=' expr ';' expr ';' lhIdVarRef '=' expr ')' genItemBlock + | yFOR '(' idVarRef '=' expr ';' expr ';' idVarRef '=' expr ')' genItemBlock { $$ = new AstGenFor($1, new AstAssign($4,$3,$5) ,$7, new AstAssign($10,$9,$11) ,$13);} @@ -485,8 +483,8 @@ assignList: assignOne { $$ = $1; } | assignList ',' assignOne { $$ = $1->addNext($3); } ; -assignOne: lhIdRanged '=' expr { $$ = new AstAssignW($2,$1,$3); } - | '{' lhConcIdList '}' '=' expr { $$ = new AstAssignW($1,$2,$5); } +assignOne: idRanged '=' expr { $$ = new AstAssignW($2,$1,$3); } + | '{' concIdList '}' '=' expr { $$ = new AstAssignW($1,$2,$5); } ; delayE: /* empty */ @@ -660,12 +658,12 @@ stmtList: stmtBlock { $$ = $1; } ; stmt: ';' { $$ = NULL; } - | lhIdRanged yLTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } - | lhIdRanged '=' delayE expr ';' { $$ = new AstAssign($2,$1,$4); } - | lhIdRanged '=' yD_FOPEN '(' expr ',' expr ')' ';' { $$ = new AstFOpen($3,$1,$5,$7); } - | yASSIGN lhIdRanged '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } - | '{' lhConcIdList '}' yLTE delayE expr ';' { $$ = new AstAssignDly($4,$2,$6); } - | '{' lhConcIdList '}' '=' delayE expr ';' { $$ = new AstAssign($4,$2,$6); } + | idRanged yLTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } + | idRanged '=' delayE expr ';' { $$ = new AstAssign($2,$1,$4); } + | idRanged '=' yD_FOPEN '(' expr ',' expr ')' ';' { $$ = new AstFOpen($3,$1,$5,$7); } + | yASSIGN idRanged '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } + | '{' concIdList '}' yLTE delayE expr ';' { $$ = new AstAssignDly($4,$2,$6); } + | '{' concIdList '}' '=' delayE expr ';' { $$ = new AstAssign($4,$2,$6); } | yD_C '(' cStrList ')' ';' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); } | yD_FCLOSE '(' idVarXRef ')' ';' { $$ = new AstFClose($1, $3); } | yD_FINISH ';' { $$ = new AstFinish($1); } @@ -683,18 +681,18 @@ stmt: ';' { $$ = NULL; } | yD_FDISPLAY '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); } | yD_FWRITE '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); } | yD_FWRITE '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); } - | yD_READMEMB '(' expr ',' lhIdArrayed ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); } - | yD_READMEMB '(' expr ',' lhIdArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); } - | yD_READMEMB '(' expr ',' lhIdArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } - | yD_READMEMH '(' expr ',' lhIdArrayed ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); } - | yD_READMEMH '(' expr ',' lhIdArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } - | yD_READMEMH '(' expr ',' lhIdArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } + | yD_READMEMB '(' expr ',' idArrayed ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); } + | yD_READMEMB '(' expr ',' idArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); } + | yD_READMEMB '(' expr ',' idArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } + | yD_READMEMH '(' expr ',' idArrayed ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); } + | yD_READMEMH '(' expr ',' idArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } + | yD_READMEMH '(' expr ',' idArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } ; stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); } | yIF expr stmtBlock %prec yLOWER_THAN_ELSE { $$ = new AstIf($1,$2,$3,NULL); } | yIF expr stmtBlock yELSE stmtBlock { $$ = new AstIf($1,$2,$3,$5); } - | yFOR '(' lhIdVarRef '=' expr ';' expr ';' lhIdVarRef '=' expr ')' stmtBlock + | yFOR '(' idVarRef '=' expr ';' expr ';' idVarRef '=' expr ')' stmtBlock { $$ = new AstFor($1, new AstAssign($4,$3,$5) ,$7, new AstAssign($10,$9,$11) ,$13);} @@ -877,21 +875,21 @@ gateIdE: /*empty*/ {} | yID {} ; -gateBuf: gateIdE '(' lhIdRanged ',' expr ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } +gateBuf: gateIdE '(' idRanged ',' expr ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } ; -gateNot: gateIdE '(' lhIdRanged ',' expr ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } +gateNot: gateIdE '(' idRanged ',' expr ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } ; -gateAnd: gateIdE '(' lhIdRanged ',' gateAndPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } +gateAnd: gateIdE '(' idRanged ',' gateAndPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } ; -gateNand: gateIdE '(' lhIdRanged ',' gateAndPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } +gateNand: gateIdE '(' idRanged ',' gateAndPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } ; -gateOr: gateIdE '(' lhIdRanged ',' gateOrPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } +gateOr: gateIdE '(' idRanged ',' gateOrPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } ; -gateNor: gateIdE '(' lhIdRanged ',' gateOrPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } +gateNor: gateIdE '(' idRanged ',' gateOrPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } ; -gateXor: gateIdE '(' lhIdRanged ',' gateXorPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } +gateXor: gateIdE '(' idRanged ',' gateXorPinList ')' { $$ = new AstAssignW ($2,$3,$5); $$->allowImplicit(true); } ; -gateXnor: gateIdE '(' lhIdRanged ',' gateXorPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } +gateXnor: gateIdE '(' idRanged ',' gateXorPinList ')' { $$ = new AstAssignW ($2,$3,new AstNot($4,$5)); $$->allowImplicit(true); } ; gateAndPinList: expr { $$ = $1; } @@ -964,13 +962,6 @@ pathDotted: yID { $$ = $1; } | pathDotted '.' yID { $$ = V3Read::newString(*$1+string(".")+*$3); } ; -lhIdVarRef: yID { $$ = new AstVarRef(CRELINE(),*$1,true);} - ; - -lhIdVarXRef: lhIdVarRef { $$ = $1; } - | pathDotted '.' yID { $$ = new AstVarXRef(CRELINE(),*$3,*$1,true);} - ; - idVarRef: yID { $$ = new AstVarRef(CRELINE(),*$1,false);} ; @@ -992,30 +983,20 @@ idArrayed: idVarXRef { $$ = $1; } | idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. ; -lhIdArrayed: lhIdVarXRef { $$ = $1; } - | lhIdArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. - ; - idRanged: idArrayed { $$ = $1; } | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); } | idArrayed '[' expr yPLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); } | idArrayed '[' expr yMINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); } ; -lhIdRanged: lhIdArrayed { $$ = $1; } - | lhIdArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); } - | lhIdArrayed '[' expr yPLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); } - | lhIdArrayed '[' expr yMINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); } - ; - strAsInt: ySTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));} ; strAsText: ySTRING { $$ = V3Parse::createTextQuoted(CRELINE(),*$1);} ; -lhConcIdList: lhIdRanged { $$ = $1; } - | lhConcIdList ',' lhIdRanged { $$ = new AstConcat($2,$1,$3); } +concIdList: idRanged { $$ = $1; } + | concIdList ',' idRanged { $$ = new AstConcat($2,$1,$3); } ; //************************************************ @@ -1177,3 +1158,7 @@ AstText* V3Parse::createTextQuoted(FileLine* fileline, string text) { string newtext = deQuote(fileline, text); return new AstText(fileline, newtext); } + +// Local Variables: +// compile-command: "cd obj_dbg ; /usr/bin/bison -y -d -v ../verilog.y ; cat y.output" +// End: