2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Resolve module/signal name references
|
|
|
|
|
//
|
2008-04-25 12:14:27 +00:00
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2009-01-02 16:47:39 +00:00
|
|
|
|
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// LinkResolve TRANSFORMATIONS:
|
|
|
|
|
// Top-down traversal
|
|
|
|
|
// Extracts:
|
|
|
|
|
// Add SUB so that we subtract off the "base 0-start" of the array
|
|
|
|
|
// SelBit: Convert to ArraySel
|
|
|
|
|
// Add SUB so that we subtract off the "base 0-start" of the array
|
|
|
|
|
// File operations
|
|
|
|
|
// Convert normal var to FILE* type
|
2008-11-23 02:10:20 +00:00
|
|
|
|
// SenItems: Convert pos/negedge of non-simple signals to temporaries
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
2006-12-18 19:20:45 +00:00
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2008-06-30 17:11:25 +00:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdarg>
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3LinkResolve.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class LinkResolveVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Entire netlist:
|
|
|
|
|
// AstCaseItem::user2() // bool Moved default caseitems
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstUser2InUse m_inuser2;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// STATE
|
|
|
|
|
// Below state needs to be preserved between each module call.
|
|
|
|
|
AstModule* m_modp; // Current module
|
|
|
|
|
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
2007-03-06 21:43:38 +00:00
|
|
|
|
AstVAssert* m_assertp; // Current assertion
|
2008-11-23 02:10:20 +00:00
|
|
|
|
int m_senitemCvtNum; // Temporary signal counter
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// METHODS
|
2009-01-21 21:56:50 +00:00
|
|
|
|
static int debug() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
|
|
|
|
return level;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// VISITs
|
|
|
|
|
virtual void visit(AstModule* nodep, AstNUser*) {
|
|
|
|
|
// Module: Create sim table for entire module and iterate
|
|
|
|
|
UINFO(8,"MODULE "<<nodep<<endl);
|
|
|
|
|
m_modp = nodep;
|
2008-11-23 02:10:20 +00:00
|
|
|
|
m_senitemCvtNum = 0;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
}
|
2007-03-06 21:43:38 +00:00
|
|
|
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
|
|
|
|
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
|
|
|
|
m_assertp = nodep;
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
m_assertp = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2009-11-07 04:16:06 +00:00
|
|
|
|
if (nodep->isIO() && !nodep->dtypeSkipRefp()->castBasicDType()) {
|
2009-11-05 03:31:53 +00:00
|
|
|
|
nodep->v3error("Unsupported: Inputs and outputs must be simple data types; no arrays");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (m_ftaskp) nodep->funcLocal(true);
|
2007-03-02 22:24:51 +00:00
|
|
|
|
if (nodep->isSigModPublic()) {
|
|
|
|
|
nodep->sigModPublic(false); // We're done with this attribute
|
|
|
|
|
m_modp->modPublic(true); // Avoid flattening if signals are exposed
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
|
|
|
|
// VarRef: Resolve its reference
|
|
|
|
|
if (nodep->varp()) {
|
|
|
|
|
nodep->varp()->usedParam(true);
|
|
|
|
|
}
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
|
|
|
|
// NodeTask: Remember its name for later resolution
|
|
|
|
|
// Remember the existing symbol table scope
|
|
|
|
|
m_ftaskp = nodep;
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
m_ftaskp = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2006-12-21 21:53:51 +00:00
|
|
|
|
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
|
|
|
|
// Remove bit selects, and bark if it's not a simple variable
|
|
|
|
|
nodep->iterateChildren(*this);
|
2008-11-23 02:10:20 +00:00
|
|
|
|
if (nodep->isClocked()) {
|
|
|
|
|
// If it's not a simple variable wrap in a temporary
|
|
|
|
|
// This is a bit unfortunate as we haven't done width resolution
|
|
|
|
|
// and any width errors will look a bit odd, but it works.
|
|
|
|
|
AstNode* sensp = nodep->sensp();
|
|
|
|
|
if (sensp
|
|
|
|
|
&& !sensp->castNodeVarRef()
|
|
|
|
|
&& !sensp->castConst()) {
|
|
|
|
|
// Make a new temp wire
|
|
|
|
|
string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
|
|
|
|
|
AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
|
2009-11-05 03:31:53 +00:00
|
|
|
|
AstLogicPacked(), 1);
|
2008-11-23 02:10:20 +00:00
|
|
|
|
// We can't just add under the module, because we may be inside a generate, begin, etc.
|
|
|
|
|
// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
|
|
|
|
|
AstNode* addwherep = nodep; // Add to this element's next
|
|
|
|
|
while (addwherep->castSenItem()
|
|
|
|
|
|| addwherep->castSenTree()) {
|
|
|
|
|
addwherep = addwherep->backp();
|
|
|
|
|
}
|
|
|
|
|
if (!addwherep->castAlways()) { // Assertion perhaps?
|
|
|
|
|
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
|
|
|
|
|
addwherep = m_modp;
|
|
|
|
|
}
|
|
|
|
|
addwherep->addNext(newvarp);
|
|
|
|
|
|
|
|
|
|
sensp->replaceWith(new AstVarRef (sensp->fileline(), newvarp, false));
|
|
|
|
|
AstAssignW* assignp = new AstAssignW
|
|
|
|
|
(sensp->fileline(),
|
|
|
|
|
new AstVarRef(sensp->fileline(), newvarp, true),
|
|
|
|
|
sensp);
|
|
|
|
|
addwherep->addNext(assignp);
|
2007-01-03 03:30:30 +00:00
|
|
|
|
}
|
2008-11-23 02:10:20 +00:00
|
|
|
|
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
|
|
|
|
|
bool did=1;
|
|
|
|
|
while (did) {
|
|
|
|
|
did=0;
|
|
|
|
|
if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) {
|
|
|
|
|
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
|
|
|
|
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
|
|
|
|
did=1;
|
|
|
|
|
}
|
|
|
|
|
// NodeSel doesn't include AstSel....
|
|
|
|
|
if (AstSel* selp = nodep->sensp()->castSel()) {
|
|
|
|
|
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
|
|
|
|
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
|
|
|
|
did=1;
|
|
|
|
|
}
|
2009-10-25 20:53:55 +00:00
|
|
|
|
if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
|
|
|
|
|
AstNode* fromp = selp->lhsp()->unlinkFrBack();
|
|
|
|
|
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
|
|
|
|
did=1;
|
|
|
|
|
}
|
2007-01-03 03:30:30 +00:00
|
|
|
|
}
|
2006-12-21 21:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
if (!nodep->sensp()->castNodeVarRef()) {
|
2007-01-03 03:30:30 +00:00
|
|
|
|
if (debug()) nodep->dumpTree(cout,"-tree: ");
|
2006-12-21 21:53:51 +00:00
|
|
|
|
nodep->v3error("Unsupported: Complex statement in sensitivity list");
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-07 14:37:59 +00:00
|
|
|
|
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
|
|
|
|
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
|
|
|
|
|
}
|
2006-12-21 21:53:51 +00:00
|
|
|
|
|
2009-10-25 20:53:55 +00:00
|
|
|
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
|
|
|
|
if (!nodep->attrp()) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
// Constification may change the fromp() to a constant, which will loose the
|
|
|
|
|
// variable we're extracting from (to determine MSB/LSB/endianness/etc.)
|
|
|
|
|
// So we replicate it in another node
|
|
|
|
|
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
|
|
|
|
|
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
|
|
|
|
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
|
|
|
|
|
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
|
|
|
|
|
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
|
|
|
|
varrefp->cloneTree(false)));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
|
|
|
|
// Move default caseItems to the bottom of the list
|
|
|
|
|
// That saves us from having to search each case list twice, for non-defaults and defaults
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
if (!nodep->user2() && nodep->isDefault() && nodep->nextp()) {
|
|
|
|
|
nodep->user2(true);
|
|
|
|
|
AstNode* nextp = nodep->nextp();
|
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
nextp->addNext(nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstPragma* nodep, AstNUser*) {
|
|
|
|
|
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
|
|
|
|
|
if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module\n");
|
|
|
|
|
m_modp->modPublic(true);
|
|
|
|
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
|
|
|
|
|
if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task\n");
|
|
|
|
|
m_ftaskp->taskPublic(true);
|
|
|
|
|
m_modp->modPublic(true); // Need to get to the task...
|
|
|
|
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
|
|
|
|
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without
|
|
|
|
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-01 18:15:10 +00:00
|
|
|
|
void expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) {
|
2008-06-30 18:31:58 +00:00
|
|
|
|
// Check display arguments
|
|
|
|
|
bool inPct = false;
|
|
|
|
|
for (const char* inp = format.c_str(); *inp; inp++) {
|
2008-07-01 18:15:10 +00:00
|
|
|
|
char ch = tolower(*inp); // Breaks with iterators...
|
2008-06-30 18:31:58 +00:00
|
|
|
|
if (!inPct && ch=='%') {
|
|
|
|
|
inPct = true;
|
|
|
|
|
} else if (inPct) {
|
|
|
|
|
inPct = false;
|
2009-09-11 23:25:42 +00:00
|
|
|
|
switch (tolower(ch)) {
|
2008-06-30 18:31:58 +00:00
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
|
inPct = true;
|
|
|
|
|
break;
|
|
|
|
|
case '%': break; // %% - just output a %
|
2008-07-01 18:15:10 +00:00
|
|
|
|
case 'm': // %m - auto insert "name"
|
|
|
|
|
if (isScan) nodep->v3error("Unsupported: %m in $fscanf");
|
|
|
|
|
break;
|
2008-06-30 18:31:58 +00:00
|
|
|
|
default: // Most operators, just move to next argument
|
|
|
|
|
if (!V3Number::displayedFmtLegal(ch)) {
|
|
|
|
|
nodep->v3error("Unknown $display format code: %"<<ch);
|
|
|
|
|
} else {
|
|
|
|
|
if (!argp) {
|
|
|
|
|
nodep->v3error("Missing arguments for $display format");
|
|
|
|
|
} else {
|
|
|
|
|
argp = argp->nextp();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} // switch
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (argp) {
|
|
|
|
|
argp->v3error("Extra arguments for $display format\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
|
2008-06-26 12:52:02 +00:00
|
|
|
|
if (!filep) nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
|
|
|
|
|
}
|
2008-06-30 18:31:58 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstFOpen* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2006-12-21 21:53:51 +00:00
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstFClose* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2006-12-21 21:53:51 +00:00
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
}
|
2008-06-26 12:52:02 +00:00
|
|
|
|
virtual void visit(AstFEof* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
}
|
2008-06-27 12:45:05 +00:00
|
|
|
|
virtual void visit(AstFFlush* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2008-07-16 18:06:08 +00:00
|
|
|
|
if (nodep->filep()) {
|
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
}
|
2008-06-27 12:45:05 +00:00
|
|
|
|
}
|
2008-06-28 00:04:20 +00:00
|
|
|
|
virtual void visit(AstFGetC* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstFGetS* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
}
|
2008-07-01 18:15:10 +00:00
|
|
|
|
virtual void visit(AstFScanF* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
|
|
|
|
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstSScanF* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
|
|
|
|
}
|
2006-12-21 21:53:51 +00:00
|
|
|
|
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
2008-07-01 18:15:10 +00:00
|
|
|
|
expectFormat(nodep, nodep->text(), nodep->exprsp(), false);
|
2007-03-06 21:43:38 +00:00
|
|
|
|
if (!m_assertp
|
|
|
|
|
&& (nodep->displayType() == AstDisplayType::INFO
|
|
|
|
|
|| nodep->displayType() == AstDisplayType::WARNING
|
|
|
|
|
|| nodep->displayType() == AstDisplayType::ERROR
|
|
|
|
|
|| nodep->displayType() == AstDisplayType::FATAL)) {
|
|
|
|
|
nodep->v3error(nodep->verilogKwd()+" only allowed under a assertion.");
|
|
|
|
|
}
|
2007-06-14 16:41:32 +00:00
|
|
|
|
if (nodep->displayType().needScopeTracking()
|
2009-09-11 23:25:42 +00:00
|
|
|
|
|| nodep->name().find("%m") != string::npos
|
|
|
|
|
|| nodep->name().find("%M") != string::npos) {
|
2007-06-14 16:41:32 +00:00
|
|
|
|
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstScCtor* nodep, AstNUser*) {
|
|
|
|
|
// Constructor info means the module must remain public
|
|
|
|
|
m_modp->modPublic(true);
|
2006-08-30 17:27:53 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstScDtor* nodep, AstNUser*) {
|
|
|
|
|
// Destructor info means the module must remain public
|
|
|
|
|
m_modp->modPublic(true);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstScInt* nodep, AstNUser*) {
|
|
|
|
|
// Special class info means the module must remain public
|
|
|
|
|
m_modp->modPublic(true);
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
LinkResolveVisitor(AstNetlist* rootp) {
|
|
|
|
|
m_ftaskp = NULL;
|
|
|
|
|
m_modp = NULL;
|
2007-03-06 21:43:38 +00:00
|
|
|
|
m_assertp = NULL;
|
2008-11-23 02:10:20 +00:00
|
|
|
|
m_senitemCvtNum = 0;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~LinkResolveVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// LinkBotupVisitor
|
|
|
|
|
// Recurses cells backwards, so we can pick up those things that propagate
|
|
|
|
|
// from child cells up to the top module.
|
|
|
|
|
|
|
|
|
|
class LinkBotupVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
|
|
|
|
AstModule* m_modp; // Current module
|
2009-01-21 21:56:50 +00:00
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
static int debug() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
|
|
|
|
return level;
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// VISITs
|
|
|
|
|
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
|
|
|
|
// Iterate modules backwards, in bottom-up order.
|
|
|
|
|
nodep->iterateChildrenBackwards(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstModule* nodep, AstNUser*) {
|
|
|
|
|
m_modp = nodep;
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
|
|
|
|
// Parent module inherits child's publicity
|
|
|
|
|
if (nodep->modp()->modPublic()) m_modp->modPublic(true);
|
|
|
|
|
//** No iteration for speed
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeMath* nodep, AstNUser*) {
|
|
|
|
|
// Speedup
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
LinkBotupVisitor(AstNetlist* rootp) {
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
//
|
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~LinkBotupVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
|
|
|
|
void V3LinkResolve::linkResolve(AstNetlist* rootp) {
|
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
|
|
|
|
LinkResolveVisitor visitor(rootp);
|
|
|
|
|
LinkBotupVisitor visitorb(rootp);
|
|
|
|
|
}
|