verilator/src/V3EmitV.cpp

753 lines
24 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Emit Verilog from tree
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2004-2018 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 "V3Global.h"
#include "V3EmitV.h"
#include "V3EmitCBase.h"
#include <algorithm>
#include <cmath>
#include <cstdarg>
#include <map>
#include <vector>
//######################################################################
// Emit statements and math operators
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi;
AstSenTree* m_sensesp;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void puts(const string& str) = 0;
virtual void putbs(const string& str) = 0;
virtual void putfs(AstNode* nodep, const string& str) = 0; // Fileline and node %% mark
virtual void putqs(AstNode* nodep, const string& str) = 0; // Fileline quiet w/o %% mark
virtual void putsNoTracking(const string& str) = 0;
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(V3Number::quoteNameControls(str));
putsNoTracking("\"");
}
// VISITORS
virtual void visit(AstNetlist* nodep) {
iterateChildren(nodep);
}
virtual void visit(AstNodeModule* nodep) {
putfs(nodep, nodep->verilogKwd()+" "+modClassName(nodep)+";\n");
iterateChildren(nodep);
putqs(nodep, "end"+nodep->verilogKwd()+"\n");
}
virtual void visit(AstNodeFTask* nodep) {
putfs(nodep, nodep->isFunction() ? "function":"task");
puts(" ");
puts(nodep->prettyName());
puts(";\n");
putqs(nodep, "begin\n"); // Only putfs the first time for each visitor; later for same node is putqs
iterateAndNextNull(nodep->stmtsp());
putqs(nodep, "end\n");
}
virtual void visit(AstBegin* nodep) {
if (nodep->unnamed()) {
putbs("begin\n");
} else {
putbs("begin : "+nodep->name()+"\n");
}
iterateChildren(nodep);
puts("end\n");
}
virtual void visit(AstGenerate* nodep) {
putfs(nodep, "generate\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstFinal* nodep) {
putfs(nodep, "final begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstInitial* nodep) {
putfs(nodep,"initial begin\n");
iterateChildren(nodep);
putqs(nodep, "end\n");
}
virtual void visit(AstAlways* nodep) {
putfs(nodep,"always ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
putbs(" begin\n");
iterateAndNextNull(nodep->bodysp());
putqs(nodep,"end\n");
}
virtual void visit(AstAlwaysPublic* nodep) {
putfs(nodep,"/*verilator public_flat_rw ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
putqs(nodep," ");
iterateAndNextNull(nodep->bodysp());
putqs(nodep,"*/\n");
}
virtual void visit(AstNodeAssign* nodep) {
iterateAndNextNull(nodep->lhsp());
putfs(nodep," "+nodep->verilogKwd()+" ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignDly* nodep) {
iterateAndNextNull(nodep->lhsp());
putfs(nodep," <= ");
iterateAndNextNull(nodep->rhsp());
puts(";\n");
}
virtual void visit(AstAssignAlias* nodep) {
putbs("alias ");
iterateAndNextNull(nodep->lhsp());
putfs(nodep," = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAssignW* nodep) {
putfs(nodep,"assign ");
iterateAndNextNull(nodep->lhsp());
putbs(" = ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstBreak* nodep) {
putbs("break");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstSenTree* nodep) {
// AstSenItem is called for dumping in isolation by V3Order
putfs(nodep,"@(");
for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) {
iterate(expp);
if (expp->nextp()) putqs(expp->nextp()," or ");
}
puts(")");
}
virtual void visit(AstSenGate* nodep) {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
}
virtual void visit(AstSenItem* nodep) {
putfs(nodep,"");
puts(nodep->edgeType().verilogKwd());
if (nodep->sensp()) puts(" ");
iterateChildren(nodep);
}
virtual void visit(AstNodeCase* nodep) {
putfs(nodep,"");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (casep->priorityPragma()) puts("priority ");
if (casep->uniquePragma()) puts("unique ");
if (casep->unique0Pragma()) puts("unique0 ");
}
puts(nodep->verilogKwd());
puts(" (");
iterateAndNextNull(nodep->exprp());
puts(")\n");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (casep->fullPragma() || casep->parallelPragma()) {
puts(" // synopsys");
if (casep->fullPragma()) puts(" full_case");
if (casep->parallelPragma()) puts(" parallel_case");
}
}
iterateAndNextNull(nodep->itemsp());
putqs(nodep,"endcase\n");
}
virtual void visit(AstCaseItem* nodep) {
if (nodep->condsp()) {
iterateAndNextNull(nodep->condsp());
} else putbs("default");
putfs(nodep,": begin ");
iterateAndNextNull(nodep->bodysp());
putqs(nodep,"end\n");
}
virtual void visit(AstComment* nodep) {
puts(string("// ")+nodep->name()+"\n");
iterateChildren(nodep);
}
virtual void visit(AstContinue* nodep) {
putbs("continue");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstCoverDecl*) {} // N/A
virtual void visit(AstCoverInc*) {} // N/A
virtual void visit(AstCoverToggle*) {} // N/A
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, AstNode* exprsp) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (fileOrStrgp) { iterateAndNextNull(fileOrStrgp); putbs(","); }
putsQuoted(text);
for (AstNode* expp=exprsp; expp; expp = expp->nextp()) {
puts(",");
iterateAndNextNull(expp);
}
puts(");\n");
}
virtual void visit(AstDisable* nodep) {
putbs("disable "+nodep->name()+";\n");
}
virtual void visit(AstDisplay* nodep) {
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstFScanF* nodep) {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSScanF* nodep) {
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSFormat* nodep) {
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
}
virtual void visit(AstSFormatF* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
putbs(",");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
if (nodep->modep()) iterateAndNextNull(nodep->modep());
puts(");\n");
}
virtual void visit(AstFClose* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstFFlush* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstJumpGo* nodep) {
putbs("disable "+cvtToStr((void*)(nodep->labelp()))+";\n");
}
virtual void visit(AstJumpLabel* nodep) {
putbs("begin : "+cvtToStr((void*)(nodep))+"\n");
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
puts("end\n");
}
virtual void visit(AstNodeReadWriteMem* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
if (nodep->memp()) iterateAndNextNull(nodep->memp());
if (nodep->lsbp()) { putbs(","); iterateAndNextNull(nodep->lsbp()); }
if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); }
puts(");\n");
}
virtual void visit(AstSysFuncAsTask* nodep) {
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstSysIgnore* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
virtual void visit(AstNodeFor* nodep) {
putfs(nodep,"for (");
m_suppressSemi = true;
iterateAndNextNull(nodep->initsp());
puts(";");
iterateAndNextNull(nodep->condp());
puts(";");
iterateAndNextNull(nodep->incsp());
m_suppressSemi = false;
puts(") begin\n");
iterateAndNextNull(nodep->bodysp());
putqs(nodep,"end\n");
}
virtual void visit(AstRepeat* nodep) {
putfs(nodep,"repeat (");
iterateAndNextNull(nodep->countp());
puts(") begin\n");
iterateAndNextNull(nodep->bodysp());
putfs(nodep,"end\n");
}
virtual void visit(AstWhile* nodep) {
iterateAndNextNull(nodep->precondsp());
putfs(nodep,"while (");
iterateAndNextNull(nodep->condp());
puts(") begin\n");
iterateAndNextNull(nodep->bodysp());
iterateAndNextNull(nodep->incsp());
iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop
putfs(nodep,"end\n");
}
virtual void visit(AstNodeIf* nodep) {
putfs(nodep,"");
if (const AstIf* ifp = VN_CAST(nodep, If)) {
if (ifp->priorityPragma()) puts("priority ");
if (ifp->uniquePragma()) puts("unique ");
if (ifp->unique0Pragma()) puts("unique0 ");
}
puts("if (");
iterateAndNextNull(nodep->condp());
puts(") begin\n");
iterateAndNextNull(nodep->ifsp());
if (nodep->elsesp()) {
putqs(nodep,"end\n");
putqs(nodep,"else begin\n");
iterateAndNextNull(nodep->elsesp());
}
putqs(nodep,"end\n");
}
virtual void visit(AstPast* nodep) {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
puts(",");
iterateAndNextNull(nodep->ticksp());
}
puts(")");
}
virtual void visit(AstReturn* nodep) {
putfs(nodep,"return ");
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstStop* nodep) {
putfs(nodep,"$stop;\n");
}
virtual void visit(AstFinish* nodep) {
putfs(nodep,"$finish;\n");
}
virtual void visit(AstText* nodep) {
putsNoTracking(nodep->text());
}
virtual void visit(AstScopeName* nodep) {
}
virtual void visit(AstCStmt* nodep) {
putfs(nodep,"$_CSTMT(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstCMath* nodep) {
putfs(nodep,"$_CMATH(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCStmt* nodep) {
putfs(nodep,"$c(");
iterateAndNextNull(nodep->bodysp());
puts(");\n");
}
virtual void visit(AstUCFunc* nodep) {
putfs(nodep,"$c(");
iterateAndNextNull(nodep->bodysp());
puts(")");
}
// Operators
virtual void emitVerilogFormat(AstNode* nodep, const string& format,
AstNode* lhsp=NULL, AstNode* rhsp=NULL, AstNode* thsp=NULL) {
// Look at emitVerilog() format for term/uni/dual/triops,
// and write out appropriate text.
// %f Potential fileline-if-change and line break
// %l lhsp - if appropriate
// %r rhsp - if appropriate
// %t thsp - if appropriate
// %d dtypep - if appropriate
// %k Potential line break
bool inPct = false;
putbs("");
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
if (pos[0]=='%') {
inPct = true;
} else if (!inPct) { // Normal text
string s; s+=pos[0]; puts(s);
} else { // Format character
inPct = false;
switch (*pos) {
case '%': puts("%"); break;
case 'f': putfs(nodep,""); break;
case 'k': putbs(""); break;
case 'l': {
if (!lhsp) { nodep->v3fatalSrc("emitVerilog() references undef node"); }
else iterateAndNextNull(lhsp);
break;
}
case 'r': {
if (!rhsp) { nodep->v3fatalSrc("emitVerilog() references undef node"); }
else iterateAndNextNull(rhsp);
break;
}
case 't': {
if (!thsp) { nodep->v3fatalSrc("emitVerilog() references undef node"); }
else iterateAndNextNull(thsp);
break;
}
case 'd': {
if (!nodep->dtypep()) { nodep->v3fatalSrc("emitVerilog() references undef node"); }
else iterateAndNextNull(nodep->dtypep());
break;
}
default:
nodep->v3fatalSrc("Unknown emitVerilog format code: %"<<pos[0]);
break;
}
}
}
}
virtual void visit(AstNodeTermop* nodep) {
emitVerilogFormat(nodep, nodep->emitVerilog());
}
virtual void visit(AstNodeUniop* nodep) {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
}
virtual void visit(AstAttrOf* nodep) {
putfs(nodep,"$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
putbs(",");
iterateAndNextNull(nodep->dimp());
}
puts(")");
}
virtual void visit(AstInitArray* nodep) {
putfs(nodep,"`{");
int pos = 0;
for (AstNode* itemp = nodep->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
int index = nodep->posIndex(pos);
puts(cvtToStr(index));
puts(":");
iterate(itemp);
if (itemp->nextp()) putbs(",");
}
puts("}");
}
virtual void visit(AstNodeCond* nodep) {
putbs("(");
iterateAndNextNull(nodep->condp()); putfs(nodep," ? ");
iterateAndNextNull(nodep->expr1p()); putbs(" : ");
iterateAndNextNull(nodep->expr2p()); puts(")");
}
virtual void visit(AstRange* nodep) {
puts("[");
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt())); puts(":");
puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt())); puts("]");
} else {
iterateAndNextNull(nodep->leftp()); puts(":");
iterateAndNextNull(nodep->rightp()); puts("]");
}
}
virtual void visit(AstSel* nodep) {
iterateAndNextNull(nodep->fromp()); puts("[");
if (VN_IS(nodep->lsbp(), Const)) {
if (nodep->widthp()->isOne()) {
if (VN_IS(nodep->lsbp(), Const)) {
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
} else {
iterateAndNextNull(nodep->lsbp());
}
} else {
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()
+ VN_CAST(nodep->widthp(), Const)->toSInt()
- 1));
puts(":");
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
}
} else {
iterateAndNextNull(nodep->lsbp()); putfs(nodep,"+:");
iterateAndNextNull(nodep->widthp()); puts("]");
}
puts("]");
}
virtual void visit(AstSliceSel* nodep) {
iterateAndNextNull(nodep->fromp());
puts(cvtToStr(nodep->declRange()));
}
virtual void visit(AstTypedef* nodep) {
putfs(nodep,"typedef ");
iterateAndNextNull(nodep->dtypep()); puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
virtual void visit(AstBasicDType* nodep) {
if (nodep->isSigned()) putfs(nodep,"signed ");
putfs(nodep,nodep->prettyName());
if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); }
else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); }
}
virtual void visit(AstConstDType* nodep) {
putfs(nodep,"const ");
iterate(nodep->subDTypep());
}
virtual void visit(AstNodeArrayDType* nodep) {
iterate(nodep->subDTypep());
iterateAndNextNull(nodep->rangep());
}
virtual void visit(AstNodeClassDType* nodep) {
puts(nodep->verilogKwd()+" ");
if (nodep->packed()) puts("packed ");
puts("\n");
iterateAndNextNull(nodep->membersp());
puts("}");
}
virtual void visit(AstMemberDType* nodep) {
iterate(nodep->subDTypep());
puts(" ");
puts(nodep->name());
puts("}");
}
virtual void visit(AstNodeFTaskRef* nodep) {
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
else { putfs(nodep,nodep->prettyName()); }
puts("(");
iterateAndNextNull(nodep->pinsp());
puts(")");
}
virtual void visit(AstArg* nodep) {
iterateAndNextNull(nodep->exprp());
}
// Terminals
virtual void visit(AstVarRef* nodep) {
if (nodep->varScopep())
putfs(nodep,nodep->varScopep()->prettyName());
else {
putfs(nodep,nodep->hiername());
puts(nodep->varp()->prettyName());
}
}
virtual void visit(AstVarXRef* nodep) {
putfs(nodep,nodep->dotted());
puts(".");
puts(nodep->varp()->prettyName());
}
virtual void visit(AstConst* nodep) {
putfs(nodep,nodep->num().ascii(true,true));
}
// Just iterate
virtual void visit(AstTopScope* nodep) {
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) {
iterateChildren(nodep);
}
virtual void visit(AstVar* nodep) {
putfs(nodep,nodep->verilogKwd());
puts(" ");
iterate(nodep->dtypep()); puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
virtual void visit(AstActive* nodep) {
m_sensesp = nodep->sensesp();
iterateAndNextNull(nodep->stmtsp());
m_sensesp = NULL;
}
virtual void visit(AstVarScope*) {}
virtual void visit(AstNodeText*) {}
virtual void visit(AstTraceDecl*) {}
virtual void visit(AstTraceInc*) {}
// NOPs
virtual void visit(AstPragma*) {}
virtual void visit(AstCell*) {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep) {
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
nodep->v3error("Internal: Unknown node type reached emitter: "<<nodep->prettyTypeName());
}
public:
explicit EmitVBaseVisitor(AstSenTree* domainp=NULL) { // Domain for printing one a ALWAYS under a ACTIVE
m_suppressSemi = false;
m_sensesp = domainp;
}
virtual ~EmitVBaseVisitor() {}
};
//######################################################################
// Emit to an output file
class EmitVFileVisitor : public EmitVBaseVisitor {
// MEMBERS
V3OutFile* m_ofp;
// 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); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp) {
m_ofp = ofp;
iterate(nodep);
}
virtual ~EmitVFileVisitor() {}
};
//######################################################################
// Emit to a stream (perhaps stringstream)
class EmitVStreamVisitor : public EmitVBaseVisitor {
// MEMBERS
std::ostream& m_os;
// METHODS
virtual void putsNoTracking(const string& str) { m_os<<str; }
virtual void puts(const string& str) { putsNoTracking(str); }
virtual void putbs(const string& str) { puts(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
virtual void putqs(AstNode*, const string& str) { putbs(str); }
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) {
iterate(nodep);
}
virtual ~EmitVStreamVisitor() {}
};
//######################################################################
// Emit to a stream (perhaps stringstream)
class EmitVPrefixedFormatter : public V3OutFormatter {
std::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; }
EmitVPrefixedFormatter(std::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 ~EmitVPrefixedFormatter() {
if (m_column) puts("\n");
}
};
class EmitVPrefixedVisitor : public EmitVBaseVisitor {
// MEMBERS
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter)
// METHODS
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) { m_formatter.puts(str); }
// We don't use m_formatter's putbs because the tokens will change filelines
// and insert returns at the proper locations
virtual void putbs(const string& str) { m_formatter.puts(str); }
virtual void putfs(AstNode* nodep, const string& str) { putfsqs(nodep,str,false); }
virtual void putqs(AstNode* nodep, const string& str) { putfsqs(nodep,str,true); }
void putfsqs(AstNode* nodep, const string& str, bool quiet) {
if (m_formatter.prefixFl() != nodep->fileline()) {
m_formatter.prefixFl(nodep->fileline());
if (m_formatter.column()) puts("\n"); // This in turn will print the m_prefixFl
}
if (!quiet && nodep->user3()) puts("%%");
putbs(str);
}
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
}
virtual ~EmitVPrefixedVisitor() {}
};
//######################################################################
// EmitV class functions
void V3EmitV::emitv() {
UINFO(2,__FUNCTION__<<": "<<endl);
if (1) {
// All-in-one file
V3OutVFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__Vout.v");
of.putsHeader();
of.puts("# DESCR" "IPTION: Verilator output: Verilog representation of internal tree for debug\n");
EmitVFileVisitor visitor (v3Global.rootp(), &of);
} else {
// Process each module in turn
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
V3OutVFile of (v3Global.opt.makeDir()
+"/"+EmitCBaseVisitor::modClassName(modp)+"__Vout.v");
of.putsHeader();
EmitVFileVisitor visitor (modp, &of);
}
}
}
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) {
EmitVStreamVisitor(nodep, os);
}
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, flWidth, domainp, user3mark);
}