Add very experimental --xml option
This commit is contained in:
parent
37839e2709
commit
204fb82975
|
|
@ -182,6 +182,7 @@ RAW_OBJS = \
|
|||
V3EmitCSyms.o \
|
||||
V3EmitMk.o \
|
||||
V3EmitV.o \
|
||||
V3EmitXml.o \
|
||||
V3Error.o \
|
||||
V3Expand.o \
|
||||
V3File.o \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,196 @@
|
|||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Emit Verilog from tree
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2012 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3EmitXml.h"
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
//######################################################################
|
||||
// Emit statements and math operators
|
||||
|
||||
class EmitXmlFileVisitor : public EmitCBaseVisitor {
|
||||
// MEMBERS
|
||||
V3OutFile* m_ofp;
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
// Outfile methods
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
virtual void puts(const string& str) { ofp()->puts(str); }
|
||||
virtual void putbs(const string& str) { ofp()->putbs(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
|
||||
virtual void putsQuoted(const string& str) {
|
||||
// Quote \ and " for use inside C programs
|
||||
// Don't use to quote a filename for #include - #include doesn't \ escape.
|
||||
// Duplicate in V3File - here so we can print to string
|
||||
putsNoTracking("\"");
|
||||
putsNoTracking(AstNode::quoteName(str));
|
||||
putsNoTracking("\"");
|
||||
}
|
||||
|
||||
// XML methods
|
||||
void outputTag(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = V3Options::downcase(nodep->typeName());
|
||||
puts("<"+tag+" "+nodep->fileline()->xml());
|
||||
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
||||
}
|
||||
void outputChildrenEnd(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = V3Options::downcase(nodep->typeName());
|
||||
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
||||
puts(">\n");
|
||||
nodep->iterateChildren(*this);
|
||||
puts("</"+tag+">\n");
|
||||
} else {
|
||||
puts("/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||
puts("<netlist>\n");
|
||||
nodep->iterateChildren(*this);
|
||||
puts("</netlist>\n");
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
outputTag(nodep, "");
|
||||
if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode
|
||||
puts(" topModule=\"1\""); // IEEE vpiTopModule
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
outputTag(nodep, "instance"); // IEEE: vpiInstance
|
||||
puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName
|
||||
outputChildrenEnd(nodep, "instance");
|
||||
}
|
||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isInOnly())
|
||||
puts(" direction=\"in\"");
|
||||
else if (nodep->modVarp()->isOutOnly())
|
||||
puts(" direction=\"out\"");
|
||||
else puts(" direction=\"inout\"");
|
||||
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
|
||||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
outputTag(nodep, "contAssign"); // IEEE: vpiContAssign
|
||||
outputChildrenEnd(nodep, "contAssign");
|
||||
}
|
||||
|
||||
// Data types
|
||||
virtual void visit(AstBasicDType* nodep, AstNUser*) {
|
||||
outputTag(nodep, "basicDType ");
|
||||
if (nodep->isRanged()) {
|
||||
puts(" left=\""+cvtToStr(nodep->left())+"\"");
|
||||
puts(" right=\""+cvtToStr(nodep->right())+"\"");
|
||||
}
|
||||
puts("/>\n");
|
||||
}
|
||||
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
outputTag(nodep, "");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
public:
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
|
||||
m_ofp = ofp;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~EmitXmlFileVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Emit to a stream (perhaps stringstream)
|
||||
|
||||
class EmitXmlPrefixedFormatter : public V3OutFormatter {
|
||||
ostream& m_os;
|
||||
string m_prefix; // What to print at beginning of each line
|
||||
int m_flWidth; // Padding of fileline
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
// METHODS
|
||||
virtual void putcOutput(char chr) {
|
||||
if (chr == '\n') {
|
||||
m_column = 0;
|
||||
m_os<<chr;
|
||||
} else {
|
||||
if (m_column == 0) {
|
||||
m_column = 10;
|
||||
m_os<<m_prefixFl->ascii()+":";
|
||||
m_os<<V3OutFile::indentSpaces(m_flWidth-(m_prefixFl->ascii().length()+1));
|
||||
m_os<<" ";
|
||||
m_os<<m_prefix;
|
||||
}
|
||||
m_column++;
|
||||
m_os<<chr;
|
||||
}
|
||||
}
|
||||
public:
|
||||
void prefixFl(FileLine* fl) { m_prefixFl = fl; }
|
||||
FileLine* prefixFl() const { return m_prefixFl; }
|
||||
int column() const { return m_column; }
|
||||
EmitXmlPrefixedFormatter(ostream& os, const string& prefix, int flWidth)
|
||||
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
|
||||
, m_os(os), m_prefix(prefix), m_flWidth(flWidth) {
|
||||
m_column = 0;
|
||||
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
|
||||
}
|
||||
virtual ~EmitXmlPrefixedFormatter() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// EmitXml class functions
|
||||
|
||||
void V3EmitXml::emitxml() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
// All-in-one file
|
||||
V3OutXmlFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".xml");
|
||||
of.putsHeader();
|
||||
of.puts("<!-- DESCR" "IPTION: Verilator output: XML representation of netlist -->\n");
|
||||
of.puts("<verilator_xml>\n");
|
||||
{
|
||||
stringstream sstr;
|
||||
FileLine::fileNameNumMapDumpXml(sstr);
|
||||
of.puts(sstr.str());
|
||||
}
|
||||
EmitXmlFileVisitor visitor (v3Global.rootp(), &of);
|
||||
of.puts("</verilator_xml>\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
//-*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Emit XML code
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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 _V3EMITXML_H_
|
||||
#define _V3EMITXML_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3EmitXml {
|
||||
public:
|
||||
static void emitxml();
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -92,6 +92,14 @@ int FileLineSingleton::nameToNumber(const string& filename) {
|
|||
return num;
|
||||
}
|
||||
|
||||
void FileLineSingleton::fileNameNumMapDumpXml(ostream& os) {
|
||||
os<<"<files>\n";
|
||||
for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
|
||||
os<<"<file id=\""<<filenameLetters(it->second)<<"\" filename=\""<<it->first<<"\"/>\n";
|
||||
}
|
||||
os<<"</files>\n";
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// FileLine class functions
|
||||
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ protected:
|
|||
int nameToNumber(const string& filename);
|
||||
const string numberToName(int filenameno) const { return m_names[filenameno]; }
|
||||
void clear() { m_namemap.clear(); m_names.clear(); }
|
||||
void fileNameNumMapDumpXml(ostream& os);
|
||||
static const string filenameLetters(int fileno);
|
||||
};
|
||||
|
||||
|
|
@ -327,6 +328,7 @@ public:
|
|||
const string filebasename () const;
|
||||
const string filebasenameNoExt () const;
|
||||
const string profileFuncname() const;
|
||||
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
|
||||
string lineDirectiveStrg(int enter_exit_level) const;
|
||||
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line.
|
||||
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
|
||||
|
|
@ -352,6 +354,8 @@ public:
|
|||
defaultFileLine().warnOff(code, flag); }
|
||||
static bool globalWarnOff(const string& code, bool flag) {
|
||||
return defaultFileLine().warnOff(code, flag); }
|
||||
static void fileNameNumMapDumpXml(ostream& os) {
|
||||
singleton().fileNameNumMapDumpXml(os); }
|
||||
|
||||
// METHODS - Called from netlist
|
||||
// Merge warning disables from another fileline
|
||||
|
|
|
|||
|
|
@ -726,6 +726,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||
else if ( !strcmp (sw, "-debug-sigsegv") ) { throwSigsegv(); } // Undocumented, see also --debug-abort
|
||||
else if ( !strcmp (sw, "-debug-fatalsrc") ) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort
|
||||
else if ( onoff (sw, "-dump-tree", flag/*ref*/) ) { m_dumpTree = flag; }
|
||||
else if ( onoff (sw, "-dump-tree-more", flag/*ref*/) ) { m_dumpTreeMore = m_dumpTree = flag; } // Undocumented
|
||||
else if ( onoff (sw, "-exe", flag/*ref*/) ) { m_exe = flag; }
|
||||
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
|
||||
else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)){ m_inhibitSim = flag; }
|
||||
|
|
@ -747,6 +748,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
||||
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
|
||||
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
|
||||
else if ( onoff (sw, "-xml-only", flag/*ref*/) ) { m_xmlOnly = flag; } // Undocumented, still experimental
|
||||
// Optimization
|
||||
else if ( !strncmp (sw, "-O", 2) ) {
|
||||
for (const char* cp=sw+strlen("-O"); *cp; ++cp) {
|
||||
|
|
@ -1161,6 +1163,7 @@ V3Options::V3Options() {
|
|||
m_coverageUser = false;
|
||||
m_debugCheck = false;
|
||||
m_dumpTree = false;
|
||||
m_dumpTreeMore = false;
|
||||
m_exe = false;
|
||||
m_ignc = false;
|
||||
m_l2Name = true;
|
||||
|
|
@ -1182,6 +1185,7 @@ V3Options::V3Options() {
|
|||
m_traceDups = false;
|
||||
m_traceUnderscore = false;
|
||||
m_underlineZero = false;
|
||||
m_xmlOnly = false;
|
||||
|
||||
m_errorLimit = 50;
|
||||
m_ifDepth = 0;
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ class V3Options {
|
|||
bool m_coverageUser; // main switch: --coverage-func
|
||||
bool m_debugCheck; // main switch: --debug-check
|
||||
bool m_dumpTree; // main switch: --dump-tree
|
||||
bool m_dumpTreeMore; // main switch: --dump-tree-more
|
||||
bool m_exe; // main switch: --exe
|
||||
bool m_ignc; // main switch: --ignc
|
||||
bool m_inhibitSim; // main switch: --inhibit-sim
|
||||
|
|
@ -126,6 +127,7 @@ class V3Options {
|
|||
bool m_traceDups; // main switch: --trace-dups
|
||||
bool m_traceUnderscore;// main switch: --trace-underscore
|
||||
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
|
||||
bool m_xmlOnly; // main switch: --xml-netlist
|
||||
|
||||
int m_errorLimit; // main switch: --error-limit
|
||||
int m_ifDepth; // main switch: --if-depth
|
||||
|
|
@ -237,6 +239,7 @@ class V3Options {
|
|||
bool coverageUser() const { return m_coverageUser; }
|
||||
bool debugCheck() const { return m_debugCheck; }
|
||||
bool dumpTree() const { return m_dumpTree; }
|
||||
bool dumpTreeMore() const { return m_dumpTreeMore; }
|
||||
bool exe() const { return m_exe; }
|
||||
bool trace() const { return m_trace; }
|
||||
bool traceDups() const { return m_traceDups; }
|
||||
|
|
@ -252,6 +255,7 @@ class V3Options {
|
|||
bool lintOnly() const { return m_lintOnly; }
|
||||
bool ignc() const { return m_ignc; }
|
||||
bool inhibitSim() const { return m_inhibitSim; }
|
||||
bool xmlOnly() const { return m_xmlOnly; }
|
||||
|
||||
int errorLimit() const { return m_errorLimit; }
|
||||
int ifDepth() const { return m_ifDepth; }
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "V3EmitC.h"
|
||||
#include "V3EmitMk.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3EmitXml.h"
|
||||
#include "V3Expand.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Cdc.h"
|
||||
|
|
@ -142,6 +143,8 @@ void V3Global::readFiles() {
|
|||
//######################################################################
|
||||
|
||||
void process () {
|
||||
bool dumpMore = v3Global.opt.dumpTreeMore();
|
||||
|
||||
// Sort modules by level so later algorithms don't need to care
|
||||
V3LinkLevel::modSortByLevel();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree"));
|
||||
|
|
@ -149,14 +152,19 @@ void process () {
|
|||
|
||||
// Convert parseref's to varrefs, and other directly post parsing fixups
|
||||
V3LinkParse::linkParse(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkparse.tree"));
|
||||
// Cross-link signal names
|
||||
V3Link::link(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkmain.tree"));
|
||||
// Cross-link dotted hierarchical references
|
||||
V3LinkDot::linkDotPrearrayed(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
// Correct state we couldn't know at parse time, repair SEL's
|
||||
V3LinkResolve::linkResolve(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkresolve.tree"));
|
||||
// Set Lvalue's in variable refs
|
||||
V3LinkLValue::linkLValue(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linklvalue.tree"));
|
||||
// Convert return/continue/disable to jumps
|
||||
V3LinkJump::linkJump(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
||||
|
|
@ -173,7 +181,7 @@ void process () {
|
|||
|
||||
// Remove any modules that were parameterized and are no longer referenced.
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
||||
v3Global.checkTree();
|
||||
|
||||
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
|
||||
|
|
@ -186,7 +194,7 @@ void process () {
|
|||
V3Width::widthCommit(v3Global.rootp());
|
||||
v3Global.assertDTypesResolved(true);
|
||||
v3Global.assertWidthsMatch(true);
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("widthcommit.tree"));
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("widthcommit.tree"));
|
||||
|
||||
// Coverage insertion
|
||||
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||
|
|
@ -212,321 +220,350 @@ void process () {
|
|||
V3Assert::assertAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
|
||||
|
||||
// Add top level wrapper with instance pointing to old top
|
||||
// Move packages to under new top
|
||||
// Must do this after we know the width of any parameters
|
||||
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
|
||||
V3LinkLevel::wrapTop(v3Global.rootp());
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Add top level wrapper with instance pointing to old top
|
||||
// Move packages to under new top
|
||||
// Must do this after we know the width of any parameters
|
||||
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
|
||||
V3LinkLevel::wrapTop(v3Global.rootp());
|
||||
}
|
||||
|
||||
// Propagate constants into expressions
|
||||
V3Const::constifyAllLint(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Expand Inouts
|
||||
V3Tristate::inoutAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Expand Inouts
|
||||
V3Tristate::inoutAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
|
||||
}
|
||||
|
||||
// Remove cell arrays (must be between V3Width and scoping)
|
||||
V3Inst::dearrayAll(v3Global.rootp());
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Remove cell arrays (must be between V3Width and scoping)
|
||||
V3Inst::dearrayAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
|
||||
}
|
||||
|
||||
// Expand inouts, stage 2
|
||||
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
|
||||
V3Tristate::tristateAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Expand inouts, stage 2
|
||||
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
|
||||
V3Tristate::tristateAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
|
||||
|
||||
// Task inlining & pushing BEGINs names to variables/cells
|
||||
// Begin processing must be after Param, before module inlining
|
||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
|
||||
// Task inlining & pushing BEGINs names to variables/cells
|
||||
// Begin processing must be after Param, before module inlining
|
||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
|
||||
|
||||
// Move assignments from X into MODULE temps.
|
||||
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
||||
V3Unknown::unknownAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
|
||||
// Move assignments from X into MODULE temps.
|
||||
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
||||
V3Unknown::unknownAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
|
||||
|
||||
// Module inlining
|
||||
// Cannot remove dead variables after this, as alias information for final
|
||||
// V3Scope's V3LinkDot is in the AstVar.
|
||||
if (v3Global.opt.oInline()) {
|
||||
V3Inline::inlineAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
|
||||
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
// Module inlining
|
||||
// Cannot remove dead variables after this, as alias information for final
|
||||
// V3Scope's V3LinkDot is in the AstVar.
|
||||
if (v3Global.opt.oInline()) {
|
||||
V3Inline::inlineAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
|
||||
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
}
|
||||
}
|
||||
|
||||
//--PRE-FLAT OPTIMIZATIONS------------------
|
||||
|
||||
// Initial const/dead to reduce work for ordering code
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
v3Global.checkTree();
|
||||
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
v3Global.checkTree();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
v3Global.checkTree();
|
||||
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
//--FLATTENING---------------
|
||||
|
||||
// We're going to flatten the hierarchy, so as many optimizations that
|
||||
// can be done as possible should be before this....
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// We're going to flatten the hierarchy, so as many optimizations that
|
||||
// can be done as possible should be before this....
|
||||
|
||||
// Convert instantiations to wassigns and always blocks
|
||||
V3Inst::instAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inst.tree"));
|
||||
// Convert instantiations to wassigns and always blocks
|
||||
V3Inst::instAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inst.tree"));
|
||||
|
||||
// Inst may have made lots of concats; fix them
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
// Inst may have made lots of concats; fix them
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
||||
V3Scope::scopeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
|
||||
V3LinkDot::linkDotScope(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
||||
V3Scope::scopeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
|
||||
V3LinkDot::linkDotScope(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
}
|
||||
|
||||
//--SCOPE BASED OPTIMIZATIONS--------------
|
||||
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
v3Global.checkTree();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Inline all tasks
|
||||
V3Task::taskAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("task.tree"));
|
||||
|
||||
// Add __PVT's
|
||||
// After V3Task so task internal variables will get renamed
|
||||
V3Name::nameAll(v3Global.rootp());
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("name.tree"));
|
||||
|
||||
// Loop unrolling & convert FORs to WHILEs
|
||||
V3Unroll::unrollAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
|
||||
|
||||
// Expand slices of arrays
|
||||
V3Slice::sliceAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("slices.tree"));
|
||||
|
||||
// Convert case statements to if() blocks. Must be after V3Unknown
|
||||
V3Case::caseAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
|
||||
|
||||
// Push constants across variables and remove redundant assignments
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
if (v3Global.opt.oLife()) {
|
||||
V3Life::lifeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
|
||||
}
|
||||
|
||||
// Make large low-fanin logic blocks into lookup tables
|
||||
// This should probably be done much later, once we have common logic elimination.
|
||||
if (!v3Global.opt.lintOnly() && v3Global.opt.oTable()) {
|
||||
V3Table::tableAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("table.tree"));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
v3Global.checkTree();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Detect clock enables and mode into sensitives, and split always based on clocks
|
||||
// (so this is a good prelude to splitAlways.)
|
||||
if (v3Global.opt.oFlopGater()) {
|
||||
V3ClkGater::clkGaterAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clkgater.tree"));
|
||||
}
|
||||
|
||||
// Move assignments/sensitives into a SBLOCK for each unique sensitivity list
|
||||
// (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
|
||||
V3Active::activeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("active.tree"));
|
||||
|
||||
// Split single ALWAYS blocks into multiple blocks for better ordering chances
|
||||
if (v3Global.opt.oSplit()) {
|
||||
V3Split::splitAlwaysAll(v3Global.rootp());
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
|
||||
}
|
||||
V3SplitAs::splitAsAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("splitas.tree"));
|
||||
|
||||
// Create tracing sample points, before we start eliminating signals
|
||||
if (v3Global.opt.trace()) {
|
||||
V3TraceDecl::traceDeclAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tracedecl.tree"));
|
||||
}
|
||||
|
||||
// Gate-based logic elimination; eliminate signals and push constant across cell boundaries
|
||||
// Instant propagation makes lots-o-constant reduction possibilities.
|
||||
if (v3Global.opt.oGate()) {
|
||||
V3Gate::gateAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("gate.tree"));
|
||||
// V3Gate calls constant propagation itself.
|
||||
} else {
|
||||
v3info("Command Line disabled gate optimization with -Og/-O0. This may cause ordering problems.");
|
||||
}
|
||||
|
||||
// Combine COVERINCs with duplicate terms
|
||||
if (v3Global.opt.coverage()) {
|
||||
V3CoverageJoin::coverageJoin(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("coveragejoin.tree"));
|
||||
}
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Clock domain crossing analysis
|
||||
if (v3Global.opt.cdc()) {
|
||||
V3Cdc::cdcAll(v3Global.rootp());
|
||||
V3Error::abortIfErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reorder assignments in pipelined blocks
|
||||
if (v3Global.opt.oReorder()) {
|
||||
V3Split::splitReorderAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("reorder.tree"));
|
||||
}
|
||||
|
||||
// Create delayed assignments
|
||||
// This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
|
||||
V3Delayed::delayedAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("delayed.tree"));
|
||||
|
||||
// Make Active's on the top level
|
||||
// Differs from V3Active, because identical clocks may be pushed down to a module and now be identical
|
||||
V3ActiveTop::activeTopAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("activetop.tree"));
|
||||
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
|
||||
|
||||
// Order the code; form SBLOCKs and BLOCKCALLs
|
||||
V3Order::orderAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("order.tree"));
|
||||
|
||||
#ifndef NEW_ORDERING
|
||||
// Change generated clocks to look at delayed signals
|
||||
V3GenClk::genClkAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("genclk.tree"));
|
||||
#endif
|
||||
|
||||
// Convert sense lists into IF statements.
|
||||
V3Clock::clockAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));
|
||||
|
||||
// Cleanup any dly vars or other temps that are simple assignments
|
||||
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
|
||||
if (v3Global.opt.oLife()) {
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Life::lifeAll(v3Global.rootp());
|
||||
}
|
||||
if (v3Global.opt.oLifePost()) {
|
||||
V3LifePost::lifepostAll(v3Global.rootp());
|
||||
}
|
||||
if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
|
||||
}
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
v3Global.checkTree();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
// Inline all tasks
|
||||
V3Task::taskAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("task.tree"));
|
||||
|
||||
// Add __PVT's
|
||||
// After V3Task so task internal variables will get renamed
|
||||
V3Name::nameAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("name.tree"));
|
||||
|
||||
// Loop unrolling & convert FORs to WHILEs
|
||||
V3Unroll::unrollAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
|
||||
|
||||
// Expand slices of arrays
|
||||
V3Slice::sliceAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("slices.tree"));
|
||||
|
||||
// Convert case statements to if() blocks. Must be after V3Unknown
|
||||
V3Case::caseAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
|
||||
|
||||
// Push constants across variables and remove redundant assignments
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
if (v3Global.opt.oLife()) {
|
||||
V3Life::lifeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
|
||||
}
|
||||
|
||||
// Make large low-fanin logic blocks into lookup tables
|
||||
// This should probably be done much later, once we have common logic elimination.
|
||||
if (!v3Global.opt.lintOnly() && v3Global.opt.oTable()) {
|
||||
V3Table::tableAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("table.tree"));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
v3Global.checkTree();
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Detect clock enables and mode into sensitives, and split always based on clocks
|
||||
// (so this is a good prelude to splitAlways.)
|
||||
if (v3Global.opt.oFlopGater()) {
|
||||
V3ClkGater::clkGaterAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clkgater.tree"));
|
||||
}
|
||||
|
||||
// Move assignments/sensitives into a SBLOCK for each unique sensitivity list
|
||||
// (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
|
||||
V3Active::activeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("active.tree"));
|
||||
|
||||
// Split single ALWAYS blocks into multiple blocks for better ordering chances
|
||||
if (v3Global.opt.oSplit()) {
|
||||
V3Split::splitAlwaysAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
|
||||
}
|
||||
V3SplitAs::splitAsAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("splitas.tree"));
|
||||
|
||||
// Create tracing sample points, before we start eliminating signals
|
||||
if (v3Global.opt.trace()) {
|
||||
V3TraceDecl::traceDeclAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tracedecl.tree"));
|
||||
}
|
||||
|
||||
// Gate-based logic elimination; eliminate signals and push constant across cell boundaries
|
||||
// Instant propagation makes lots-o-constant reduction possibilities.
|
||||
if (v3Global.opt.oGate()) {
|
||||
V3Gate::gateAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("gate.tree"));
|
||||
// V3Gate calls constant propagation itself.
|
||||
} else {
|
||||
v3info("Command Line disabled gate optimization with -Og/-O0. This may cause ordering problems.");
|
||||
}
|
||||
|
||||
// Combine COVERINCs with duplicate terms
|
||||
if (v3Global.opt.coverage()) {
|
||||
V3CoverageJoin::coverageJoin(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("coveragejoin.tree"));
|
||||
}
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Clock domain crossing analysis
|
||||
if (v3Global.opt.cdc()) {
|
||||
V3Cdc::cdcAll(v3Global.rootp());
|
||||
V3Error::abortIfErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reorder assignments in pipelined blocks
|
||||
if (v3Global.opt.oReorder()) {
|
||||
V3Split::splitReorderAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("reorder.tree"));
|
||||
}
|
||||
|
||||
// Create delayed assignments
|
||||
// This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
|
||||
V3Delayed::delayedAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("delayed.tree"));
|
||||
|
||||
// Make Active's on the top level
|
||||
// Differs from V3Active, because identical clocks may be pushed down to a module and now be identical
|
||||
V3ActiveTop::activeTopAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("activetop.tree"));
|
||||
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
|
||||
|
||||
// Order the code; form SBLOCKs and BLOCKCALLs
|
||||
V3Order::orderAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("order.tree"));
|
||||
|
||||
#ifndef NEW_ORDERING
|
||||
// Detect change loop
|
||||
V3Changed::changedAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("changed.tree"));
|
||||
// Change generated clocks to look at delayed signals
|
||||
V3GenClk::genClkAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("genclk.tree"));
|
||||
#endif
|
||||
|
||||
// Create tracing logic, since we ripped out some signals the user might want to trace
|
||||
// Note past this point, we presume traced variables won't move between CFuncs
|
||||
// (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
|
||||
if (v3Global.opt.trace()) {
|
||||
V3Trace::traceAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("trace.tree"));
|
||||
// Convert sense lists into IF statements.
|
||||
V3Clock::clockAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));
|
||||
|
||||
// Cleanup any dly vars or other temps that are simple assignments
|
||||
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
|
||||
if (v3Global.opt.oLife()) {
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Life::lifeAll(v3Global.rootp());
|
||||
}
|
||||
if (v3Global.opt.oLifePost()) {
|
||||
V3LifePost::lifepostAll(v3Global.rootp());
|
||||
}
|
||||
if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
|
||||
}
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
#ifndef NEW_ORDERING
|
||||
// Detect change loop
|
||||
V3Changed::changedAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("changed.tree"));
|
||||
#endif
|
||||
|
||||
// Create tracing logic, since we ripped out some signals the user might want to trace
|
||||
// Note past this point, we presume traced variables won't move between CFuncs
|
||||
// (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
|
||||
if (v3Global.opt.trace()) {
|
||||
V3Trace::traceAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("trace.tree"));
|
||||
}
|
||||
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");
|
||||
|
||||
// Remove scopes; make varrefs/funccalls relative to current module
|
||||
V3Descope::descopeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("descope.tree"));
|
||||
}
|
||||
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");
|
||||
|
||||
// Remove scopes; make varrefs/funccalls relative to current module
|
||||
V3Descope::descopeAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("descope.tree"));
|
||||
|
||||
//--MODULE OPTIMIZATIONS--------------
|
||||
|
||||
// Split deep blocks to appease MSVC++. Must be before Localize.
|
||||
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
|
||||
V3DepthBlock::depthBlockAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("deepblock.tree"));
|
||||
}
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Split deep blocks to appease MSVC++. Must be before Localize.
|
||||
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
|
||||
V3DepthBlock::depthBlockAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("deepblock.tree"));
|
||||
}
|
||||
|
||||
// Move BLOCKTEMPS from class to local variables
|
||||
if (v3Global.opt.oLocalize()) {
|
||||
V3Localize::localizeAll(v3Global.rootp());
|
||||
}
|
||||
// Move BLOCKTEMPS from class to local variables
|
||||
if (v3Global.opt.oLocalize()) {
|
||||
V3Localize::localizeAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("localize.tree"));
|
||||
}
|
||||
|
||||
// Icache packing; combine common code in each module's functions into subroutines
|
||||
if (v3Global.opt.oCombine()) {
|
||||
V3Combine::combineAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
|
||||
// Icache packing; combine common code in each module's functions into subroutines
|
||||
if (v3Global.opt.oCombine()) {
|
||||
V3Combine::combineAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
|
||||
}
|
||||
}
|
||||
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
//--GENERATION------------------
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
if (!v3Global.opt.xmlOnly()) {
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Here down, widthMin() is the Verilog width, and width() is the C++ width
|
||||
// Bits between widthMin() and width() are irrelevant, but may be non zero.
|
||||
v3Global.assertWidthsMatch(false);
|
||||
// Here down, widthMin() is the Verilog width, and width() is the C++ width
|
||||
// Bits between widthMin() and width() are irrelevant, but may be non zero.
|
||||
v3Global.assertWidthsMatch(false);
|
||||
|
||||
// Make all math operations either 8, 16, 32 or 64 bits
|
||||
V3Clean::cleanAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clean.tree"));
|
||||
// Make all math operations either 8, 16, 32 or 64 bits
|
||||
V3Clean::cleanAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clean.tree"));
|
||||
|
||||
// Move wide constants to BLOCK temps.
|
||||
V3Premit::premitAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("premit.tree"));
|
||||
// Move wide constants to BLOCK temps.
|
||||
V3Premit::premitAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("premit.tree"));
|
||||
}
|
||||
|
||||
// Expand macros and wide operators into C++ primitives
|
||||
if (v3Global.opt.oExpand()) {
|
||||
if (!v3Global.opt.xmlOnly()
|
||||
&& v3Global.opt.oExpand()) {
|
||||
V3Expand::expandAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("expand.tree"));
|
||||
}
|
||||
|
||||
// Propagate constants across WORDSEL arrayed temporaries
|
||||
if (v3Global.opt.oSubst()) {
|
||||
if (!v3Global.opt.xmlOnly()
|
||||
&& v3Global.opt.oSubst()) {
|
||||
// Constant folding of expanded stuff
|
||||
V3Const::constifyCpp(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
V3Subst::substituteAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("subst.tree"));
|
||||
}
|
||||
if (v3Global.opt.oSubstConst()) {
|
||||
if (!v3Global.opt.xmlOnly()
|
||||
&& v3Global.opt.oSubstConst()) {
|
||||
// Constant folding of substitutions
|
||||
V3Const::constifyCpp(v3Global.rootp());
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("constc.tree"));
|
||||
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
||||
}
|
||||
|
||||
if (!v3Global.opt.lintOnly()) {
|
||||
if (!v3Global.opt.lintOnly()
|
||||
&& !v3Global.opt.xmlOnly()) {
|
||||
// Fix very deep expressions
|
||||
// Mark evaluation functions as member functions, if needed.
|
||||
V3Depth::depthAll(v3Global.rootp());
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("depth.tree"));
|
||||
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("depth.tree"));
|
||||
|
||||
// Branch prediction
|
||||
V3Branch::branchAll(v3Global.rootp());
|
||||
|
|
@ -540,14 +577,21 @@ void process () {
|
|||
V3Error::abortIfErrors();
|
||||
|
||||
// Output the text
|
||||
if (!v3Global.opt.lintOnly()) {
|
||||
if (!v3Global.opt.lintOnly()
|
||||
&& !v3Global.opt.xmlOnly()) {
|
||||
// emitcInlines is first, as it may set needHInlines which other emitters read
|
||||
V3EmitC::emitcInlines();
|
||||
V3EmitC::emitcSyms();
|
||||
V3EmitC::emitcTrace();
|
||||
}
|
||||
// Unfortunately we have some lint checks in emitc.
|
||||
V3EmitC::emitc();
|
||||
if (!v3Global.opt.xmlOnly()) { // Unfortunately we have some lint checks in emitc.
|
||||
V3EmitC::emitc();
|
||||
}
|
||||
if (v3Global.opt.xmlOnly()
|
||||
// Check XML when debugging to make sure no missing node types
|
||||
|| (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly())) {
|
||||
V3EmitXml::emitxml();
|
||||
}
|
||||
|
||||
// Statistics
|
||||
if (v3Global.opt.stats()) {
|
||||
|
|
@ -555,7 +599,8 @@ void process () {
|
|||
V3Stats::statsReport();
|
||||
}
|
||||
|
||||
if (!v3Global.opt.lintOnly()) {
|
||||
if (!v3Global.opt.lintOnly()
|
||||
&& !v3Global.opt.xmlOnly()) {
|
||||
// Makefile must be after all other emitters
|
||||
V3EmitMk::emitmk(v3Global.rootp());
|
||||
}
|
||||
|
|
@ -584,8 +629,9 @@ int main(int argc, char** argv, char** env) {
|
|||
if (!v3Global.opt.outFormatOk()
|
||||
&& !v3Global.opt.preprocOnly()
|
||||
&& !v3Global.opt.lintOnly()
|
||||
&& !v3Global.opt.xmlOnly()
|
||||
&& !v3Global.opt.cdc()) {
|
||||
v3fatal("verilator: Need --cc, --sc, --sp, --cdc, --lint-only or --E option");
|
||||
v3fatal("verilator: Need --cc, --sc, --sp, --cdc, --lint-only, --xml_only or --E option");
|
||||
}
|
||||
// Check environment
|
||||
V3Options::getenvSYSTEMC();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!-- DESCRIPTION: Verilator output: XML representation of netlist -->
|
||||
<verilator_xml>
|
||||
<files>
|
||||
<file id="a" filename="AstRoot"/>
|
||||
<file id="b" filename="COMMAND_LINE"/>
|
||||
<file id="c" filename="INTERNAL_VERILATOR_DEFINE"/>
|
||||
<file id="d" filename="input.vc"/>
|
||||
<file id="e" filename="t/t_xml_first.v"/>
|
||||
</files>
|
||||
<netlist>
|
||||
<module fl="e6" name="t" topModule="1">
|
||||
<var fl="e12" name="clk">
|
||||
<basicDType fl="e12" name="logic"/>
|
||||
</var>
|
||||
<var fl="e13" name="d">
|
||||
<basicDType fl="e13" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<var fl="e14" name="q">
|
||||
<basicDType fl="e14" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<var fl="e16" name="between">
|
||||
<basicDType fl="e16" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<instance fl="e18" name="cell1" defName="mod1">
|
||||
<port fl="e18" name="q" direction="out" portIndex="1">
|
||||
<varref fl="e18" name="between"/>
|
||||
</port>
|
||||
<port fl="e21" name="clk" direction="in" portIndex="2">
|
||||
<varref fl="e21" name="clk"/>
|
||||
</port>
|
||||
<port fl="e22" name="d" direction="in" portIndex="3">
|
||||
<varref fl="e22" name="d"/>
|
||||
</port>
|
||||
</instance>
|
||||
<instance fl="e24" name="cell2" defName="mod2">
|
||||
<port fl="e24" name="d" direction="in" portIndex="1">
|
||||
<varref fl="e24" name="between"/>
|
||||
</port>
|
||||
<port fl="e27" name="q" direction="out" portIndex="2">
|
||||
<varref fl="e27" name="q"/>
|
||||
</port>
|
||||
<port fl="e29" name="clk" direction="in" portIndex="3">
|
||||
<varref fl="e29" name="clk"/>
|
||||
</port>
|
||||
</instance>
|
||||
</module>
|
||||
<module fl="e33" name="mod1">
|
||||
<var fl="e35" name="clk">
|
||||
<basicDType fl="e35" name="logic"/>
|
||||
</var>
|
||||
<var fl="e36" name="d">
|
||||
<basicDType fl="e36" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<var fl="e37" name="q">
|
||||
<basicDType fl="e37" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<always fl="e39">
|
||||
<sentree fl="e39">
|
||||
<senitem fl="e39">
|
||||
<varref fl="e39" name="clk"/>
|
||||
</senitem>
|
||||
</sentree>
|
||||
<assigndly fl="e40">
|
||||
<varref fl="e40" name="d"/>
|
||||
<varref fl="e40" name="q"/>
|
||||
</assigndly>
|
||||
</always>
|
||||
</module>
|
||||
<module fl="e44" name="mod2">
|
||||
<var fl="e46" name="clk">
|
||||
<basicDType fl="e46" name="logic"/>
|
||||
</var>
|
||||
<var fl="e47" name="d">
|
||||
<basicDType fl="e47" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<var fl="e48" name="q">
|
||||
<basicDType fl="e48" name="logic" left="3" right="0"/>
|
||||
</var>
|
||||
<contAssign fl="e51">
|
||||
<varref fl="e51" name="d"/>
|
||||
<varref fl="e51" name="q"/>
|
||||
</contAssign>
|
||||
</module>
|
||||
</netlist>
|
||||
</verilator_xml>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2012 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
||||
my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml";
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ['--xml-only'],
|
||||
verilator_make_gcc => 0,
|
||||
);
|
||||
|
||||
ok(files_identical($out_filename, $Self->{golden_out}));
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2012 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Outputs
|
||||
q,
|
||||
// Inputs
|
||||
clk, d
|
||||
);
|
||||
input clk;
|
||||
input [3:0] d;
|
||||
output wire [3:0] q;
|
||||
|
||||
logic [3:0] between;
|
||||
|
||||
mod1 cell1 (.q(between),
|
||||
/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.d (d[3:0]));
|
||||
|
||||
mod2 cell2 (.d(between),
|
||||
/*AUTOINST*/
|
||||
// Outputs
|
||||
.q (q[3:0]),
|
||||
// Inputs
|
||||
.clk (clk));
|
||||
|
||||
endmodule
|
||||
|
||||
module mod1
|
||||
(
|
||||
input clk,
|
||||
input [3:0] d,
|
||||
output logic [3:0] q
|
||||
);
|
||||
always @(posedge clk)
|
||||
q <= d;
|
||||
|
||||
endmodule
|
||||
|
||||
module mod2
|
||||
(
|
||||
input clk,
|
||||
input [3:0] d,
|
||||
output wire [3:0] q
|
||||
);
|
||||
|
||||
assign q = d;
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue