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
This commit is contained in:
Wilson Snyder 2006-12-21 21:53:51 +00:00
parent 94d0aa2058
commit 58b1ad1439
11 changed files with 446 additions and 80 deletions

View File

@ -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

View File

@ -143,6 +143,7 @@ RAW_OBJS = \
V3LinkDot.o \
V3LinkLevel.o \
V3LinkLValue.o \
V3LinkParse.o \
V3LinkResolve.o \
V3Localize.o \
V3Name.o \

View File

@ -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<<rhs.ascii(); }
//######################################################################
class AstParseRefExp {
public:
enum en {
NONE, // Used in V3LinkParse only
VAR_MEM,
VAR_ANY,
TASK,
FUNC,
_ENUM_END
};
enum en m_e;
inline AstParseRefExp() : m_e(NONE) {};
inline AstParseRefExp (en _e) : m_e(_e) {};
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_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<<rhs.ascii(); }
//######################################################################
// AstNUser - Generic pointer base class for AST User nodes.
// - Also used to allow parameter passing up/down iterate calls
@ -943,10 +970,10 @@ private:
string m_dotted; // Dotted part of scope to task or ""
string m_inlinedDots; // Dotted hiearchy flattened out
public:
AstNodeFTaskRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp)
AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp)
:AstNode(fl)
, m_taskp(NULL), m_name(name), m_dotted(dotted) {
addNOp1p(pinsp);
, m_taskp(NULL) {
setOp1p(namep); addNOp2p(pinsp);
}
virtual ~AstNodeFTaskRef() {}
virtual bool broken() const { return m_taskp && !m_taskp->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); }
};
//######################################################################

View File

@ -361,7 +361,11 @@ void AstSenTree::dump(ostream& str) {
}
void AstSenItem::dump(ostream& str) {
this->AstNode::dump(str);
str<<" ["<<m_edgeType.ascii()<<"]";
str<<" ["<<edgeType().ascii()<<"]";
}
void AstParseRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" ["<<expect().ascii()<<"]";
}
void AstActive::dump(ostream& str) {
this->AstNode::dump(str);

View File

@ -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(); }
};

236
src/V3LinkParse.cpp Normal file
View File

@ -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 <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <map>
#include <algorithm>
#include <vector>
#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 "<<nodep->type()<<" under a "<<nodep->backp()->type());
m_exp = AstParseRefExp::NONE;
}
}
// VISITs
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (!nodep->user()) {
nodep->user(true); // Process only once.
UINFO(5," "<<nodep<<endl);
checkExpected(nodep);
// Due to a need to get the arguments, the ParseRefs are under here,
// rather then the NodeFTaskRef under the ParseRef.
if (nodep->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," "<<nodep<<endl);
// May be a varref inside a select, etc, so save state and recurse
{
// Replace the parsed item with its child IE the selection tree down to the varref itself
// Do this before iterating, so we don't have to process the edited tree twice
AstNode* lhsp = nodep->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," "<<nodep<<endl);
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
m_dotText = "";
nodep->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," "<<nodep<<endl);
if (m_inModDot) { // Dotted part, just pass up
m_dotText = nodep->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__<<": "<<endl);
LinkParseVisitor visitor(rootp);
}

36
src/V3LinkParse.h Normal file
View File

@ -0,0 +1,36 @@
// $Id$ //-*- C++ -*-
//*************************************************************************
// DESCRIPTION: Verilator: Link modules/signals together
//
// 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.
//
//*************************************************************************
#ifndef _V3LINKPARSE_H_
#define _V3LINKPARSE_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
//============================================================================
class V3LinkParse {
public:
static void linkParse(AstNetlist* nodep);
};
#endif // Guard

View File

@ -97,6 +97,18 @@ private:
m_ftaskp = NULL;
}
virtual void visit(AstSenItem* nodep, AstNUser*) {
// Remove bit selects, and bark if it's not a simple variable
nodep->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*) {

View File

@ -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

View File

@ -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<nump> yINTNUM
@ -233,7 +227,6 @@ class AstSenTree;
%type<nodep> instnameList instname
%type<pinp> cellpinList cellpinlist2 cellpinitemE instparamListE
%type<nodep> defpList defpOne
%type<nodep> ignoreRangeE
%type<sentreep> sensitivityE
%type<senitemp> senList senitem senitemEdge
%type<nodep> stmtBlock stmtList stmt stateCaseForIf
@ -243,13 +236,13 @@ class AstSenTree;
%type<nodep> casecondList assignList assignOne
%type<nodep> constExpr exprNoStr expr exprPsl exprStrText
%type<nodep> eList cateList cStrList
%type<strp> pathDotted
%type<varrefp> varRefBase
%type<varnodep> idVarXRef
%type<parserefp> varRefMem
%type<parserefp> varRefDotBit
%type<taskrefp> taskRef
%type<funcrefp> funcRef
%type<nodep> varRefDotBit
%type<nodep> idArrayed
%type<nodep> idDotted
%type<nodep> strAsInt strAsText concIdList
%type<nodep> taskDecl
%type<nodep> 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)));}
;

View File

@ -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;