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
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2010-01-06 02:15:06 +00:00
|
|
|
|
// Copyright 2003-2010 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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2009-10-31 14:14:04 +00:00
|
|
|
|
// NO EDITS: Don't replace or delete nodes, as the parser symbol table
|
|
|
|
|
// has pointers into the ast tree.
|
|
|
|
|
//
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// LINK TRANSFORMATIONS:
|
|
|
|
|
// Top-down traversal
|
|
|
|
|
// Cells:
|
|
|
|
|
// Read module if needed
|
|
|
|
|
// Link to module that instantiates it
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
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 "V3LinkCells.h"
|
|
|
|
|
#include "V3SymTable.h"
|
2009-10-31 14:08:38 +00:00
|
|
|
|
#include "V3Parse.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
#include "V3Graph.h"
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Graph subclasses
|
|
|
|
|
|
|
|
|
|
class LinkCellsGraph : public V3Graph {
|
|
|
|
|
public:
|
|
|
|
|
LinkCellsGraph() {}
|
|
|
|
|
virtual ~LinkCellsGraph() {}
|
|
|
|
|
virtual void loopsMessageCb(V3GraphVertex* vertexp);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LinkCellsVertex : public V3GraphVertex {
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* m_modp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
public:
|
2009-11-07 11:20:20 +00:00
|
|
|
|
LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp)
|
2006-08-26 11:35:28 +00:00
|
|
|
|
: V3GraphVertex(graphp), m_modp(modp) {}
|
|
|
|
|
virtual ~LinkCellsVertex() {}
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* modp() const { return m_modp; }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual string name() const { return modp()->name(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class LibraryVertex : public V3GraphVertex {
|
|
|
|
|
public:
|
|
|
|
|
LibraryVertex(V3Graph* graphp)
|
|
|
|
|
: V3GraphVertex(graphp) {}
|
|
|
|
|
virtual ~LibraryVertex() {}
|
|
|
|
|
virtual string name() const { return "*LIBRARY*"; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
|
|
|
|
|
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
|
|
|
|
|
vvertexp->modp()->v3error("Recursive module (module instantiates itself): "
|
|
|
|
|
<<vvertexp->modp()->name());
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
} else { // Everything should match above, but...
|
|
|
|
|
v3fatalSrc("Recursive instantiations");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class LinkCellsVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Entire netlist:
|
2009-11-07 11:20:20 +00:00
|
|
|
|
// AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module
|
2009-10-31 14:14:04 +00:00
|
|
|
|
// Allocated across all readFiles in V3Global::readFiles:
|
|
|
|
|
// AstNode::user4p() // V3SymTable* Package and typedef symbol names
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// STATE
|
2010-01-20 12:15:51 +00:00
|
|
|
|
V3InFilter* m_filterp; // Parser filter
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Below state needs to be preserved between each module call.
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* m_modp; // Current module
|
|
|
|
|
V3SymTable m_mods; // Symbol table of all module names
|
2006-08-26 11:35:28 +00:00
|
|
|
|
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
|
|
|
|
|
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
|
2009-04-07 17:23:25 +00:00
|
|
|
|
V3GraphVertex* m_topVertexp; // Vertex of top module
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
// METHODS
|
2009-11-07 11:20:20 +00:00
|
|
|
|
V3GraphVertex* vertex(AstNodeModule* nodep) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Return corresponding vertex for this module
|
2008-11-25 14:03:49 +00:00
|
|
|
|
if (!nodep->user1p()) {
|
|
|
|
|
nodep->user1p(new LinkCellsVertex(&m_graph, nodep));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2008-11-25 14:03:49 +00:00
|
|
|
|
return (nodep->user1p()->castGraphVertex());
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITs
|
|
|
|
|
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstNode::user1ClearTree();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
readModNames();
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
// Find levels in graph
|
|
|
|
|
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
|
|
|
|
m_graph.dumpDotFilePrefixed("linkcells");
|
|
|
|
|
m_graph.rank();
|
|
|
|
|
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
|
|
|
|
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(itp)) {
|
|
|
|
|
// +1 so we leave level 1 for the new wrapper we'll make in a moment
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* modp = vvertexp->modp();
|
2009-04-24 14:32:11 +00:00
|
|
|
|
modp->level(vvertexp->rank()+1);
|
|
|
|
|
if (vvertexp == m_topVertexp && modp->level() != 2) {
|
|
|
|
|
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' isn't at the top level, it's under another cell.");
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-07 17:23:25 +00:00
|
|
|
|
if (v3Global.opt.topModule()!=""
|
|
|
|
|
&& !m_topVertexp) {
|
|
|
|
|
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' was not found in design.");
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2009-11-07 11:20:20 +00:00
|
|
|
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Module: Pick up modnames, so we can resolve cells later
|
|
|
|
|
m_modp = nodep;
|
|
|
|
|
UINFO(2,"Link Module: "<<nodep<<endl);
|
2009-04-07 17:23:25 +00:00
|
|
|
|
bool topMatch = (v3Global.opt.topModule()==nodep->name());
|
2009-04-24 14:32:11 +00:00
|
|
|
|
if (topMatch) {
|
|
|
|
|
m_topVertexp = vertex(nodep);
|
|
|
|
|
UINFO(2,"Link --top-module: "<<nodep<<endl);
|
|
|
|
|
nodep->inLibrary(false); // Safer to make sure it doesn't disappear
|
|
|
|
|
}
|
2009-04-07 17:23:25 +00:00
|
|
|
|
if (v3Global.opt.topModule()==""
|
|
|
|
|
? nodep->inLibrary() // Library cells are lower
|
|
|
|
|
: !topMatch) { // Any non-specified module is lower
|
|
|
|
|
// Put under a fake vertex so that the graph ranking won't indicate
|
|
|
|
|
// this is a top level module
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
|
|
|
|
|
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
|
|
|
|
|
}
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
nodep->checkTree();
|
|
|
|
|
m_modp = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
|
|
|
|
// Cell: Resolve its filename. If necessary, parse it.
|
|
|
|
|
if (!nodep->modp()) {
|
|
|
|
|
UINFO(4,"Link Cell: "<<nodep<<endl);
|
2009-03-24 13:22:58 +00:00
|
|
|
|
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
|
|
|
|
|
// but we might support modules-under-modules someday.
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* modp = m_mods.findIdUpward(nodep->modName())->castNodeModule();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (!modp) {
|
|
|
|
|
// Read-subfile
|
2010-01-20 12:15:51 +00:00
|
|
|
|
V3Parse parser (v3Global.rootp(), m_filterp);
|
2009-10-31 14:08:38 +00:00
|
|
|
|
parser.parseFile(nodep->fileline(), nodep->modName(), false);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
// We've read new modules, grab new pointers to their names
|
|
|
|
|
readModNames();
|
|
|
|
|
// Check again
|
2009-11-07 11:20:20 +00:00
|
|
|
|
modp = m_mods.findIdUpward(nodep->modName())->castNodeModule();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (!modp) {
|
|
|
|
|
nodep->v3error("Can't resolve module reference: "<<nodep->modName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (modp) {
|
|
|
|
|
nodep->modp(modp);
|
|
|
|
|
// Track module depths, so can sort list from parent down to children
|
|
|
|
|
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-14 13:06:08 +00:00
|
|
|
|
// Convert .* to list of pins
|
2009-05-07 22:28:05 +00:00
|
|
|
|
bool pinStar = false;
|
|
|
|
|
for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
|
|
|
|
|
nextp = pinp->nextp()->castPin();
|
|
|
|
|
if (pinp->dotStar()) {
|
|
|
|
|
if (pinStar) pinp->v3error("Duplicate .* in a cell");
|
|
|
|
|
pinStar = true;
|
|
|
|
|
// Done with this fake pin
|
|
|
|
|
pinp->unlinkFrBack()->deleteTree(); pinp=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nodep->modp() && pinStar) {
|
2007-03-14 13:06:08 +00:00
|
|
|
|
// Note what pins exist
|
|
|
|
|
UINFO(9," CELL .* connect "<<nodep<<endl);
|
2009-10-31 14:08:38 +00:00
|
|
|
|
V3SymTable ports; // Symbol table of all connected port names
|
2007-03-14 13:06:08 +00:00
|
|
|
|
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
|
|
|
|
if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
|
2009-03-24 13:22:58 +00:00
|
|
|
|
if (!ports.findIdFlat(pinp->name())) {
|
2007-03-14 13:06:08 +00:00
|
|
|
|
ports.insert(pinp->name(), pinp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-11-30 22:12:53 +00:00
|
|
|
|
// We search ports, rather than in/out declarations as they aren't resolved yet,
|
|
|
|
|
// and it's easier to do it now than in V3Link when we'd need to repeat steps.
|
2007-03-14 13:06:08 +00:00
|
|
|
|
for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep; portnodep=portnodep->nextp()) {
|
|
|
|
|
if (AstPort* portp = portnodep->castPort()) {
|
2009-03-24 13:22:58 +00:00
|
|
|
|
if (!ports.findIdFlat(portp->name())) {
|
2007-03-14 13:06:08 +00:00
|
|
|
|
UINFO(9," need PORT "<<portp<<endl);
|
|
|
|
|
// Create any not already connected
|
|
|
|
|
AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),
|
|
|
|
|
new AstVarRef(nodep->fileline(),portp->name(),false));
|
|
|
|
|
newp->svImplicit(true);
|
|
|
|
|
nodep->addPinsp(newp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Convert unnamed pins to pin number based assignments
|
|
|
|
|
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
|
|
|
|
if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum()));
|
|
|
|
|
}
|
|
|
|
|
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
|
|
|
|
if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
|
|
|
|
|
}
|
|
|
|
|
if (nodep->modp()) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Accelerate the recursion
|
|
|
|
|
// Must do statements to support Generates, math though...
|
|
|
|
|
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
// Default: Just iterate
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
void readModNames() {
|
|
|
|
|
// Look at all modules, and store pointers to all module names
|
2010-01-08 01:25:15 +00:00
|
|
|
|
for (AstNodeModule* nextp,* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nextp) {
|
|
|
|
|
nextp = nodep->nextp()->castNodeModule();
|
2009-03-24 13:22:58 +00:00
|
|
|
|
AstNode* foundp = m_mods.findIdUpward(nodep->name());
|
2008-04-09 13:56:40 +00:00
|
|
|
|
if (foundp && foundp != nodep) {
|
2010-01-08 01:25:15 +00:00
|
|
|
|
if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP) || nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP))) {
|
|
|
|
|
nodep->v3warn(MODDUP,"Duplicate declaration of module: "<<nodep->prettyName());
|
|
|
|
|
foundp->v3warn(MODDUP,"... Location of original declaration");
|
|
|
|
|
}
|
2010-01-08 19:03:00 +00:00
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
pushDeletep(nodep); nodep=NULL;
|
2008-04-09 13:56:40 +00:00
|
|
|
|
} else if (!foundp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_mods.insert(nodep->name(), nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-31 14:08:38 +00:00
|
|
|
|
//if (debug()>=9) m_mods.dump(cout, "-syms: ");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
2010-01-20 12:15:51 +00:00
|
|
|
|
LinkCellsVisitor(AstNetlist* rootp, V3InFilter* filterp) {
|
|
|
|
|
m_filterp = filterp;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_modp = NULL;
|
|
|
|
|
m_libVertexp = NULL;
|
2009-04-07 17:23:25 +00:00
|
|
|
|
m_topVertexp = NULL;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
rootp->accept(*this);
|
|
|
|
|
}
|
2009-10-02 02:33:11 +00:00
|
|
|
|
virtual ~LinkCellsVisitor() {}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
2010-01-20 12:15:51 +00:00
|
|
|
|
void V3LinkCells::link(AstNetlist* rootp, V3InFilter* filterp) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(4,__FUNCTION__<<": "<<endl);
|
2010-01-20 12:15:51 +00:00
|
|
|
|
LinkCellsVisitor visitor (rootp, filterp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|