Add very experimental --xml option

This commit is contained in:
Wilson Snyder 2012-03-20 16:13:10 -04:00
parent 37839e2709
commit 204fb82975
11 changed files with 709 additions and 248 deletions

View File

@ -182,6 +182,7 @@ RAW_OBJS = \
V3EmitCSyms.o \
V3EmitMk.o \
V3EmitV.o \
V3EmitXml.o \
V3Error.o \
V3Expand.o \
V3File.o \

196
src/V3EmitXml.cpp Normal file
View File

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

37
src/V3EmitXml.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,24 +220,31 @@ void process () {
V3Assert::assertAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));
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"));
if (!v3Global.opt.xmlOnly()) {
// Expand Inouts
V3Tristate::inoutAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
}
if (!v3Global.opt.xmlOnly()) {
// Remove cell arrays (must be between V3Width and scoping)
V3Inst::dearrayAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.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());
@ -252,22 +267,26 @@ void process () {
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"));
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---------------
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....
@ -284,11 +303,14 @@ void process () {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
V3LinkDot::linkDotScope(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
}
//--SCOPE BASED OPTIMIZATIONS--------------
if (!v3Global.opt.xmlOnly()) {
// 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"));
@ -300,7 +322,7 @@ void process () {
// Add __PVT's
// After V3Task so task internal variables will get renamed
V3Name::nameAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("name.tree"));
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("name.tree"));
// Loop unrolling & convert FORs to WHILEs
V3Unroll::unrollAll(v3Global.rootp());
@ -332,6 +354,7 @@ void process () {
// 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"));
@ -351,7 +374,7 @@ void process () {
// 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"));
if (dumpMore) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
}
V3SplitAs::splitAsAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("splitas.tree"));
@ -380,6 +403,7 @@ void process () {
// 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"));
@ -437,6 +461,7 @@ void process () {
// 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"));
@ -459,9 +484,11 @@ void process () {
// Remove scopes; make varrefs/funccalls relative to current module
V3Descope::descopeAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("descope.tree"));
}
//--MODULE OPTIMIZATIONS--------------
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());
@ -471,6 +498,7 @@ void process () {
// 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
@ -478,13 +506,16 @@ void process () {
V3Combine::combineAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
}
}
V3Error::abortIfErrors();
//--GENERATION------------------
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"));
@ -499,34 +530,40 @@ void process () {
// 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.
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();

86
test_regress/t/t_xml_first.out Executable file
View File

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

22
test_regress/t/t_xml_first.pl Executable file
View File

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

View File

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