Add very experimental --xml option
This commit is contained in:
parent
37839e2709
commit
204fb82975
|
|
@ -182,6 +182,7 @@ RAW_OBJS = \
|
||||||
V3EmitCSyms.o \
|
V3EmitCSyms.o \
|
||||||
V3EmitMk.o \
|
V3EmitMk.o \
|
||||||
V3EmitV.o \
|
V3EmitV.o \
|
||||||
|
V3EmitXml.o \
|
||||||
V3Error.o \
|
V3Error.o \
|
||||||
V3Expand.o \
|
V3Expand.o \
|
||||||
V3File.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;
|
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
|
// FileLine class functions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,7 @@ protected:
|
||||||
int nameToNumber(const string& filename);
|
int nameToNumber(const string& filename);
|
||||||
const string numberToName(int filenameno) const { return m_names[filenameno]; }
|
const string numberToName(int filenameno) const { return m_names[filenameno]; }
|
||||||
void clear() { m_namemap.clear(); m_names.clear(); }
|
void clear() { m_namemap.clear(); m_names.clear(); }
|
||||||
|
void fileNameNumMapDumpXml(ostream& os);
|
||||||
static const string filenameLetters(int fileno);
|
static const string filenameLetters(int fileno);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -327,6 +328,7 @@ public:
|
||||||
const string filebasename () const;
|
const string filebasename () const;
|
||||||
const string filebasenameNoExt () const;
|
const string filebasenameNoExt () const;
|
||||||
const string profileFuncname() const;
|
const string profileFuncname() const;
|
||||||
|
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
|
||||||
string lineDirectiveStrg(int enter_exit_level) const;
|
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 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); }
|
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
|
||||||
|
|
@ -352,6 +354,8 @@ public:
|
||||||
defaultFileLine().warnOff(code, flag); }
|
defaultFileLine().warnOff(code, flag); }
|
||||||
static bool globalWarnOff(const string& code, bool flag) {
|
static bool globalWarnOff(const string& code, bool flag) {
|
||||||
return defaultFileLine().warnOff(code, flag); }
|
return defaultFileLine().warnOff(code, flag); }
|
||||||
|
static void fileNameNumMapDumpXml(ostream& os) {
|
||||||
|
singleton().fileNameNumMapDumpXml(os); }
|
||||||
|
|
||||||
// METHODS - Called from netlist
|
// METHODS - Called from netlist
|
||||||
// Merge warning disables from another fileline
|
// 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-sigsegv") ) { throwSigsegv(); } // Undocumented, see also --debug-abort
|
||||||
else if ( !strcmp (sw, "-debug-fatalsrc") ) { v3fatalSrc("--debug-fatal-src"); } // 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", 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, "-exe", flag/*ref*/) ) { m_exe = flag; }
|
||||||
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
|
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
|
||||||
else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)){ m_inhibitSim = 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-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
||||||
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = 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, "-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
|
// Optimization
|
||||||
else if ( !strncmp (sw, "-O", 2) ) {
|
else if ( !strncmp (sw, "-O", 2) ) {
|
||||||
for (const char* cp=sw+strlen("-O"); *cp; ++cp) {
|
for (const char* cp=sw+strlen("-O"); *cp; ++cp) {
|
||||||
|
|
@ -1161,6 +1163,7 @@ V3Options::V3Options() {
|
||||||
m_coverageUser = false;
|
m_coverageUser = false;
|
||||||
m_debugCheck = false;
|
m_debugCheck = false;
|
||||||
m_dumpTree = false;
|
m_dumpTree = false;
|
||||||
|
m_dumpTreeMore = false;
|
||||||
m_exe = false;
|
m_exe = false;
|
||||||
m_ignc = false;
|
m_ignc = false;
|
||||||
m_l2Name = true;
|
m_l2Name = true;
|
||||||
|
|
@ -1182,6 +1185,7 @@ V3Options::V3Options() {
|
||||||
m_traceDups = false;
|
m_traceDups = false;
|
||||||
m_traceUnderscore = false;
|
m_traceUnderscore = false;
|
||||||
m_underlineZero = false;
|
m_underlineZero = false;
|
||||||
|
m_xmlOnly = false;
|
||||||
|
|
||||||
m_errorLimit = 50;
|
m_errorLimit = 50;
|
||||||
m_ifDepth = 0;
|
m_ifDepth = 0;
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ class V3Options {
|
||||||
bool m_coverageUser; // main switch: --coverage-func
|
bool m_coverageUser; // main switch: --coverage-func
|
||||||
bool m_debugCheck; // main switch: --debug-check
|
bool m_debugCheck; // main switch: --debug-check
|
||||||
bool m_dumpTree; // main switch: --dump-tree
|
bool m_dumpTree; // main switch: --dump-tree
|
||||||
|
bool m_dumpTreeMore; // main switch: --dump-tree-more
|
||||||
bool m_exe; // main switch: --exe
|
bool m_exe; // main switch: --exe
|
||||||
bool m_ignc; // main switch: --ignc
|
bool m_ignc; // main switch: --ignc
|
||||||
bool m_inhibitSim; // main switch: --inhibit-sim
|
bool m_inhibitSim; // main switch: --inhibit-sim
|
||||||
|
|
@ -126,6 +127,7 @@ class V3Options {
|
||||||
bool m_traceDups; // main switch: --trace-dups
|
bool m_traceDups; // main switch: --trace-dups
|
||||||
bool m_traceUnderscore;// main switch: --trace-underscore
|
bool m_traceUnderscore;// main switch: --trace-underscore
|
||||||
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
|
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_errorLimit; // main switch: --error-limit
|
||||||
int m_ifDepth; // main switch: --if-depth
|
int m_ifDepth; // main switch: --if-depth
|
||||||
|
|
@ -237,6 +239,7 @@ class V3Options {
|
||||||
bool coverageUser() const { return m_coverageUser; }
|
bool coverageUser() const { return m_coverageUser; }
|
||||||
bool debugCheck() const { return m_debugCheck; }
|
bool debugCheck() const { return m_debugCheck; }
|
||||||
bool dumpTree() const { return m_dumpTree; }
|
bool dumpTree() const { return m_dumpTree; }
|
||||||
|
bool dumpTreeMore() const { return m_dumpTreeMore; }
|
||||||
bool exe() const { return m_exe; }
|
bool exe() const { return m_exe; }
|
||||||
bool trace() const { return m_trace; }
|
bool trace() const { return m_trace; }
|
||||||
bool traceDups() const { return m_traceDups; }
|
bool traceDups() const { return m_traceDups; }
|
||||||
|
|
@ -252,6 +255,7 @@ class V3Options {
|
||||||
bool lintOnly() const { return m_lintOnly; }
|
bool lintOnly() const { return m_lintOnly; }
|
||||||
bool ignc() const { return m_ignc; }
|
bool ignc() const { return m_ignc; }
|
||||||
bool inhibitSim() const { return m_inhibitSim; }
|
bool inhibitSim() const { return m_inhibitSim; }
|
||||||
|
bool xmlOnly() const { return m_xmlOnly; }
|
||||||
|
|
||||||
int errorLimit() const { return m_errorLimit; }
|
int errorLimit() const { return m_errorLimit; }
|
||||||
int ifDepth() const { return m_ifDepth; }
|
int ifDepth() const { return m_ifDepth; }
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include "V3EmitC.h"
|
#include "V3EmitC.h"
|
||||||
#include "V3EmitMk.h"
|
#include "V3EmitMk.h"
|
||||||
#include "V3EmitV.h"
|
#include "V3EmitV.h"
|
||||||
|
#include "V3EmitXml.h"
|
||||||
#include "V3Expand.h"
|
#include "V3Expand.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
#include "V3Cdc.h"
|
#include "V3Cdc.h"
|
||||||
|
|
@ -142,6 +143,8 @@ void V3Global::readFiles() {
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
void process () {
|
void process () {
|
||||||
|
bool dumpMore = v3Global.opt.dumpTreeMore();
|
||||||
|
|
||||||
// Sort modules by level so later algorithms don't need to care
|
// Sort modules by level so later algorithms don't need to care
|
||||||
V3LinkLevel::modSortByLevel();
|
V3LinkLevel::modSortByLevel();
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree"));
|
||||||
|
|
@ -149,14 +152,19 @@ void process () {
|
||||||
|
|
||||||
// Convert parseref's to varrefs, and other directly post parsing fixups
|
// Convert parseref's to varrefs, and other directly post parsing fixups
|
||||||
V3LinkParse::linkParse(v3Global.rootp());
|
V3LinkParse::linkParse(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkparse.tree"));
|
||||||
// Cross-link signal names
|
// Cross-link signal names
|
||||||
V3Link::link(v3Global.rootp());
|
V3Link::link(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkmain.tree"));
|
||||||
// Cross-link dotted hierarchical references
|
// Cross-link dotted hierarchical references
|
||||||
V3LinkDot::linkDotPrearrayed(v3Global.rootp());
|
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
|
// Correct state we couldn't know at parse time, repair SEL's
|
||||||
V3LinkResolve::linkResolve(v3Global.rootp());
|
V3LinkResolve::linkResolve(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkresolve.tree"));
|
||||||
// Set Lvalue's in variable refs
|
// Set Lvalue's in variable refs
|
||||||
V3LinkLValue::linkLValue(v3Global.rootp());
|
V3LinkLValue::linkLValue(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linklvalue.tree"));
|
||||||
// Convert return/continue/disable to jumps
|
// Convert return/continue/disable to jumps
|
||||||
V3LinkJump::linkJump(v3Global.rootp());
|
V3LinkJump::linkJump(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
||||||
|
|
@ -173,7 +181,7 @@ void process () {
|
||||||
|
|
||||||
// Remove any modules that were parameterized and are no longer referenced.
|
// Remove any modules that were parameterized and are no longer referenced.
|
||||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
||||||
v3Global.checkTree();
|
v3Global.checkTree();
|
||||||
|
|
||||||
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
|
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
|
||||||
|
|
@ -186,7 +194,7 @@ void process () {
|
||||||
V3Width::widthCommit(v3Global.rootp());
|
V3Width::widthCommit(v3Global.rootp());
|
||||||
v3Global.assertDTypesResolved(true);
|
v3Global.assertDTypesResolved(true);
|
||||||
v3Global.assertWidthsMatch(true);
|
v3Global.assertWidthsMatch(true);
|
||||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("widthcommit.tree"));
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("widthcommit.tree"));
|
||||||
|
|
||||||
// Coverage insertion
|
// Coverage insertion
|
||||||
// Before we do dead code elimination and inlining, or we'll lose it.
|
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||||
|
|
@ -212,321 +220,350 @@ void process () {
|
||||||
V3Assert::assertAll(v3Global.rootp());
|
V3Assert::assertAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
|
||||||
|
|
||||||
// Add top level wrapper with instance pointing to old top
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
// Move packages to under new top
|
// Add top level wrapper with instance pointing to old top
|
||||||
// Must do this after we know the width of any parameters
|
// Move packages to under new top
|
||||||
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
|
// Must do this after we know the width of any parameters
|
||||||
V3LinkLevel::wrapTop(v3Global.rootp());
|
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
|
||||||
|
V3LinkLevel::wrapTop(v3Global.rootp());
|
||||||
|
}
|
||||||
|
|
||||||
// Propagate constants into expressions
|
// Propagate constants into expressions
|
||||||
V3Const::constifyAllLint(v3Global.rootp());
|
V3Const::constifyAllLint(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||||
|
|
||||||
// Expand Inouts
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
V3Tristate::inoutAll(v3Global.rootp());
|
// Expand Inouts
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
|
V3Tristate::inoutAll(v3Global.rootp());
|
||||||
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
|
||||||
|
}
|
||||||
|
|
||||||
// Remove cell arrays (must be between V3Width and scoping)
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
V3Inst::dearrayAll(v3Global.rootp());
|
// Remove cell arrays (must be between V3Width and scoping)
|
||||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
|
V3Inst::dearrayAll(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
|
||||||
|
}
|
||||||
|
|
||||||
// Expand inouts, stage 2
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
|
// Expand inouts, stage 2
|
||||||
V3Tristate::tristateAll(v3Global.rootp());
|
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
|
V3Tristate::tristateAll(v3Global.rootp());
|
||||||
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
|
||||||
|
|
||||||
// Task inlining & pushing BEGINs names to variables/cells
|
// Task inlining & pushing BEGINs names to variables/cells
|
||||||
// Begin processing must be after Param, before module inlining
|
// Begin processing must be after Param, before module inlining
|
||||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
|
||||||
|
|
||||||
// Move assignments from X into MODULE temps.
|
// Move assignments from X into MODULE temps.
|
||||||
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
||||||
V3Unknown::unknownAll(v3Global.rootp());
|
V3Unknown::unknownAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
|
||||||
|
|
||||||
// Module inlining
|
// Module inlining
|
||||||
// Cannot remove dead variables after this, as alias information for final
|
// Cannot remove dead variables after this, as alias information for final
|
||||||
// V3Scope's V3LinkDot is in the AstVar.
|
// V3Scope's V3LinkDot is in the AstVar.
|
||||||
if (v3Global.opt.oInline()) {
|
if (v3Global.opt.oInline()) {
|
||||||
V3Inline::inlineAll(v3Global.rootp());
|
V3Inline::inlineAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
|
||||||
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
||||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--PRE-FLAT OPTIMIZATIONS------------------
|
//--PRE-FLAT OPTIMIZATIONS------------------
|
||||||
|
|
||||||
// Initial const/dead to reduce work for ordering code
|
// Initial const/dead to reduce work for ordering code
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
V3Const::constifyAll(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||||
v3Global.checkTree();
|
v3Global.checkTree();
|
||||||
|
|
||||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||||
v3Global.checkTree();
|
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||||
|
v3Global.checkTree();
|
||||||
|
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
//--FLATTENING---------------
|
//--FLATTENING---------------
|
||||||
|
|
||||||
// We're going to flatten the hierarchy, so as many optimizations that
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
// can be done as possible should be before this....
|
// 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
|
// Convert instantiations to wassigns and always blocks
|
||||||
V3Inst::instAll(v3Global.rootp());
|
V3Inst::instAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inst.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inst.tree"));
|
||||||
|
|
||||||
// Inst may have made lots of concats; fix them
|
// Inst may have made lots of concats; fix them
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
V3Const::constifyAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||||
|
|
||||||
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
||||||
V3Scope::scopeAll(v3Global.rootp());
|
V3Scope::scopeAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
|
||||||
V3LinkDot::linkDotScope(v3Global.rootp());
|
V3LinkDot::linkDotScope(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||||
|
}
|
||||||
|
|
||||||
//--SCOPE BASED OPTIMIZATIONS--------------
|
//--SCOPE BASED OPTIMIZATIONS--------------
|
||||||
|
|
||||||
// Cleanup
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
// Cleanup
|
||||||
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()) {
|
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
V3Const::constifyAll(v3Global.rootp());
|
||||||
V3Life::lifeAll(v3Global.rootp());
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const_predad.tree"));
|
||||||
}
|
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||||
if (v3Global.opt.oLifePost()) {
|
v3Global.checkTree();
|
||||||
V3LifePost::lifepostAll(v3Global.rootp());
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||||
}
|
|
||||||
if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
|
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove unused vars
|
// Inline all tasks
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
V3Task::taskAll(v3Global.rootp());
|
||||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("task.tree"));
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.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
|
#ifndef NEW_ORDERING
|
||||||
// Detect change loop
|
// Change generated clocks to look at delayed signals
|
||||||
V3Changed::changedAll(v3Global.rootp());
|
V3GenClk::genClkAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("changed.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("genclk.tree"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create tracing logic, since we ripped out some signals the user might want to trace
|
// Convert sense lists into IF statements.
|
||||||
// Note past this point, we presume traced variables won't move between CFuncs
|
V3Clock::clockAll(v3Global.rootp());
|
||||||
// (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));
|
||||||
if (v3Global.opt.trace()) {
|
|
||||||
V3Trace::traceAll(v3Global.rootp());
|
// Cleanup any dly vars or other temps that are simple assignments
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("trace.tree"));
|
// 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--------------
|
//--MODULE OPTIMIZATIONS--------------
|
||||||
|
|
||||||
// Split deep blocks to appease MSVC++. Must be before Localize.
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
|
// Split deep blocks to appease MSVC++. Must be before Localize.
|
||||||
V3DepthBlock::depthBlockAll(v3Global.rootp());
|
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("deepblock.tree"));
|
V3DepthBlock::depthBlockAll(v3Global.rootp());
|
||||||
}
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("deepblock.tree"));
|
||||||
|
}
|
||||||
|
|
||||||
// Move BLOCKTEMPS from class to local variables
|
// Move BLOCKTEMPS from class to local variables
|
||||||
if (v3Global.opt.oLocalize()) {
|
if (v3Global.opt.oLocalize()) {
|
||||||
V3Localize::localizeAll(v3Global.rootp());
|
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
|
// Icache packing; combine common code in each module's functions into subroutines
|
||||||
if (v3Global.opt.oCombine()) {
|
if (v3Global.opt.oCombine()) {
|
||||||
V3Combine::combineAll(v3Global.rootp());
|
V3Combine::combineAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
//--GENERATION------------------
|
//--GENERATION------------------
|
||||||
|
|
||||||
// Remove unused vars
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
// Remove unused vars
|
||||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
V3Const::constifyAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
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
|
// 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.
|
// Bits between widthMin() and width() are irrelevant, but may be non zero.
|
||||||
v3Global.assertWidthsMatch(false);
|
v3Global.assertWidthsMatch(false);
|
||||||
|
|
||||||
// Make all math operations either 8, 16, 32 or 64 bits
|
// Make all math operations either 8, 16, 32 or 64 bits
|
||||||
V3Clean::cleanAll(v3Global.rootp());
|
V3Clean::cleanAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clean.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clean.tree"));
|
||||||
|
|
||||||
// Move wide constants to BLOCK temps.
|
// Move wide constants to BLOCK temps.
|
||||||
V3Premit::premitAll(v3Global.rootp());
|
V3Premit::premitAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("premit.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("premit.tree"));
|
||||||
|
}
|
||||||
|
|
||||||
// Expand macros and wide operators into C++ primitives
|
// Expand macros and wide operators into C++ primitives
|
||||||
if (v3Global.opt.oExpand()) {
|
if (!v3Global.opt.xmlOnly()
|
||||||
|
&& v3Global.opt.oExpand()) {
|
||||||
V3Expand::expandAll(v3Global.rootp());
|
V3Expand::expandAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("expand.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("expand.tree"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate constants across WORDSEL arrayed temporaries
|
// Propagate constants across WORDSEL arrayed temporaries
|
||||||
if (v3Global.opt.oSubst()) {
|
if (!v3Global.opt.xmlOnly()
|
||||||
|
&& v3Global.opt.oSubst()) {
|
||||||
// Constant folding of expanded stuff
|
// Constant folding of expanded stuff
|
||||||
V3Const::constifyCpp(v3Global.rootp());
|
V3Const::constifyCpp(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||||
V3Subst::substituteAll(v3Global.rootp());
|
V3Subst::substituteAll(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("subst.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("subst.tree"));
|
||||||
}
|
}
|
||||||
if (v3Global.opt.oSubstConst()) {
|
if (!v3Global.opt.xmlOnly()
|
||||||
|
&& v3Global.opt.oSubstConst()) {
|
||||||
// Constant folding of substitutions
|
// Constant folding of substitutions
|
||||||
V3Const::constifyCpp(v3Global.rootp());
|
V3Const::constifyCpp(v3Global.rootp());
|
||||||
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("constc.tree"));
|
||||||
|
|
||||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v3Global.opt.lintOnly()) {
|
if (!v3Global.opt.lintOnly()
|
||||||
|
&& !v3Global.opt.xmlOnly()) {
|
||||||
// Fix very deep expressions
|
// Fix very deep expressions
|
||||||
// Mark evaluation functions as member functions, if needed.
|
// Mark evaluation functions as member functions, if needed.
|
||||||
V3Depth::depthAll(v3Global.rootp());
|
V3Depth::depthAll(v3Global.rootp());
|
||||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("depth.tree"));
|
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("depth.tree"));
|
||||||
|
|
||||||
// Branch prediction
|
// Branch prediction
|
||||||
V3Branch::branchAll(v3Global.rootp());
|
V3Branch::branchAll(v3Global.rootp());
|
||||||
|
|
@ -540,14 +577,21 @@ void process () {
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
// Output the text
|
// 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
|
// emitcInlines is first, as it may set needHInlines which other emitters read
|
||||||
V3EmitC::emitcInlines();
|
V3EmitC::emitcInlines();
|
||||||
V3EmitC::emitcSyms();
|
V3EmitC::emitcSyms();
|
||||||
V3EmitC::emitcTrace();
|
V3EmitC::emitcTrace();
|
||||||
}
|
}
|
||||||
// Unfortunately we have some lint checks in emitc.
|
if (!v3Global.opt.xmlOnly()) { // Unfortunately we have some lint checks in emitc.
|
||||||
V3EmitC::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
|
// Statistics
|
||||||
if (v3Global.opt.stats()) {
|
if (v3Global.opt.stats()) {
|
||||||
|
|
@ -555,7 +599,8 @@ void process () {
|
||||||
V3Stats::statsReport();
|
V3Stats::statsReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v3Global.opt.lintOnly()) {
|
if (!v3Global.opt.lintOnly()
|
||||||
|
&& !v3Global.opt.xmlOnly()) {
|
||||||
// Makefile must be after all other emitters
|
// Makefile must be after all other emitters
|
||||||
V3EmitMk::emitmk(v3Global.rootp());
|
V3EmitMk::emitmk(v3Global.rootp());
|
||||||
}
|
}
|
||||||
|
|
@ -584,8 +629,9 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (!v3Global.opt.outFormatOk()
|
if (!v3Global.opt.outFormatOk()
|
||||||
&& !v3Global.opt.preprocOnly()
|
&& !v3Global.opt.preprocOnly()
|
||||||
&& !v3Global.opt.lintOnly()
|
&& !v3Global.opt.lintOnly()
|
||||||
|
&& !v3Global.opt.xmlOnly()
|
||||||
&& !v3Global.opt.cdc()) {
|
&& !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
|
// Check environment
|
||||||
V3Options::getenvSYSTEMC();
|
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