From 58b1ad1439cdeade1ba683e9785da9bbd63e5444 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 21 Dec 2006 21:53:51 +0000 Subject: [PATCH] Rework parser and add V3LinkParse so we can handle foo[#].foo[#].foo[#:#] etc git-svn-id: file://localhost/svn/verilator/trunk/verilator@862 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- Makefile.in | 6 +- src/Makefile_obj.in | 1 + src/V3Ast.h | 43 ++++++- src/V3AstNodes.cpp | 6 +- src/V3AstNodes.h | 69 ++++++++-- src/V3LinkParse.cpp | 236 +++++++++++++++++++++++++++++++++++ src/V3LinkParse.h | 36 ++++++ src/V3LinkResolve.cpp | 20 ++- src/Verilator.cpp | 3 + src/verilog.y | 102 +++++++-------- test_regress/t/t_func_wide.v | 4 +- 11 files changed, 446 insertions(+), 80 deletions(-) create mode 100644 src/V3LinkParse.cpp create mode 100644 src/V3LinkParse.h diff --git a/Makefile.in b/Makefile.in index 487dca548..4f7edbd41 100644 --- a/Makefile.in +++ b/Makefile.in @@ -155,15 +155,15 @@ test_vcs: all_nomsg test_c: all_nomsg @(cd test_c && $(MAKE)) test_c_debug: all_nomsg - @(cd test_c && $(MAKE) debug) + @(cd test_c && $(MAKE) test_debug) test_sc: all_nomsg @(cd test_sc && $(MAKE)) test_sc_debug: all_nomsg - @(cd test_sc && $(MAKE) debug) + @(cd test_sc && $(MAKE) test_debug) test_sp: all_nomsg @(cd test_sp && $(MAKE)) test_sp_debug: all_nomsg - @(cd test_sp && $(MAKE) debug) + @(cd test_sp && $(MAKE) test_debug) test_verilated: all_nomsg @(cd test_verilated && $(MAKE)) test_regress: all_nomsg diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index f48a9f877..10ad47fb9 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -143,6 +143,7 @@ RAW_OBJS = \ V3LinkDot.o \ V3LinkLevel.o \ V3LinkLValue.o \ + V3LinkParse.o \ V3LinkResolve.o \ V3Localize.o \ V3Name.o \ diff --git a/src/V3Ast.h b/src/V3Ast.h index 5a3910f05..85c76edcb 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -248,6 +248,33 @@ public: inline bool operator== (AstBranchPred::en lhs, AstBranchPred rhs) { return (lhs == rhs.m_e); } inline ostream& operator<<(ostream& os, AstBranchPred rhs) { return os<(_e)) {}; + operator en () const { return m_e; }; + const char* ascii() const { + static const char* names[] = { + "","VAR_MEM","VAR_ANY","TASK","FUNC"}; + return names[m_e];}; + }; + inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); } + inline bool operator== (AstParseRefExp lhs, AstParseRefExp::en rhs) { return (lhs.m_e == rhs); } + inline bool operator== (AstParseRefExp::en lhs, AstParseRefExp rhs) { return (lhs == rhs.m_e); } + inline ostream& operator<<(ostream& os, AstParseRefExp rhs) { return os<brokeExists(); } @@ -961,9 +988,13 @@ public: void inlinedDots(const string& flag) { m_inlinedDots = flag; } AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable void taskp(AstNodeFTask* taskp) { m_taskp=taskp; } - // op1 = Pin interconnection list - AstNode* pinsp() const { return op1p()->castNode(); } - void addPinsp(AstNode* nodep) { addOp1p(nodep); } + void name(const string& name) { m_name = name; } + void dotted(const string& name) { m_dotted = name; } + // op1 = namep + AstNode* namep() const { return op1p(); } + // op2 = Pin interconnection list + AstNode* pinsp() const { return op2p()->castNode(); } + void addPinsp(AstNode* nodep) { addOp2p(nodep); } }; //###################################################################### diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 825026759..0636814db 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -361,7 +361,11 @@ void AstSenTree::dump(ostream& str) { } void AstSenItem::dump(ostream& str) { this->AstNode::dump(str); - str<<" ["<AstNode::dump(str); + str<<" ["<AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index fb6b8b47b..876c272c9 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -756,6 +756,46 @@ struct AstGenerate : public AstNode { void addStmtp(AstNode* nodep) { addOp1p(nodep); } }; +struct AstParseRef : public AstNode { + // A reference to a variable, function or task + // We don't know which at parse time due to bison constraints + // The link stages will replace this with AstVarRef, or AstTaskRef, etc. + // Parents: math|stmt + // Children: TEXT|DOT|SEL* (or expression under sel) +private: + AstParseRefExp m_expect; // Type we think it should resolve to +public: + AstParseRef(FileLine* fl, AstParseRefExp expect, AstNode* lhsp) + :AstNode(fl), m_expect(expect) { setOp1p(lhsp); } + virtual ~AstParseRef() {} + virtual AstType type() const { return AstType::PARSEREF;} + virtual AstNode* clone() { return new AstParseRef(*this);} + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual void dump(ostream& str); + virtual V3Hash sameHash() const { return V3Hash(m_expect); } + virtual bool same(AstNode* samep) const { return expect() == samep->castParseRef()->expect(); } + virtual string emitVerilog() { V3ERROR_NA; return ""; } + virtual string emitOperator() { V3ERROR_NA; return ""; } + AstParseRefExp expect() const { return m_expect; } + // op1 = Components + AstNode* lhsp() const { return op1p(); } // op1 = List of statements +}; + +struct AstDot : public AstNode { + // A dot separating paths in a AstXRef, AstFuncRef or AstTaskRef + // These are elimiated in the link stage + AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + :AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); } + virtual ~AstDot() {} + virtual AstType type() const { return AstType::DOT;} + virtual AstNode* clone() { return new AstDot(*this);} + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual string emitVerilog() { V3ERROR_NA; return ""; } + virtual string emitOperator() { V3ERROR_NA; return ""; } + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } +}; + //###################################################################### struct AstTask : public AstNodeFTask { @@ -785,8 +825,8 @@ struct AstFunc : public AstNodeFTask { struct AstTaskRef : public AstNodeFTaskRef { // A reference to a task - AstTaskRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp) - :AstNodeFTaskRef(fl, name, dotted, pinsp) {} + AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + :AstNodeFTaskRef(fl, namep, pinsp) {} virtual ~AstTaskRef() {} virtual AstType type() const { return AstType::TASKREF;} virtual AstNode* clone() { return new AstTaskRef(*this);} @@ -795,8 +835,8 @@ struct AstTaskRef : public AstNodeFTaskRef { struct AstFuncRef : public AstNodeFTaskRef { // A reference to a function - AstFuncRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp) - :AstNodeFTaskRef(fl, name, dotted, pinsp) {} + AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + :AstNodeFTaskRef(fl, namep, pinsp) {} virtual ~AstFuncRef() {} virtual AstType type() const { return AstType::FUNCREF;} virtual AstNode* clone() { return new AstFuncRef(*this);} @@ -816,8 +856,11 @@ public: class Settle {}; // for creator type-overload selection class Never {}; // for creator type-overload selection AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNodeVarRef* varrefp) - : AstNode(fl) { - m_edgeType = edgeType; + : AstNode(fl), m_edgeType(edgeType) { + setOp1p(varrefp); + } + AstSenItem(FileLine* fl, AstEdgeType edgeType, AstParseRef* varrefp) + : AstNode(fl), m_edgeType(edgeType) { setOp1p(varrefp); } AstSenItem(FileLine* fl, Combo) @@ -1175,10 +1218,12 @@ public: }; struct AstDisplay : public AstNodePli { + // Parents: stmtlist + // Children: file which must be a varref, MATH to print private: char m_newline; public: - AstDisplay(FileLine* fileline, char newln, const string& text, AstNodeVarRef* filep, AstNode* exprsp) + AstDisplay(FileLine* fileline, char newln, const string& text, AstNode* filep, AstNode* exprsp) : AstNodePli (fileline, text, exprsp) { setNOp2p(filep); m_newline = newln; @@ -1200,7 +1245,7 @@ public: && text()==samep->castDisplay()->text(); } // op1 used by AstNodePli char newline() const { return m_newline; } // * = Add a newline for $display - AstNodeVarRef* filep() const { return op2p()->castVarRef(); } + AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } AstNode* scopeAttrp() const { return op3p(); } AstText* scopeTextp() const { return op3p()->castText(); } @@ -1208,7 +1253,9 @@ public: }; struct AstFClose : public AstNodeStmt { - AstFClose(FileLine* fileline, AstNodeVarRef* filep) + // Parents: stmtlist + // Children: file which must be a varref + AstFClose(FileLine* fileline, AstNode* filep) : AstNodeStmt (fileline) { setNOp2p(filep); } @@ -1224,7 +1271,7 @@ struct AstFClose : public AstNodeStmt { virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } - AstNodeVarRef* filep() const { return op2p()->castVarRef(); } + AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; @@ -1247,7 +1294,7 @@ struct AstFOpen : public AstNodeStmt { virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } - AstNodeVarRef* filep() const { return op1p()->castVarRef(); } + AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } AstNode* modep() const { return op3p(); } }; diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp new file mode 100644 index 000000000..23e30f5eb --- /dev/null +++ b/src/V3LinkParse.cpp @@ -0,0 +1,236 @@ +// $Id$ +//************************************************************************* +// DESCRIPTION: Verilator: Parse 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. +// +//************************************************************************* +// LinkParse TRANSFORMATIONS: +// Top-down traversal +// Replace ParseRef with VarRef, VarXRef, FuncRef or TaskRef +// TASKREF(PARSEREF(DOT(TEXTa,TEXTb))) -> TASKREF(a,b) +// PARSEREF(TEXTa) -> VARREF(a) +// PARSEREF(DOT(TEXTa,TEXTb)) -> VARXREF("a","b") +// PARSEREF(DOT(DOT(TEXTa,TEXTb),TEXTc)) -> VARXREF("a.b","c") +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" +#include +#include +#include +#include +#include +#include + +#include "V3Global.h" +#include "V3LinkParse.h" +#include "V3Ast.h" + +//###################################################################### +// Link state, as a visitor of each AstNode + +class LinkParseVisitor : public AstNVisitor { +private: + // NODE STATE + // Cleared on netlist + // AstNode::user() -> bool. True if processed + + // STATE + string m_dotText; // Dotted module text we are building for a dotted node, passed up + bool m_inModDot; // We're inside module part of dotted name + AstParseRefExp m_exp; // Type of data we're looking for + AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref + + //int debug() { return 9; } + + // METHODS + void checkExpected(AstNode* nodep) { + if (m_exp != AstParseRefExp::NONE) { + nodep->v3fatalSrc("Tree syntax error: Not expecting "<type()<<" under a "<backp()->type()); + m_exp = AstParseRefExp::NONE; + } + } + + // VISITs + virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { + if (!nodep->user()) { + nodep->user(true); // Process only once. + UINFO(5," "<namep()) { + m_exp = AstParseRefExp::FUNC; + nodep->namep()->accept(*this); // No next, we don't want to do the edit + m_exp = AstParseRefExp::NONE; + if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name"); + nodep->name(m_baseTextp->text()); + nodep->dotted(m_dotText); + nodep->namep()->unlinkFrBack()->deleteTree(); m_baseTextp=NULL; + } + nodep->iterateChildren(*this); + } + } + virtual void visit(AstParseRef* nodep, AstNUser*) { + // VarRef: Parse its reference + UINFO(5," "<lhsp()->unlinkFrBack(); + nodep->replaceWith(lhsp); + + // Process lower nodes + m_dotText = ""; + m_baseTextp = NULL; + if (m_exp == AstParseRefExp::FUNC) { + lhsp->accept(*this); + // Return m_dotText to invoker + } else if (nodep->expect() == AstParseRefExp::VAR_MEM + || nodep->expect() == AstParseRefExp::VAR_ANY) { + m_exp = nodep->expect(); + lhsp->accept(*this); + m_exp = AstParseRefExp::NONE; + if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name"); + if (m_dotText == "") { + AstNode* newp = new AstVarRef(nodep->fileline(), m_baseTextp->text(), false); // lvalue'ness computed later + m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL; + } else { + AstNode* newp = new AstVarXRef(nodep->fileline(), m_baseTextp->text(), m_dotText, false); // lvalue'ness computed later + m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL; + } + } else { + nodep->v3fatalSrc("Unknown ParseRefExp type\n"); + } + } + nodep->deleteTree(); nodep=NULL; + } + virtual void visit(AstDot* nodep, AstNUser*) { + UINFO(5," "<lhsp()->iterateAndNext(*this); + string namelhs = m_dotText; + + m_dotText = ""; + nodep->rhsp()->iterateAndNext(*this); + m_dotText = namelhs + "." + m_dotText; + } else { // Not in ModDot, so this is {modulepart} DOT {name} + m_inModDot = true; + m_dotText = ""; + nodep->lhsp()->iterateAndNext(*this); + string namelhs = m_dotText; + + m_inModDot = false; + m_dotText = ""; + nodep->rhsp()->iterateAndNext(*this); + m_dotText = namelhs; + + nodep->replaceWith(nodep->rhsp()->unlinkFrBack()); nodep->deleteTree(); nodep=NULL; + } + } + virtual void visit(AstSelBit* nodep, AstNUser*) { + if (!nodep->user()) { + nodep->user(true); // Process only once. + if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart} + m_dotText = ""; + nodep->lhsp()->iterateAndNext(*this); + if (AstConst* constp = nodep->rhsp()->castConst()) { + m_dotText = m_dotText+"__BRA__"+cvtToStr(constp->asInt())+"__KET__"; + } else { + nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference"); + } + // And pass up m_dotText + } else if (m_exp==AstParseRefExp::FUNC) { + nodep->v3error("Syntax Error: Range selection '[]' is not allowed as part of function names"); + } else { + nodep->lhsp()->iterateAndNext(*this); + AstParseRefExp lastExp = m_exp; + AstText* lasttextp = m_baseTextp; + { + m_exp = AstParseRefExp::NONE; + nodep->rhsp()->iterateAndNext(*this); + } + m_baseTextp = lasttextp; + m_exp = lastExp; + } + } + } + virtual void visit(AstNodePreSel* nodep, AstNUser*) { + // Excludes simple AstSel, see above + if (!nodep->user()) { + nodep->user(true); // Process only once. + if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart} + nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference"); + } else if (m_exp==AstParseRefExp::FUNC) { + nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed as part of function names"); + } else if (m_exp==AstParseRefExp::VAR_MEM) { + nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed when expecting memory reference"); + } else { + nodep->lhsp()->iterateAndNext(*this); + AstParseRefExp lastExp = m_exp; + AstText* lasttextp = m_baseTextp; + { + m_exp = AstParseRefExp::NONE; + nodep->rhsp()->iterateAndNext(*this); + nodep->thsp()->iterateAndNext(*this); + } + m_baseTextp = lasttextp; + m_exp = lastExp; + } + } + } + virtual void visit(AstText* nodep, AstNUser*) { + if (!nodep->user()) { + nodep->user(true); // Process only once. + if (m_exp != AstParseRefExp::NONE) { + UINFO(7," "<text(); + } else { + if (m_baseTextp) nodep->v3fatalSrc("Multiple low-level ParseRef text's found; which one is var name?"); + m_baseTextp = nodep; + } + } + } + } + virtual void visit(AstNode* nodep, AstNUser*) { + // Default: Just iterate + checkExpected(nodep); // So we detect node types we forgot to list here + nodep->iterateChildren(*this); + } + +public: + // CONSTUCTORS + LinkParseVisitor(AstNetlist* rootp) { + m_inModDot = false; + m_exp = AstParseRefExp::NONE; + m_baseTextp = NULL; + AstNode::userClearTree(); // userp() used on entire tree + rootp->accept(*this); + } + virtual ~LinkParseVisitor() {} +}; + +//###################################################################### +// Link class functions + +void V3LinkParse::linkParse(AstNetlist* rootp) { + UINFO(4,__FUNCTION__<<": "<iterateChildren(*this); + if (AstSel* selp = nodep->sensp()->castSel()) { + AstNode* fromp = selp->fromp()->unlinkFrBack(); + selp->replaceWith(fromp); selp->deleteTree(); selp=NULL; + } + if (!nodep->sensp()->castNodeVarRef()) { + nodep->v3error("Unsupported: Complex statement in sensitivity list"); + } + } + void iterateSelTriop(AstNodePreSel* nodep) { nodep->iterateChildren(*this); } @@ -284,11 +296,15 @@ private: } virtual void visit(AstFOpen* nodep, AstNUser*) { nodep->iterateChildren(*this); - expectDescriptor(nodep, nodep->filep()); + expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); } virtual void visit(AstFClose* nodep, AstNUser*) { nodep->iterateChildren(*this); - expectDescriptor(nodep, nodep->filep()); + expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); + } + virtual void visit(AstDisplay* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); } virtual void visit(AstScCtor* nodep, AstNUser*) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 8019d9fe2..df8186653 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -58,6 +58,7 @@ #include "V3LinkCells.h" #include "V3LinkDot.h" #include "V3LinkLevel.h" +#include "V3LinkParse.h" #include "V3LinkLValue.h" #include "V3LinkResolve.h" #include "V3Localize.h" @@ -107,6 +108,8 @@ void process () { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree")); V3Error::abortIfErrors(); + // Convert parseref's to varrefs, and other directly post parsing fixups + V3LinkParse::linkParse(v3Global.rootp()); // Cross-link signal names V3Link::link(v3Global.rootp()); // Cross-link dotted hierarchical references diff --git a/src/verilog.y b/src/verilog.y index 389861170..b7ccb2637 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -18,13 +18,6 @@ //************************************************************************* // Original code here by Paul Wasson and Duane Galbi //************************************************************************* -//General Hints -//----------------- -// 1) {A,B} <= HI; -> expands to two DISTINCT assignment nodes in AST tree -// -// 2) inv a(in1,out1), b(in2,out2); -> expanded into two AST instance_nodes -// -//************************************************************************* %{ /* $Id$ */ @@ -121,6 +114,7 @@ class AstSenTree; AstVar* varp; AstVarRef* varrefp; AstNodeVarRef* varnodep; + AstParseRef* parserefp; } %token yINTNUM @@ -233,7 +227,6 @@ class AstSenTree; %type instnameList instname %type cellpinList cellpinlist2 cellpinitemE instparamListE %type defpList defpOne -%type ignoreRangeE %type sensitivityE %type senList senitem senitemEdge %type stmtBlock stmtList stmt stateCaseForIf @@ -243,13 +236,13 @@ class AstSenTree; %type casecondList assignList assignOne %type constExpr exprNoStr expr exprPsl exprStrText %type eList cateList cStrList -%type pathDotted %type varRefBase -%type idVarXRef +%type varRefMem +%type varRefDotBit %type taskRef %type funcRef -%type varRefDotBit %type idArrayed +%type idDotted %type strAsInt strAsText concIdList %type taskDecl %type varDeclList funcDecl funcVarList funcVar @@ -628,16 +621,12 @@ senList: senitem { $$ = $1; } ; senitem: senitemEdge { $$ = $1; } - | idVarXRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); } +//FIX need range ignoring to be stripped later, this was simple varXRef + | varRefDotBit { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); } ; -senitemEdge: yPOSEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); } - | yNEGEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); } - ; - -ignoreRangeE: /* empty */ { $$ = NULL; } /* ignored */ - | '[' expr ']' { $$ = NULL; } /* ignored */ - | '[' expr ':' expr ']' { $$ = NULL; } /* ignored */ +senitemEdge: yPOSEDGE varRefDotBit { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); } + | yNEGEDGE varRefDotBit { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); } ; stmtBlock: stmt { $$ = $1; } @@ -663,7 +652,7 @@ stmt: ';' { $$ = NULL; } | '{' 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_FCLOSE '(' varRefDotBit ')' ';' { $$ = new AstFClose($1, $3); } | yD_FINISH ';' { $$ = new AstFinish($1); } | yD_STOP ';' { $$ = new AstStop($1); } | yVL_COVER_OFF { $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); } @@ -675,16 +664,16 @@ stmt: ';' { $$ = NULL; } | yD_DISPLAY '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,$5); } | yD_WRITE '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,NULL); } | yD_WRITE '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,$5); } - | yD_FDISPLAY '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,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 ',' 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); } + | yD_FDISPLAY '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,NULL); } + | yD_FDISPLAY '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); } + | yD_FWRITE '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); } + | yD_FWRITE '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); } + | yD_READMEMB '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); } + | yD_READMEMB '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); } + | yD_READMEMB '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } + | yD_READMEMH '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); } + | yD_READMEMH '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } + | yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } ; stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); } @@ -956,37 +945,40 @@ specifyJunk: dterm {} /* ignored */ //************************************************ // IDs -pathDotted: yID { $$ = $1; } - | pathDotted '.' yID { $$ = V3Read::newString(*$1+string(".")+*$3); } - ; -varRefBase: yID { $$ = new AstVarRef(CRELINE(),*$1,false);} - ; - -idVarXRef: varRefBase { $$ = $1; } - | pathDotted '.' yID { $$ = new AstVarXRef(CRELINE(),*$3,*$1,false);} - ; - -taskRef: yID { $$ = new AstTaskRef(CRELINE(),*$1,"",NULL);} - | yID '(' eList ')' { $$ = new AstTaskRef(CRELINE(),*$1,"",$3);} - | pathDotted '.' yID { $$ = new AstTaskRef(CRELINE(),*$3,*$1,NULL);} - | pathDotted '.' yID '(' eList ')' { $$ = new AstTaskRef(CRELINE(),*$3,*$1,$5);} - ; - -funcRef: yID '(' eList ')' { $$ = new AstFuncRef($2,*$1,"",$3); } - | pathDotted '.' yID '(' eList ')' { $$ = new AstFuncRef($4,*$3,*$1,$5); } - ; - -idArrayed: idVarXRef { $$ = $1; } - | idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. - ; - -varRefDotBit: idArrayed { $$ = $1; } +// Single component of dotted path, maybe [#]. +// Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part), +// we'll assume so and cleanup later. +idArrayed: yID { $$ = new AstText(CRELINE(),*$1); } + | idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. | 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); } ; +idDotted: idArrayed { $$ = $1; } + | idDotted '.' idArrayed { $$ = new AstDot($2,$1,$3); } + ; + +// VarRef without any dots or vectorizaion +varRefBase: yID { $$ = new AstVarRef(CRELINE(),*$1,false);} + ; + +// VarRef to a Memory +varRefMem: idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_MEM, $1); } + ; + +// VarRef to dotted, and/or arrayed, and/or bit-ranged variable +varRefDotBit: idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_ANY, $1); } + ; + +taskRef: idDotted { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),NULL);} + | idDotted '(' eList ')' { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),$3);} + ; + +funcRef: idDotted '(' eList ')' { $$ = new AstFuncRef($2,new AstParseRef($1->fileline(), AstParseRefExp::FUNC, $1), $3); } + ; + strAsInt: ySTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));} ; diff --git a/test_regress/t/t_func_wide.v b/test_regress/t/t_func_wide.v index 54505d0bc..2749c8627 100644 --- a/test_regress/t/t_func_wide.v +++ b/test_regress/t/t_func_wide.v @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed into the Public Domain, for any use, @@ -33,7 +33,7 @@ module muxtop ( output reg [ 31:0 ] o ); - always @ ( i ) + always @ ( i[43:0] ) // Verify we ignore ranges on always statement sense lists o = MUX( i[39:0] ); function [31:0] MUX;