Add '--decorations node' for inserting debug comments into emitted code.

This commit is contained in:
Wilson Snyder 2024-01-24 21:51:47 -05:00
parent c8a40e0b52
commit 354a534d68
25 changed files with 558 additions and 332 deletions

View File

@ -16,6 +16,7 @@ Verilator 5.021 devel
* Add predicted stack overflow warning (#4799).
* Add +verilator+coverage+file runtime option.
* Add --main support for dumping coverage.
* Add '--decorations node' for inserting debug comments into emitted code.
* Remove deprecated 32-bit pointer mode (`gcc -m32`).
* Change zero replication width error to ZEROREPL warning (#4753) (#4762). [Pengcheng Xu]
* Support `vpiConstType` in `vpi_get_str()` (#4797). [Marlon James]

View File

@ -324,7 +324,8 @@ detailed descriptions of these arguments.
--no-debug-leak Disable leaking memory in --debug mode
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--no-decoration Disable comments and symbol decorations
--decorations <level> Set output comment and spacing level
--no-decoration Disable comments and lower spacing level
--default-language <lang> Default language to parse
+define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file

View File

@ -6,7 +6,7 @@ Deprecations
The following deprecated items are scheduled for future removal:
C++11 compiler support
C++14 compiler support
Verilator currently requires a C++20 or newer compiler for timing, and a
C++14 or newer compiler for both compiling Verilator and compiling
Verilated models with --no-timing.

View File

@ -304,12 +304,40 @@ Summary:
detailed messages. See :vlopt:`--debug` for other implications of
enabling debug.
.. option:: --decorations none
.. option:: --decorations medium
.. option:: --decorations node
When creating output Verilated code, set level of comment and whitespace
decoration.
With "--decorations none",
Minimize comments, white space, symbol names, and other decorative
items, at the cost of reduced readability. This may assist C++ compile
times. This will not typically change the ultimate model's
performance, but may in some cases. See also :vlopt:`--no-decoration`
option.
With "--decorations medium",
The default, put a small amount of comments and white space, for
typical level of readability.
With "--decorations node",
Include comments indicating what caused generation of the following
text, including what node pointer (corresponding to
:vlopt:`--dump-tree` .tree printed data), and the source Verilog
filename and line number. If subsequent following statements etc have
the same filename/line number these comments are omitted. This
enables easy debug when looking at the C++ code to determine what
Verilog source may be related. As node pointers are not stable
between different Verilator runs, this may harm compile caching and
should only be used for debug.
.. option:: --no-decoration
When creating output Verilated code, minimize comments, white space,
symbol names, and other decorative items, at the cost of reduced
readability. This may assist C++ compile times. This will not typically
change the ultimate model's performance, but may in some cases.
Alias for ``--decorations none``.
.. option:: --default-language <value>

View File

@ -524,11 +524,16 @@ with:
.. code-block:: bash
--decorations node
-CFLAGS -ggdb -LDFLAGS -ggdb
-CFLAGS -DVL_DEBUG=1
-CFLAGS -D_GLIBCXX_DEBUG
-CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined
The :vlopt:`--decorations node` option used here will add comments to the
Verilated C++ code to indicate what Verilog code was responsible, which may
assist debug readability.
The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options used here pass the
following argument into the generated Makefile for use as compiler or
linker options respectively. If you are using your own Makefiles, adapt

View File

@ -106,19 +106,19 @@ string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) {
void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
bool withScope) {
if (funcp->slow()) puts("VL_ATTR_COLD ");
if (funcp->slow()) putns(funcp, "VL_ATTR_COLD ");
if (!funcp->isConstructor() && !funcp->isDestructor()) {
puts(funcp->rtnTypeVoid());
putns(funcp, funcp->rtnTypeVoid());
puts(" ");
}
if (withScope) {
if (funcp->dpiExportDispatcher()) {
puts(topClassName() + "::");
putns(funcp, topClassName() + "::");
} else if (funcp->isProperMethod()) {
puts(prefixNameProtect(modp) + "::");
putns(funcp, prefixNameProtect(modp) + "::");
}
}
puts(funcNameProtect(funcp, modp));
putns(funcp, funcNameProtect(funcp, modp));
puts("(" + cFuncArgs(funcp) + ")");
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
}
@ -126,16 +126,16 @@ void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNode
void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
bool cLinkage) {
ensureNewLine();
if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n");
if (cLinkage) puts("extern \"C\" ");
if (funcp->isStatic() && funcp->isProperMethod()) puts("static ");
if (!funcp->ifdef().empty()) putns(funcp, "#ifdef " + funcp->ifdef() + "\n");
if (cLinkage) putns(funcp, "extern \"C\" ");
if (funcp->isStatic() && funcp->isProperMethod()) putns(funcp, "static ");
if (funcp->isVirtual()) {
UASSERT_OBJ(funcp->isProperMethod(), funcp, "Virtual function is not a proper method");
puts("virtual ");
putns(funcp, "virtual ");
}
emitCFuncHeader(funcp, modp, /* withScope: */ false);
puts(";\n");
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
putns(funcp, ";\n");
if (!funcp->ifdef().empty()) putns(funcp, "#endif // " + funcp->ifdef() + "\n");
}
void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
@ -146,21 +146,21 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
// This isn't very robust and may need cleanup for other data types
for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
puts("[" + cvtToStr(arrayp->elementsConst()) + "]");
putns(arrayp, "[" + cvtToStr(arrayp->elementsConst()) + "]");
}
};
if (nodep->isIO() && nodep->isSc()) {
UASSERT_OBJ(basicp, nodep, "Unimplemented: Outputting this data type");
if (nodep->attrScClocked() && nodep->isReadOnly()) {
puts("sc_core::sc_in_clk ");
putns(nodep, "sc_core::sc_in_clk ");
} else {
if (nodep->isInoutish()) {
puts("sc_core::sc_inout<");
putns(nodep, "sc_core::sc_inout<");
} else if (nodep->isWritable()) {
puts("sc_core::sc_out<");
putns(nodep, "sc_core::sc_out<");
} else if (nodep->isNonOutput()) {
puts("sc_core::sc_in<");
putns(nodep, "sc_core::sc_in<");
} else {
nodep->v3fatalSrc("Unknown type");
}
@ -168,20 +168,20 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
puts("> ");
}
if (asRef) {
if (refNeedParens) puts("(");
puts("&");
if (refNeedParens) putns(nodep, "(");
putns(nodep, "&");
}
puts(nodep->nameProtect());
putns(nodep, nodep->nameProtect());
if (asRef && refNeedParens) { puts(")"); }
emitDeclArrayBrackets(nodep);
puts(";\n");
} else if (nodep->isIO() && basicp && !basicp->isOpaque()) {
if (nodep->isInoutish()) {
puts("VL_INOUT");
putns(nodep, "VL_INOUT");
} else if (nodep->isWritable()) {
puts("VL_OUT");
putns(nodep, "VL_OUT");
} else if (nodep->isNonOutput()) {
puts("VL_IN");
putns(nodep, "VL_IN");
} else {
nodep->v3fatalSrc("Unknown type");
}
@ -221,7 +221,7 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
&& name.substr(name.size() - suffix.size()) == suffix;
if (beStatic) puts("static thread_local ");
}
puts(nodep->vlArgType(true, false, false, "", asRef));
putns(nodep, nodep->vlArgType(true, false, false, "", asRef));
puts(";\n");
}
}
@ -246,10 +246,10 @@ void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType ty
if (nodep->type() == type) {
if (last_line != nodep->fileline()->lineno()) {
if (last_line < 0) {
puts("\n//*** Below code from `systemc in Verilog file\n");
putns(nodep, "\n//*** Below code from `systemc in Verilog file\n");
}
putsDecoration(
ifNoProtect("// From `systemc at " + nodep->fileline()->ascii() + "\n"));
putsDecoration(nodep, ifNoProtect("// From `systemc at "
+ nodep->fileline()->ascii() + "\n"));
last_line = nodep->fileline()->lineno();
}
ofp()->putsNoTracking(textp->text());

View File

@ -89,10 +89,12 @@ public:
// METHODS
V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putns(const AstNode* nodep, const string& str) { ofp()->putns(nodep, str); }
void putsHeader() { ofp()->putsHeader(); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsDecoration(const string& str) {
if (v3Global.opt.decoration()) puts(str);
void putnbs(const AstNode* nodep, const string& str) { ofp()->putnbs(nodep, str); }
void putsDecoration(const AstNode* nodep, const string& str) {
if (v3Global.opt.decoration()) putns(nodep, str);
}
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
void ensureNewLine() { ofp()->ensureNewLine(); }

View File

@ -60,7 +60,7 @@ protected:
const auto& mapr = nodep->map();
for (const auto& itr : mapr) {
if (comma++) putbs(",\n");
puts(cvtToStr(itr.first));
putns(nodep, cvtToStr(itr.first));
ofp()->printf("%" PRIx64 "ULL", itr.first);
ofp()->putsNoTracking(":");
ofp()->putsNoTracking("{");
@ -102,17 +102,17 @@ protected:
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
const AstNodeDType* const dtypep = nodep->dtypep();
if (num.isNull()) {
puts("VlNull{}");
putns(nodep, "VlNull{}");
} else if (num.isString()) {
// Note: putsQuoted does not track indentation, so we use this instead
puts("\"");
putns(nodep, "\"");
puts(num.toString());
puts("\"");
} else if (dtypep->isWide()) {
const uint32_t size = dtypep->widthWords();
// Note the double {{ initializer. The first { starts the initializer of the VlWide,
// and the second starts the initializer of m_storage within the VlWide.
puts("{");
putns(nodep, "{");
ofp()->putsNoTracking("{");
if (m_inUnpacked) puts(" // VlWide " + cvtToStr(m_unpackedWord));
puts("\n");
@ -129,11 +129,13 @@ protected:
= !m_inUnpacked && (static_cast<int>(dnum) == dnum && -1000 < dnum && dnum < 1000)
? "%3.1f" // Force decimal point
: "%.17e"; // %e always yields a float literal
putns(nodep, "");
ofp()->printf(fmt, dnum);
} else if (dtypep->isQuad()) {
const uint64_t qnum = static_cast<uint64_t>(num.toUQuad());
const char* const fmt
= !m_inUnpacked && (qnum < 10) ? ("%" PRIx64 "ULL") : ("0x%016" PRIx64 "ULL");
putns(nodep, "");
ofp()->printf(fmt, qnum);
} else {
const uint32_t unum = num.toUInt();
@ -141,6 +143,7 @@ protected:
: (dtypep->widthMin() > 16) ? ("0x%08" PRIx32 "U")
: (dtypep->widthMin() > 8) ? ("0x%04" PRIx32 "U")
: ("0x%02" PRIx32 "U");
putns(nodep, "");
ofp()->printf(fmt, unum);
}
}

View File

@ -66,7 +66,7 @@ class EmitCConstPool final : public EmitCConstInit {
void emitVars(const AstConstPool* poolp) {
std::vector<const AstVar*> varps;
for (AstNode* nodep = poolp->modp()->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) { varps.push_back(varp); }
if (const AstVar* const varp = VN_CAST(nodep, Var)) varps.push_back(varp);
}
if (varps.empty()) return; // Constant pool is empty, so we are done
@ -81,11 +81,11 @@ class EmitCConstPool final : public EmitCConstInit {
maybeSplitCFile();
const string nameProtect = topClassName() + "__ConstPool__" + varp->nameProtect();
puts("\n");
puts("extern const ");
puts(varp->dtypep()->cType(nameProtect, false, false));
puts(" = ");
putns(varp, "extern const ");
putns(varp, varp->dtypep()->cType(nameProtect, false, false));
putns(varp, " = ");
iterateConst(varp->valuep());
puts(";\n");
putns(varp, ";\n");
// Keep track of stats
if (VN_IS(varp->dtypep(), UnpackArrayDType)) {
++m_tablesEmitted;

View File

@ -64,7 +64,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
} \
} while (false)
putbs("");
putnbs(nodep, "");
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
if (pos[0] == ',') {
// Remember we need to add one, but don't do yet to avoid ",)"
@ -106,7 +106,8 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
"Wide Op w/ no temp, perhaps missing op in V3EmitC?");
COMMA;
if (!m_wideTempRefp->selfPointer().isEmpty()) {
emitDereference(m_wideTempRefp->selfPointerProtect(m_useSelfForThis));
emitDereference(m_wideTempRefp,
m_wideTempRefp->selfPointerProtect(m_useSelfForThis));
}
puts(m_wideTempRefp->varp()->nameProtect());
m_wideTempRefp = nullptr;
@ -170,13 +171,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
bool isStmt = false;
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
isStmt = false;
puts("VL_FSCANF_IX(");
putns(nodep, "VL_FSCANF_IX(");
iterateConst(dispp->filep());
puts(",");
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
isStmt = false;
checkMaxWords(dispp->fromp());
puts("VL_SSCANF_I");
putns(nodep, "VL_SSCANF_I");
emitIQW(dispp->fromp());
puts("X(");
puts(cvtToStr(dispp->fromp()->widthMin()));
@ -186,11 +187,11 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
isStmt = true;
if (dispp->filep()) {
puts("VL_FWRITEF(");
putns(nodep, "VL_FWRITEF(");
iterateConst(dispp->filep());
puts(",");
} else {
puts("VL_WRITEF(");
putns(nodep, "VL_WRITEF(");
}
} else if (const AstSFormat* const dispp = VN_CAST(nodep, SFormat)) {
isStmt = true;
@ -201,7 +202,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
putbs(",");
} else if (VN_IS(nodep, SFormatF)) {
isStmt = false;
puts("VL_SFORMATF_NX(");
putns(nodep, "VL_SFORMATF_NX(");
} else {
nodep->v3fatalSrc("Unknown displayEmit node type");
}
@ -409,7 +410,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer,
bool inProcess) {
puts("(");
putns(nodep, "(");
bool comma = false;
if (nodep->funcp()->isLoose() && !nodep->funcp()->isStatic()) {
UASSERT_OBJ(!selfPointer.empty(), nodep, "Call to loose method without self pointer");
@ -436,29 +437,29 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint
puts(")");
}
void EmitCFunc::emitDereference(const string& pointer) {
void EmitCFunc::emitDereference(AstNode* nodep, const string& pointer) {
if (pointer[0] == '(' && pointer[1] == '&') {
// remove "address of" followed by immediate dereference
// Note: this relies on only the form '(&OBJECT)' being used by Verilator
puts(pointer.substr(2, pointer.length() - 3));
putns(nodep, pointer.substr(2, pointer.length() - 3));
puts(".");
} else {
puts(pointer);
putns(nodep, pointer);
puts("->");
}
}
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
putbs("std::string{");
putnbs(nodep, "std::string{");
putsQuoted(constp->num().toString());
puts("}");
} else if (VN_IS(nodep->dtypep(), StreamDType)) {
putbs("VL_CVT_PACK_STR_ND(");
putnbs(nodep, "VL_CVT_PACK_STR_ND(");
iterateAndNextConstNull(nodep);
puts(")");
} else {
putbs("VL_CVT_PACK_STR_N");
putnbs(nodep, "VL_CVT_PACK_STR_N");
emitIQW(nodep);
puts("(");
if (nodep->isWide()) {
@ -472,7 +473,7 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
}
void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
putbs("VL_CVT_W_A(");
putnbs(nodep, "VL_CVT_W_A(");
iterateConst(nodep);
puts(", ");
iterateConst(fromp);
@ -482,12 +483,13 @@ void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string
putns(nodep, "");
if (nodep->num().isNull()) {
puts("VlNull{}");
putns(nodep, "VlNull{}");
} else if (nodep->num().isFourState()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
} else if (nodep->num().isString()) {
putbs("std::string{");
putnbs(nodep, "std::string{");
putsQuoted(nodep->num().toString());
puts("}");
} else if (nodep->isWide()) {
@ -501,14 +503,14 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
}
{ // Upper e.g. 8 words
if (chunks) {
putbs("VL_CONSTHI_W_");
putnbs(nodep, "VL_CONSTHI_W_");
puts(cvtToStr(VL_WORDS_I(upWidth)));
puts("X(");
puts(cvtToStr(nodep->widthMin()));
puts(",");
puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE));
} else {
putbs("VL_CONST_W_");
putnbs(nodep, "VL_CONST_W_");
puts(cvtToStr(VL_WORDS_I(upWidth)));
puts("X(");
puts(cvtToStr(nodep->widthMin()));
@ -518,7 +520,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(assignString);
} else {
if (!assigntop->selfPointer().isEmpty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
}
@ -540,7 +542,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(assignString);
} else {
if (!assigntop->selfPointer().isEmpty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
}
@ -648,7 +650,7 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
varp->v3fatalSrc("InitArray under non-arrayed var");
}
} else {
puts(emitVarResetRecurse(varp, varNameProtected, dtypep, 0, ""));
putns(varp, emitVarResetRecurse(varp, varNameProtected, dtypep, 0, ""));
}
}

View File

@ -65,7 +65,7 @@ class EmitCLazyDecls final : public VNVisitorConst {
if (!declaredOnce(varp)) return; // Already declared
const string nameProtect
= m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect();
m_emitter.puts("extern const ");
m_emitter.putns(varp, "extern const ");
m_emitter.puts(varp->dtypep()->cType(nameProtect, false, false));
m_emitter.puts(";\n");
m_needsBlankLine = true;
@ -205,7 +205,7 @@ public:
void emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp,
AstNode* thsp);
void emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer, bool inProcess);
void emitDereference(const string& pointer);
void emitDereference(AstNode* nodep, const string& pointer);
void emitCvtPackStr(AstNode* nodep);
void emitCvtWideArray(AstNode* nodep, AstNode* fromp);
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString);
@ -290,8 +290,8 @@ public:
puts("\n");
m_lazyDecls.emit(nodep);
if (nodep->ifdef() != "") puts("#ifdef " + nodep->ifdef() + "\n");
if (nodep->isInline()) puts("VL_INLINE_OPT ");
if (nodep->ifdef() != "") putns(nodep, "#ifdef " + nodep->ifdef() + "\n");
if (nodep->isInline()) putns(nodep, "VL_INLINE_OPT ");
emitCFuncHeader(nodep, m_modp, /* withScope: */ true);
if (nodep->isConstructor()) {
@ -344,17 +344,17 @@ public:
}
if (nodep->initsp()) {
putsDecoration("// Init\n");
putsDecoration(nodep, "// Init\n");
iterateAndNextConstNull(nodep->initsp());
}
if (nodep->stmtsp()) {
putsDecoration("// Body\n");
putsDecoration(nodep, "// Body\n");
iterateAndNextConstNull(nodep->stmtsp());
}
if (nodep->finalsp()) {
putsDecoration("// Final\n");
putsDecoration(nodep, "// Final\n");
iterateAndNextConstNull(nodep->finalsp());
}
@ -368,15 +368,15 @@ public:
}
void visit(AstCvtDynArrayToPacked* nodep) override {
puts("VL_DYN_TO_");
putns(nodep, "VL_DYN_TO_");
emitIQW(nodep);
puts("<");
const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep();
putns(elemDTypep, "<");
putbs(elemDTypep->cType("", false, false));
puts(">(");
iterateAndNextConstNull(nodep->fromp());
puts(", ");
puts(cvtToStr(elemDTypep->widthMin()));
putns(elemDTypep, cvtToStr(elemDTypep->widthMin()));
puts(")");
}
@ -386,7 +386,7 @@ public:
bool rhs = true;
if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) {
if (selp->widthMin() == 1) {
putbs("VL_ASSIGNBIT_");
putnbs(nodep, "VL_ASSIGNBIT_");
emitIQW(selp->fromp());
if (nodep->rhsp()->isAllOnesV()) {
puts("O(");
@ -399,11 +399,11 @@ public:
iterateAndNextConstNull(selp->fromp());
if (rhs) puts(", ");
} else {
putbs("VL_ASSIGNSEL_");
putnbs(nodep, "VL_ASSIGNSEL_");
emitIQW(selp->fromp());
emitIQW(nodep->rhsp());
puts("(");
puts(cvtToStr(selp->fromp()->widthMin()) + ",");
putns(selp->fromp(), cvtToStr(selp->fromp()->widthMin()) + ",");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextConstNull(selp->lsbp());
puts(", ");
@ -413,13 +413,13 @@ public:
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
iterateAndNextConstNull(selp->lhsp());
puts(" = ");
putbs("VL_PUTC_N(");
putnbs(selp, "VL_PUTC_N(");
iterateAndNextConstNull(selp->lhsp());
puts(", ");
iterateAndNextConstNull(selp->rhsp());
puts(", ");
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
putbs("VL_ASSIGN_"); // Set a systemC variable
putnbs(varp, "VL_ASSIGN_"); // Set a systemC variable
emitScIQW(varp);
emitIQW(nodep);
puts("(");
@ -427,7 +427,7 @@ public:
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
putbs("VL_ASSIGN_"); // Get a systemC variable
putnbs(varp, "VL_ASSIGN_"); // Get a systemC variable
emitIQW(nodep);
emitScIQW(varp);
puts("(");
@ -436,12 +436,12 @@ public:
puts(", ");
} else if (const AstCvtPackedToDynArray* const castp
= VN_CAST(nodep->rhsp(), CvtPackedToDynArray)) {
puts("VL_ASSIGN_DYN_Q<");
putns(castp, "VL_ASSIGN_DYN_Q<");
putbs(castp->dtypep()->subDTypep()->cType("", false, false));
puts(">(");
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
puts(cvtToStr(castp->dtypep()->subDTypep()->widthMin()));
putns(castp->dtypep(), cvtToStr(castp->dtypep()->subDTypep()->widthMin()));
puts(", ");
puts(cvtToStr(castp->fromp()->widthMin()));
puts(", ");
@ -460,7 +460,7 @@ public:
m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef);
paren = false;
} else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
putbs("VL_ASSIGN_W(");
putnbs(nodep, "VL_ASSIGN_W(");
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
@ -471,7 +471,7 @@ public:
ofp()->blockInc();
decind = true;
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
puts("= ");
putns(nodep, "= ");
}
if (rhs) iterateAndNextConstNull(nodep->rhsp());
if (paren) puts(")");
@ -481,7 +481,7 @@ public:
void visit(AstAlwaysPublic*) override {}
void visit(AstAssocSel* nodep) override {
iterateAndNextConstNull(nodep->fromp());
putbs(".at(");
putnbs(nodep, ".at(");
AstAssocArrayDType* const adtypep
= VN_AS(nodep->fromp()->dtypep()->skipRefp(), AssocArrayDType);
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
@ -490,7 +490,7 @@ public:
}
void visit(AstWildcardSel* nodep) override {
iterateAndNextConstNull(nodep->fromp());
putbs(".at(");
putnbs(nodep, ".at(");
AstWildcardArrayDType* const adtypep
= VN_AS(nodep->fromp()->dtypep()->skipRefp(), WildcardArrayDType);
UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type");
@ -500,26 +500,27 @@ public:
void visit(AstCCall* nodep) override {
const AstCFunc* const funcp = nodep->funcp();
const AstNodeModule* const funcModp = EmitCParentModule::get(funcp);
putnbs(nodep, "");
if (funcp->dpiImportPrototype()) {
// Calling DPI import
puts(funcp->name());
putns(nodep, funcp->name());
} else if (funcp->isProperMethod() && funcp->isStatic()) {
// Call static method via the containing class
puts(prefixNameProtect(funcModp) + "::");
puts(funcp->nameProtect());
putns(funcModp, prefixNameProtect(funcModp) + "::");
putns(nodep, funcp->nameProtect());
} else if (nodep->superReference()) {
// Calling superclass method
puts(prefixNameProtect(funcModp) + "::");
puts(funcp->nameProtect());
putns(funcModp, prefixNameProtect(funcModp) + "::");
putns(nodep, funcp->nameProtect());
} else if (funcp->isLoose()) {
// Calling loose method
puts(funcNameProtect(funcp));
putns(nodep, funcNameProtect(funcp));
} else {
// Calling regular method/function
if (!nodep->selfPointer().isEmpty()) {
emitDereference(nodep->selfPointerProtect(m_useSelfForThis));
emitDereference(nodep, nodep->selfPointerProtect(m_useSelfForThis));
}
puts(funcp->nameProtect());
putns(nodep, funcp->nameProtect());
}
emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis), m_cfuncp->needProcess());
}
@ -527,12 +528,12 @@ public:
const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall");
iterateConst(nodep->fromp());
putbs("->");
puts(funcp->nameProtect());
putnbs(nodep, "->");
putns(funcp, funcp->nameProtect());
emitCCallArgs(nodep, "", m_cfuncp->needProcess());
}
void visit(AstCAwait* nodep) override {
puts("co_await ");
putns(nodep, "co_await ");
iterateConst(nodep->exprp());
}
void visit(AstCNew* nodep) override {
@ -541,15 +542,15 @@ public:
return;
}
// assignment case;
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "
+ optionalProcArg(nodep->dtypep()) + "vlSymsp");
putns(nodep, "VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "
+ optionalProcArg(nodep->dtypep()) + "vlSymsp");
putCommaIterateNext(nodep->argsp(), true);
puts(")");
}
void visit(AstCMethodHard* nodep) override {
iterateConst(nodep->fromp());
puts(".");
puts(nodep->name());
putns(nodep, ".");
putns(nodep, nodep->name());
puts("(");
bool comma = false;
for (AstNode* subnodep = nodep->pinsp(); subnodep; subnodep = subnodep->nextp()) {
@ -567,13 +568,13 @@ public:
void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
void visit(AstWith* nodep) override {
// With uses a C++11 lambda
putbs("[&](");
putnbs(nodep, "[&](");
if (auto* const argrefp = nodep->indexArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
putnbs(argrefp, argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
puts(",");
}
if (auto* const argrefp = nodep->valueArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
putnbs(argrefp, argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
}
puts(") {\n");
iterateAndNextConstNull(nodep->exprp());
@ -591,12 +592,12 @@ public:
if (!v3Global.opt.protectIds()) return;
}
if (!(nodep->protect() && v3Global.opt.protectIds())) {
putsDecoration(string{"// "} + nodep->name() + at + "\n");
putsDecoration(nodep, string{"// "} + nodep->name() + at + "\n");
}
iterateChildrenConst(nodep);
}
void visit(AstCoverDecl* nodep) override {
puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
putns(nodep, "vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
puts("&(vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->dataDeclThisp()->binNum()));
puts("])");
@ -625,18 +626,18 @@ public:
}
void visit(AstCoverInc* nodep) override {
if (v3Global.opt.threads() > 1) {
puts("vlSymsp->__Vcoverage[");
putns(nodep, "vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
puts("].fetch_add(1, std::memory_order_relaxed);\n");
} else {
puts("++(vlSymsp->__Vcoverage[");
putns(nodep, "++(vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
puts("]);\n");
}
}
void visit(AstDisableFork* nodep) override { puts("vlProcess->disableFork();\n"); }
void visit(AstDisableFork* nodep) override { putns(nodep, "vlProcess->disableFork();\n"); }
void visit(AstCReturn* nodep) override {
puts("return (");
putns(nodep, "return (");
iterateAndNextConstNull(nodep->lhsp());
puts(");\n");
}
@ -648,16 +649,16 @@ public:
void visit(AstDumpCtl* nodep) override {
switch (nodep->ctlType()) {
case VDumpCtlType::FILE:
puts("vlSymsp->_vm_contextp__->dumpfile(");
putns(nodep, "vlSymsp->_vm_contextp__->dumpfile(");
emitCvtPackStr(nodep->exprp());
puts(");\n");
break;
case VDumpCtlType::VARS:
// We ignore number of levels to dump in exprp()
if (v3Global.opt.trace()) {
puts("vlSymsp->_traceDumpOpen();\n");
putns(nodep, "vlSymsp->_traceDumpOpen();\n");
} else {
puts("VL_PRINTF_MT(\"-Info: ");
putns(nodep, "VL_PRINTF_MT(\"-Info: ");
puts(V3OutFormatter::quoteNameControls(protect(nodep->fileline()->filename())));
puts(":");
puts(cvtToStr(nodep->fileline()->lineno()));
@ -690,7 +691,7 @@ public:
if (!nodep->dpiExport()) {
// this is where the DPI import context scope is set
const string scope = nodep->scopeDpiName();
putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))");
putnbs(nodep, "(&(vlSymsp->" + protect("__Vscope_" + scope) + "))");
}
}
void visit(AstSFormat* nodep) override {
@ -707,7 +708,7 @@ public:
displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true);
}
void visit(AstValuePlusArgs* nodep) override {
puts("VL_VALUEPLUSARGS_IN");
putns(nodep, "VL_VALUEPLUSARGS_IN");
emitIQW(nodep->outp());
puts("(");
puts(cvtToStr(nodep->outp()->widthMin()));
@ -719,12 +720,12 @@ public:
puts(")");
}
void visit(AstTestPlusArgs* nodep) override {
puts("VL_TESTPLUSARGS_I(");
putns(nodep, "VL_TESTPLUSARGS_I(");
emitCvtPackStr(nodep->searchp());
puts(")");
}
void visit(AstFError* nodep) override {
puts("VL_FERROR_I");
putns(nodep, "VL_FERROR_I");
puts(nodep->strp()->isString() ? "N(" : "W(");
iterateAndNextConstNull(nodep->filep());
putbs(", ");
@ -749,7 +750,7 @@ public:
}
}
void visit(AstFOpen* nodep) override {
puts("VL_FOPEN_NN(");
putns(nodep, "VL_FOPEN_NN(");
emitCvtPackStr(nodep->filenamep());
putbs(", ");
if (nodep->modep()->width() > 4 * 8)
@ -758,12 +759,12 @@ public:
puts(");\n");
}
void visit(AstFOpenMcd* nodep) override {
puts("VL_FOPEN_MCD_N(");
putns(nodep, "VL_FOPEN_MCD_N(");
emitCvtPackStr(nodep->filenamep());
puts(");\n");
}
void visit(AstNodeReadWriteMem* nodep) override {
puts(nodep->cFuncPrefixp());
putns(nodep, nodep->cFuncPrefixp());
puts("N(");
puts(nodep->isHex() ? "true" : "false");
putbs(", ");
@ -812,23 +813,24 @@ public:
puts(");\n");
}
void visit(AstFClose* nodep) override {
puts("VL_FCLOSE_I(");
putns(nodep, "VL_FCLOSE_I(");
iterateAndNextConstNull(nodep->filep());
puts("); ");
}
void visit(AstFFlush* nodep) override {
if (!nodep->filep()) {
puts("Verilated::runFlushCallbacks();\n");
putns(nodep, "Verilated::runFlushCallbacks();\n");
} else {
puts("if (");
putns(nodep, "if (");
iterateAndNextConstNull(nodep->filep());
puts(") { VL_FFLUSH_I(");
puts(") { ");
putns(nodep, "VL_FFLUSH_I(");
iterateAndNextConstNull(nodep->filep());
puts("); }\n");
}
}
void visit(AstFSeek* nodep) override {
puts("(VL_FSEEK_I(");
putns(nodep, "(VL_FSEEK_I(");
iterateAndNextConstNull(nodep->filep());
puts(",");
iterateAndNextConstNull(nodep->offset());
@ -837,17 +839,17 @@ public:
puts(") == -1 ? -1 : 0)");
}
void visit(AstFTell* nodep) override {
puts("VL_FTELL_I(");
putns(nodep, "VL_FTELL_I(");
iterateAndNextConstNull(nodep->filep());
puts(")");
}
void visit(AstFRewind* nodep) override {
puts("(VL_FSEEK_I(");
putns(nodep, "(VL_FSEEK_I(");
iterateAndNextConstNull(nodep->filep());
puts(", 0, 0) == -1 ? -1 : 0)");
}
void visit(AstFRead* nodep) override {
puts("VL_FREAD_I(");
putns(nodep, "VL_FREAD_I(");
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width
putbs(",");
uint32_t array_lo = 0;
@ -890,14 +892,14 @@ public:
puts(")");
}
void visit(AstSysFuncAsTask* nodep) override {
if (!nodep->lhsp()->isWide()) puts("(void)");
if (!nodep->lhsp()->isWide()) putns(nodep, "(void)");
iterateAndNextConstNull(nodep->lhsp());
if (!nodep->lhsp()->isWide()) puts(";\n");
if (!nodep->lhsp()->isWide()) putns(nodep, ";\n");
}
void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); }
void visit(AstStackTraceT* nodep) override { puts("VL_STACKTRACE();\n"); }
void visit(AstStackTraceF* nodep) override { putns(nodep, "VL_STACKTRACE_N()"); }
void visit(AstStackTraceT* nodep) override { putns(nodep, "VL_STACKTRACE();\n"); }
void visit(AstSystemT* nodep) override {
puts("(void)VL_SYSTEM_I");
putns(nodep, "(void)VL_SYSTEM_I");
emitIQW(nodep->lhsp());
puts("(");
if (nodep->lhsp()->isWide()) {
@ -909,7 +911,7 @@ public:
puts(");\n");
}
void visit(AstSystemF* nodep) override {
puts("VL_SYSTEM_I");
putns(nodep, "VL_SYSTEM_I");
emitIQW(nodep->lhsp());
puts("(");
if (nodep->lhsp()->isWide()) {
@ -920,31 +922,32 @@ public:
iterateAndNextConstNull(nodep->lhsp());
puts(")");
}
void visit(AstStmtExpr* node) override {
iterateConst(node->exprp());
void visit(AstStmtExpr* nodep) override {
putns(nodep, "");
iterateConst(nodep->exprp());
puts(";\n");
}
void visit(AstJumpBlock* nodep) override {
nodep->labelNum(++m_labelNum);
puts("{\n"); // Make it visually obvious label jumps outside these
putns(nodep, "{\n"); // Make it visually obvious label jumps outside these
iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->endStmtsp());
puts("}\n");
}
void visit(AstCLocalScope* nodep) override {
puts("{\n");
putns(nodep, "{\n");
iterateAndNextConstNull(nodep->stmtsp());
puts("}\n");
}
void visit(AstJumpGo* nodep) override {
puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
putns(nodep, "goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
}
void visit(AstJumpLabel* nodep) override {
puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
putns(nodep, "__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
}
void visit(AstWhile* nodep) override {
iterateAndNextConstNull(nodep->precondsp());
puts("while (");
putns(nodep, "while (");
iterateAndNextConstNull(nodep->condp());
puts(") {\n");
iterateAndNextConstNull(nodep->stmtsp());
@ -953,7 +956,7 @@ public:
puts("}\n");
}
void visit(AstNodeIf* nodep) override {
puts("if (");
putns(nodep, "if (");
if (!nodep->branchPred().unknown()) {
puts(nodep->branchPred().ascii());
puts("(");
@ -979,14 +982,14 @@ public:
void visit(AstExprStmt* nodep) override {
// GCC allows compound statements in expressions, but this is not standard.
// So we use an immediate-evaluation lambda and comma operator
putbs("([&]() {\n");
putnbs(nodep, "([&]() {\n");
iterateAndNextConstNull(nodep->stmtsp());
puts("}(), ");
iterateAndNextConstNull(nodep->resultp());
puts(")");
}
void visit(AstStop* nodep) override {
puts("VL_STOP_MT(");
putns(nodep, "VL_STOP_MT(");
putsQuoted(protect(nodep->fileline()->filename()));
puts(", ");
puts(cvtToStr(nodep->fileline()->lineno()));
@ -994,14 +997,14 @@ public:
puts(");\n");
}
void visit(AstFinish* nodep) override {
puts("VL_FINISH_MT(");
putns(nodep, "VL_FINISH_MT(");
putsQuoted(protect(nodep->fileline()->filename()));
puts(", ");
puts(cvtToStr(nodep->fileline()->lineno()));
puts(", \"\");\n");
}
void visit(AstPrintTimeScale* nodep) override {
puts("VL_PRINTTIMESCALE(");
putns(nodep, "VL_PRINTTIMESCALE(");
putsQuoted(protect(nodep->prettyName()));
puts(", ");
putsQuoted(nodep->timeunit().ascii());
@ -1014,21 +1017,21 @@ public:
emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr);
}
void visit(AstTime* nodep) override {
puts("VL_TIME_UNITED_Q(");
putns(nodep, "VL_TIME_UNITED_Q(");
UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time has no units");
puts(cvtToStr(nodep->timeunit().multiplier()
/ v3Global.rootp()->timeprecision().multiplier()));
puts(")");
}
void visit(AstTimeD* nodep) override {
puts("VL_TIME_UNITED_D(");
putns(nodep, "VL_TIME_UNITED_D(");
UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$realtime has no units");
puts(cvtToStr(nodep->timeunit().multiplier()
/ v3Global.rootp()->timeprecision().multiplier()));
puts(")");
}
void visit(AstTimeFormat* nodep) override {
puts("VL_TIMEFORMAT_IINI(");
putns(nodep, "VL_TIMEFORMAT_IINI(");
iterateAndNextConstNull(nodep->unitsp());
puts(", ");
iterateAndNextConstNull(nodep->precisionp());
@ -1039,7 +1042,7 @@ public:
puts(", vlSymsp->_vm_contextp__);\n");
}
void visit(AstTimePrecision* nodep) override {
puts("vlSymsp->_vm_contextp__->timeprecision()");
putns(nodep, "vlSymsp->_vm_contextp__->timeprecision()");
}
void visit(AstNodeSimpleText* nodep) override {
const string text = m_inUC && m_useSelfForThis
@ -1059,17 +1062,19 @@ public:
}
}
void visit(AstCStmt* nodep) override {
putbs("");
putnbs(nodep, "");
iterateAndNextConstNull(nodep->exprsp());
}
void visit(AstCExpr* nodep) override {
putbs("");
putnbs(nodep, "");
iterateAndNextConstNull(nodep->exprsp());
}
void visit(AstUCStmt* nodep) override {
VL_RESTORER(m_inUC);
m_inUC = true;
putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
putnbs(nodep, "");
putsDecoration(nodep,
ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextConstNull(nodep->exprsp());
puts("\n");
}
@ -1077,7 +1082,9 @@ public:
VL_RESTORER(m_inUC);
m_inUC = true;
puts("\n");
putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
putnbs(nodep, "");
putsDecoration(nodep,
ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n"));
iterateAndNextConstNull(nodep->exprsp());
puts("\n");
}
@ -1097,7 +1104,7 @@ public:
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
if (emitSimpleOk(nodep)) {
putbs("(");
putnbs(nodep, "(");
puts(nodep->emitSimpleOperator());
puts(" ");
iterateAndNextConstNull(nodep->lhsp());
@ -1115,7 +1122,7 @@ public:
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
if (emitSimpleOk(nodep)) {
putbs("(");
putnbs(nodep, "(");
iterateAndNextConstNull(nodep->lhsp());
puts(" ");
putbs(nodep->emitSimpleOperator());
@ -1140,7 +1147,7 @@ public:
: nodep->lhsp()->dtypep()->widthPow2();
UASSERT_OBJ(widthPow2 > 1, nodep,
"Reduction over single bit value should have been folded");
putbs("VL_REDXOR_");
putnbs(nodep, "VL_REDXOR_");
puts(cvtToStr(widthPow2));
puts("(");
iterateAndNextConstNull(nodep->lhsp());
@ -1150,15 +1157,15 @@ public:
void visit(AstCCast* nodep) override {
// Extending a value of the same word width is just a NOP.
if (const AstClassRefDType* const classDtypep = VN_CAST(nodep->dtypep(), ClassRefDType)) {
puts("(" + classDtypep->cType("", false, false) + ")(");
putns(nodep, "(" + classDtypep->cType("", false, false) + ")(");
} else if (nodep->size() <= VL_BYTESIZE) {
puts("(CData)(");
putns(nodep, "(CData)(");
} else if (nodep->size() <= VL_SHORTSIZE) {
puts("(SData)(");
putns(nodep, "(SData)(");
} else if (nodep->size() <= VL_IDATASIZE) {
puts("(IData)(");
putns(nodep, "(IData)(");
} else {
puts("(QData)(");
putns(nodep, "(QData)(");
}
iterateAndNextConstNull(nodep->lhsp());
puts(")");
@ -1168,7 +1175,7 @@ public:
if (nodep->thenp()->isWide()) {
emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep());
} else {
putbs("(");
putnbs(nodep, "(");
iterateAndNextConstNull(nodep->condp());
putbs(" ? ");
iterateAndNextConstNull(nodep->thenp());
@ -1179,16 +1186,16 @@ public:
}
void visit(AstMemberSel* nodep) override {
iterateAndNextConstNull(nodep->fromp());
putbs("->");
putnbs(nodep, "->");
puts(nodep->varp()->nameProtect());
}
void visit(AstStructSel* nodep) override {
iterateAndNextConstNull(nodep->fromp());
putbs(".");
putnbs(nodep, ".");
puts(nodep->nameProtect());
}
void visit(AstNullCheck* nodep) override {
puts("VL_NULL_CHECK(");
putns(nodep, "VL_NULL_CHECK(");
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
putsQuoted(protect(nodep->fileline()->filename()));
@ -1197,8 +1204,8 @@ public:
puts(")");
}
void visit(AstNewCopy* nodep) override {
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "
+ optionalProcArg(nodep->dtypep()));
putns(nodep, "VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "
+ optionalProcArg(nodep->dtypep()));
puts("*"); // i.e. make into a reference
iterateAndNextConstNull(nodep->rhsp());
puts(")");
@ -1213,7 +1220,7 @@ public:
* nodep->srcp()->widthMin())
== nodep->widthMin(),
nodep, "Replicate non-constant or width miscomputed");
puts("VL_REPLICATE_");
putns(nodep, "VL_REPLICATE_");
emitIQW(nodep);
puts("OI(");
if (nodep->srcp()) puts(cvtToStr(nodep->srcp()->widthMin()));
@ -1232,7 +1239,7 @@ public:
const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1;
const uint32_t sliceSize = VN_AS(nodep->rhsp(), Const)->toUInt();
if (isPow2 && sliceSize <= (nodep->isQuad() ? sizeof(uint64_t) : sizeof(uint32_t))) {
puts("VL_STREAML_FAST_");
putns(nodep, "VL_STREAML_FAST_");
emitIQW(nodep);
emitIQW(nodep->lhsp());
puts("I(");
@ -1249,14 +1256,14 @@ public:
nullptr);
}
void visit(AstCastDynamic* nodep) override {
putbs("VL_CAST_DYNAMIC(");
putnbs(nodep, "VL_CAST_DYNAMIC(");
iterateAndNextConstNull(nodep->fromp());
puts(", ");
iterateAndNextConstNull(nodep->top());
puts(")");
}
void visit(AstCountBits* nodep) override {
putbs("VL_COUNTBITS_");
putnbs(nodep, "VL_COUNTBITS_");
emitIQW(nodep->lhsp());
puts("(");
puts(cvtToStr(nodep->lhsp()->widthMin()));
@ -1282,26 +1289,26 @@ public:
const AstNodeModule* const varModp = EmitCParentModule::get(varp);
if (isConstPoolMod(varModp)) {
// Reference to constant pool variable
puts(topClassName() + "__ConstPool__");
putns(nodep, topClassName() + "__ConstPool__");
} else if (varp->isStatic()) {
// Access static variable via the containing class
puts(prefixNameProtect(varModp) + "::");
putns(nodep, prefixNameProtect(varModp) + "::");
} else if (VN_IS(varModp, Class) && varModp != m_modp) {
// Superclass member reference
puts(prefixNameProtect(varModp) + "::");
putns(nodep, prefixNameProtect(varModp) + "::");
} else if (varp->isIfaceRef()) {
puts(nodep->selfPointerProtect(m_useSelfForThis));
putns(nodep, nodep->selfPointerProtect(m_useSelfForThis));
return;
} else if (!nodep->selfPointer().isEmpty()) {
emitDereference(nodep->selfPointerProtect(m_useSelfForThis));
emitDereference(nodep, nodep->selfPointerProtect(m_useSelfForThis));
}
puts(nodep->varp()->nameProtect());
putns(nodep, nodep->varp()->nameProtect());
}
void visit(AstAddrOfCFunc* nodep) override {
// Note: Can be thought to handle more, but this is all that is needed right now
const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method");
puts("&");
putns(nodep, "&");
puts(funcNameProtect(funcp));
}
void visit(AstConst* nodep) override {
@ -1316,7 +1323,7 @@ public:
}
}
void visit(AstThisRef* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
puts("{");
puts(m_useSelfForThis ? "vlSelf" : "this");
puts("}");
@ -1329,7 +1336,7 @@ public:
iterateChildrenConst(nodep);
}
void visit(AstConsAssoc* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
@ -1339,7 +1346,7 @@ public:
}
void visit(AstSetAssoc* nodep) override {
iterateAndNextConstNull(nodep->lhsp());
putbs(".set(");
putnbs(nodep, ".set(");
iterateAndNextConstNull(nodep->keyp());
puts(", ");
putbs("");
@ -1347,7 +1354,7 @@ public:
puts(")");
}
void visit(AstConsWildcard* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
@ -1357,7 +1364,7 @@ public:
}
void visit(AstSetWildcard* nodep) override {
iterateAndNextConstNull(nodep->lhsp());
putbs(".set(");
putnbs(nodep, ".set(");
iterateAndNextConstNull(nodep->keyp());
puts(", ");
putbs("");
@ -1365,11 +1372,11 @@ public:
puts(")");
}
void visit(AstConsDynArray* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
putns(nodep, "()");
} else {
puts("::cons(");
putns(nodep, "::cons(");
iterateAndNextConstNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
@ -1380,23 +1387,23 @@ public:
}
}
void visit(AstConsPackUOrStruct* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
puts("{");
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
iterateConst(memberp);
if (memberp->nextp()) { puts(", "); }
if (memberp->nextp()) puts(", ");
}
puts("}");
}
void visit(AstConsPackMember* nodep) override {
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
putbs(".");
putnbs(nodep, ".");
puts(vdtypep->name());
puts(" = ");
iterateConst(nodep->rhsp());
}
void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
putnbs(nodep, nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
@ -1423,7 +1430,7 @@ public:
// Default
void visit(AstNode* nodep) override {
puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n");
putns(nodep, string{"\n???? // "} + nodep->prettyTypeName() + "\n");
iterateChildrenConst(nodep);
// LCOV_EXCL_START
if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress

View File

@ -35,7 +35,7 @@ class EmitCHeader final : public EmitCConstInit {
void decorateFirst(bool& first, const string& str) {
if (first) {
putsDecoration(str);
putsDecoration(nullptr, str);
first = false;
}
}
@ -44,7 +44,8 @@ class EmitCHeader final : public EmitCConstInit {
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
decorateFirst(first, "// CELLS\n");
puts(prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n");
putns(cellp,
prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n");
}
}
}
@ -120,11 +121,11 @@ class EmitCHeader final : public EmitCConstInit {
void emitInternalVarDecls(const AstNodeModule* modp) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
if (classp->needRNG()) {
putsDecoration("\n// INTERNAL VARIABLES\n");
putsDecoration(nullptr, "\n// INTERNAL VARIABLES\n");
puts("VlRNG __Vm_rng;\n");
}
} else { // not class
putsDecoration("\n// INTERNAL VARIABLES\n");
putsDecoration(nullptr, "\n// INTERNAL VARIABLES\n");
puts(symClassName() + "* const vlSymsp;\n");
}
}
@ -137,7 +138,7 @@ class EmitCHeader final : public EmitCConstInit {
UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?");
// Only C++ LiteralTypes can be constexpr
const bool canBeConstexpr = varp->dtypep()->isLiteralType();
puts("static ");
putns(varp, "static ");
puts(canBeConstexpr ? "constexpr " : "const ");
puts(varp->dtypep()->cType(varp->nameProtect(), false, false));
if (canBeConstexpr) {
@ -152,10 +153,10 @@ class EmitCHeader final : public EmitCConstInit {
void emitCtorDtorDecls(const AstNodeModule* modp) {
if (!VN_IS(modp, Class)) { // Classes use CFuncs with isConstructor/isDestructor
const string& name = prefixNameProtect(modp);
putsDecoration("\n// CONSTRUCTORS\n");
puts(name + "(" + symClassName() + "* symsp, const char* v__name);\n");
puts("~" + name + "();\n");
puts("VL_UNCOPYABLE(" + name + ");\n");
putsDecoration(nullptr, "\n// CONSTRUCTORS\n");
putns(modp, name + "(" + symClassName() + "* symsp, const char* v__name);\n");
putns(modp, "~" + name + "();\n");
putns(modp, "VL_UNCOPYABLE(" + name + ");\n");
}
}
void emitInternalMethodDecls(const AstNodeModule* modp) {
@ -193,18 +194,19 @@ class EmitCHeader final : public EmitCConstInit {
if (!edtypep) continue;
decorateFirst(first, "\n// ENUMS (that were declared public)\n");
if (edtypep->width() > 64) {
putsDecoration("// enum " + tdefp->nameProtect() + " ignored: Too wide for C++\n");
putsDecoration(tdefp,
"// enum " + tdefp->nameProtect() + " ignored: Too wide for C++\n");
} else {
puts("enum " + tdefp->name() + " {\n");
putns(tdefp, "enum " + tdefp->name() + " {\n");
for (const AstEnumItem* itemp = edtypep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), EnumItem)) {
if (const AstConst* const constp = VN_CAST(itemp->valuep(), Const)) {
if (constp->num().isFourState()) {
puts("// " + itemp->nameProtect() + " is four-state\n");
putns(itemp, "// " + itemp->nameProtect() + " is four-state\n");
continue;
}
}
puts(itemp->nameProtect());
putns(itemp, itemp->nameProtect());
puts(" = ");
iterateConst(itemp->valuep());
if (VN_IS(itemp->nextp(), EnumItem)) puts(",");
@ -229,26 +231,26 @@ class EmitCHeader final : public EmitCConstInit {
}
}
}
puts(sdtypep->verilogKwd()); // "struct"/"union"
putns(sdtypep, sdtypep->verilogKwd()); // "struct"/"union"
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false));
putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false));
puts(";\n");
}
puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
+ "& rhs) const {\n");
putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
+ "& rhs) const {\n");
puts("return ");
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
if (itemp != sdtypep->membersp()) puts("\n && ");
puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect());
putns(itemp, itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect());
}
puts(";\n");
puts("}\n");
puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep)
+ "& rhs) const {\n");
putns(sdtypep, "bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep)
+ "& rhs) const {\n");
puts("return !(*this == rhs);\n}\n");
puts("};\n");
}
@ -298,8 +300,8 @@ class EmitCHeader final : public EmitCConstInit {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
puts("#include \"" + prefixNameProtect(extp->classp()->classOrPackagep())
+ ".h\"\n");
putns(extp, "#include \"" + prefixNameProtect(extp->classp()->classOrPackagep())
+ ".h\"\n");
}
}
@ -312,7 +314,8 @@ class EmitCHeader final : public EmitCConstInit {
emitStructs(modp);
// Open class body {{{
puts("\nclass ");
puts("\n");
putns(modp, "class ");
if (!VN_IS(modp, Class)) puts("alignas(VL_CACHE_LINE_BYTES) ");
puts(prefixNameProtect(modp));
if (const AstClass* const classp = VN_CAST(modp, Class)) {
@ -321,7 +324,7 @@ class EmitCHeader final : public EmitCConstInit {
if (classp->extendsp()) {
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
puts(prefixNameProtect(extp->classp()));
putns(extp, prefixNameProtect(extp->classp()));
if (extp->nextp()) puts(", " + virtpub);
}
} else {

View File

@ -203,7 +203,7 @@ class EmitCImp final : EmitCFunc {
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isStatic()) {
puts(varp->vlArgType(true, false, false, modName));
putns(varp, varp->vlArgType(true, false, false, modName));
puts(";\n");
}
}
@ -217,15 +217,15 @@ class EmitCImp final : EmitCFunc {
if (varp->isParam()) {
if (first) {
puts("\n");
putsDecoration("// Parameter definitions for " + modName + "\n");
putsDecoration(modp, "// Parameter definitions for " + modName + "\n");
first = false;
}
UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?");
// Only C++ LiteralTypes can be constexpr
const bool canBeConstexpr = varp->dtypep()->isLiteralType();
puts(canBeConstexpr ? "constexpr " : "const ");
putns(varp, canBeConstexpr ? "constexpr " : "const ");
const string scopedName = modName + "::" + varp->nameProtect();
puts(varp->dtypep()->cType(scopedName, false, false));
putns(varp, varp->dtypep()->cType(scopedName, false, false));
if (!canBeConstexpr) {
puts(" = ");
emitConstInit(varp->valuep());
@ -244,7 +244,8 @@ class EmitCImp final : EmitCFunc {
"(" + modName + "* vlSelf);");
puts("\n");
puts(modName + "::" + modName + "(" + symClassName() + "* symsp, const char* v__name)\n");
putns(modp,
modName + "::" + modName + "(" + symClassName() + "* symsp, const char* v__name)\n");
puts(" : VerilatedModule{v__name}\n");
ofp()->indentInc();
@ -254,19 +255,19 @@ class EmitCImp final : EmitCFunc {
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
if (dtypep->keyword().isMTaskState()) {
puts(", ");
puts(varp->nameProtect());
putns(varp, varp->nameProtect());
puts("(");
iterateConst(varp->valuep());
puts(")\n");
} else if (varp->isIO() && varp->isSc()) {
puts(", ");
puts(varp->nameProtect());
putns(varp, varp->nameProtect());
puts("(");
putsQuoted(varp->nameProtect());
puts(")\n");
} else if (dtypep->isDelayScheduler()) {
puts(", ");
puts(varp->nameProtect());
putns(varp, varp->nameProtect());
puts("{*symsp->_vm_contextp__}\n");
}
}
@ -277,7 +278,7 @@ class EmitCImp final : EmitCFunc {
puts(" {\n");
putsDecoration("// Reset structure values\n");
putsDecoration(modp, "// Reset structure values\n");
puts(modName + "__" + protect("_ctor_var_reset") + "(this);\n");
emitTextSection(modp, VNType::atScCtor);
@ -339,7 +340,7 @@ class EmitCImp final : EmitCFunc {
}
void emitDestructorImp(const AstNodeModule* modp) {
puts("\n");
puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n");
putns(modp, prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n");
emitTextSection(modp, VNType::atScDtor);
puts("}\n");
splitSizeInc(10);
@ -352,8 +353,8 @@ class EmitCImp final : EmitCFunc {
const string funcname = de ? "__Vdeserialize" : "__Vserialize";
const string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void " + prefixNameProtect(modp) + "::" + protect(funcname) + "(" + classname
+ "& os) {\n");
putns(modp, "void " + prefixNameProtect(modp) + "::" + protect(funcname) + "("
+ classname + "& os) {\n");
// Place a computed checksum to ensure proper structure save/restore formatting
// OK if this hash includes some things we won't dump, since
// just looking for loading the wrong model
@ -414,7 +415,7 @@ class EmitCImp final : EmitCFunc {
puts("; " + ivar + " < " + cvtToStr(elementp->widthWords()));
puts("; ++" + ivar + ") {\n");
}
puts("os" + op + varp->nameProtect());
putns(varp, "os" + op + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}\n");
@ -773,7 +774,7 @@ class EmitCTrace final : EmitCFunc {
m_enumNumMap[nodep] = enumNum;
int nvals = 0;
typesFp()->puts("{\n");
typesFp()->puts("const char* " + protect("__VenumItemNames") + "[]\n");
typesFp()->putns(nodep, "const char* " + protect("__VenumItemNames") + "[]\n");
typesFp()->puts("= {");
for (AstEnumItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), EnumItem)) {
@ -817,26 +818,28 @@ class EmitCTrace final : EmitCFunc {
// Note: Both VTraceType::CHANGE and VTraceType::FULL use the 'full' methods
const std::string func = nodep->traceType() == VTraceType::CHANGE ? "chg" : "full";
bool emitWidth = true;
string stype;
if (nodep->dtypep()->basicp()->isDouble()) {
puts("bufp->" + func + "Double");
stype = "Double";
emitWidth = false;
} else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) {
puts("bufp->" + func + "WData");
stype = "WData";
} else if (nodep->isQuad()) {
puts("bufp->" + func + "QData");
stype = "QData";
} else if (nodep->declp()->widthMin() > 16) {
puts("bufp->" + func + "IData");
stype = "IData";
} else if (nodep->declp()->widthMin() > 8) {
puts("bufp->" + func + "SData");
stype = "SData";
} else if (nodep->declp()->widthMin() > 1) {
puts("bufp->" + func + "CData");
stype = "CData";
} else if (nodep->dtypep()->basicp()->isEvent()) {
puts("bufp->" + func + "Event");
stype = "Event";
emitWidth = false;
} else {
puts("bufp->" + func + "Bit");
stype = "Bit";
emitWidth = false;
}
putns(nodep, "bufp->" + func + stype);
const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords());
const uint32_t code = nodep->declp()->code() + offset;
@ -906,17 +909,18 @@ class EmitCTrace final : EmitCFunc {
EmitCFunc::visit(nodep);
}
void visit(AstTracePushPrefix* nodep) override {
puts("tracep->pushPrefix(");
putns(nodep, "tracep->pushPrefix(");
putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect()));
puts(", VerilatedTracePrefixType::");
puts(nodep->prefixType().ascii());
puts(");\n");
}
void visit(AstTracePopPrefix* nodep) override { //
puts("tracep->popPrefix();\n");
putns(nodep, "tracep->popPrefix();\n");
}
void visit(AstTraceDecl* nodep) override {
const int enumNum = emitTraceDeclDType(nodep->dtypep());
putns(nodep, "");
if (nodep->arrayRange().ranged()) {
puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n");
emitTraceInitOne(nodep, enumNum);
@ -946,7 +950,7 @@ class EmitCTrace final : EmitCFunc {
if (m_slow) openNextTypesFile();
// Emit functions
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); }
if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) iterateConst(funcp);
}
// Close output file
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);

View File

@ -87,7 +87,7 @@ class EmitCModel final : public EmitCFunc {
puts("\n");
puts("// This class is the main interface to the Verilated model\n");
puts("class alignas(VL_CACHE_LINE_BYTES) " + topClassName() + " VL_NOT_FINAL : ");
putns(modp, "class alignas(VL_CACHE_LINE_BYTES) " + topClassName() + " VL_NOT_FINAL : ");
if (optSystemC()) {
// SC_MODULE, but with multiple-inheritance of VerilatedModel
puts("public ::sc_core::sc_module, ");
@ -120,7 +120,8 @@ class EmitCModel final : public EmitCFunc {
"// Otherwise the application code can consider these internals.\n");
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
puts(prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + ";\n");
putns(cellp, prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect()
+ ";\n");
}
}
@ -253,7 +254,7 @@ class EmitCModel final : public EmitCFunc {
putSectionDelimiter("Constructors");
puts("\n");
puts(topClassName() + "::" + topClassName());
putns(modp, topClassName() + "::" + topClassName());
if (optSystemC()) {
puts("(sc_core::sc_module_name /* unused */)\n");
puts(" : VerilatedModel{*Verilated::threadContextp()}\n");
@ -269,7 +270,8 @@ class EmitCModel final : public EmitCFunc {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isPrimaryIO()) {
const string protName = varp->nameProtect();
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
puts(" , ");
putns(varp, protName + "{vlSymsp->TOP." + protName + "}\n");
}
}
}
@ -278,7 +280,8 @@ class EmitCModel final : public EmitCFunc {
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
const string protName = cellp->nameProtect();
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
puts(" , ");
putns(cellp, protName + "{vlSymsp->TOP." + protName + "}\n");
}
}
@ -291,7 +294,7 @@ class EmitCModel final : public EmitCFunc {
if (optSystemC()) {
// Create sensitivity list for when to evaluate the model.
putsDecoration("// Sensitivities on all clocks and combinational inputs\n");
putsDecoration(nullptr, "// Sensitivities on all clocks and combinational inputs\n");
puts("SC_METHOD(eval);\n");
if (v3Global.usesTiming()) puts("SC_METHOD(eval_sens);\n");
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
@ -307,12 +310,12 @@ class EmitCModel final : public EmitCFunc {
UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp,
"Should have swapped msb & lsb earlier.");
const string ivar = std::string{"__Vi"} + cvtToStr(vecnum);
puts("for (int __Vi" + cvtToStr(vecnum) + " = "
+ cvtToStr(arrayp->lo()));
putns(varp, "for (int __Vi" + cvtToStr(vecnum) + " = "
+ cvtToStr(arrayp->lo()));
puts("; " + ivar + " <= " + cvtToStr(arrayp->hi()));
puts("; ++" + ivar + ") {\n");
}
puts("sensitive << " + varp->nameProtect());
putns(varp, "sensitive << " + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}\n");
@ -384,7 +387,7 @@ class EmitCModel final : public EmitCFunc {
+ "::eval_step\\n\"); );\n");
puts("#ifdef VL_DEBUG\n");
putsDecoration("// Debug assertions\n");
putsDecoration(nullptr, "// Debug assertions\n");
puts(topModNameProtected + "__" + protect("_eval_debug_assertions")
+ "(&(vlSymsp->TOP));\n");
puts("#endif // VL_DEBUG\n");
@ -407,7 +410,7 @@ class EmitCModel final : public EmitCFunc {
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Eval\\n\"););\n");
puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n");
putsDecoration("// Evaluate cleanup\n");
putsDecoration(nullptr, "// Evaluate cleanup\n");
puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
puts("}\n");
@ -419,11 +422,12 @@ class EmitCModel final : public EmitCFunc {
// ::eval_end_step
if (v3Global.needTraceDumper() && !optSystemC()) {
puts("\nvoid " + topClassName() + "::eval_end_step() {\n");
puts("\n");
putns(modp, "void " + topClassName() + "::eval_end_step() {\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + topClassName()
+ "::eval_end_step\\n\"); );\n");
puts("#ifdef VM_TRACE\n");
putsDecoration("// Tracing\n");
putsDecoration(nullptr, "// Tracing\n");
// SystemC's eval loop deals with calling trace, not us
puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) vlSymsp->_traceDump();\n");
puts("#endif // VM_TRACE\n");
@ -432,14 +436,15 @@ class EmitCModel final : public EmitCFunc {
putSectionDelimiter("Events and timing");
if (auto* const delaySchedp = v3Global.rootp()->delaySchedulerp()) {
puts("bool " + topClassName() + "::eventsPending() { return !vlSymsp->TOP.");
putns(modp, "bool " + topClassName() + "::eventsPending() { return !vlSymsp->TOP.");
puts(delaySchedp->nameProtect());
puts(".empty(); }\n\n");
puts("uint64_t " + topClassName() + "::nextTimeSlot() { return vlSymsp->TOP.");
putns(modp, "uint64_t " + topClassName() + "::nextTimeSlot() { return vlSymsp->TOP.");
puts(delaySchedp->nameProtect());
puts(".nextTimeSlot(); }\n");
} else {
puts("bool " + topClassName() + "::eventsPending() { return false; }\n\n");
putns(modp, "bool " + topClassName() + "::eventsPending() { return false; }\n\n");
puts("uint64_t " + topClassName() + "::nextTimeSlot() {\n");
puts("VL_FATAL_MT(__FILE__, __LINE__, \"\", \"%Error: No delays in the "
"design\");\n");
@ -450,7 +455,8 @@ class EmitCModel final : public EmitCFunc {
if (!optSystemC()) {
// ::name
puts("\nconst char* " + topClassName() + "::name() const {\n");
puts("\n");
putns(modp, "const char* " + topClassName() + "::name() const {\n");
puts(/**/ "return vlSymsp->name();\n");
puts("}\n");
}
@ -458,21 +464,23 @@ class EmitCModel final : public EmitCFunc {
putSectionDelimiter("Invoke final blocks");
// Forward declarations
puts("\n");
puts("void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n");
putns(modp,
"void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n");
// ::final
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n");
puts("}\n");
putSectionDelimiter("Implementations of abstract methods from VerilatedModel\n");
puts("const char* " + topClassName() + "::hierName() const { return vlSymsp->name(); }\n");
puts("const char* " + topClassName() + "::modelName() const { return \"" + topClassName()
+ "\"; }\n");
puts("unsigned " + topClassName() + "::threads() const { return "
+ cvtToStr(v3Global.opt.threads()) + "; }\n");
puts("void " + topClassName()
+ "::prepareClone() const { contextp()->prepareClone(); }\n");
puts("void " + topClassName() + "::atClone() const {\n");
putns(modp, "const char* " + topClassName()
+ "::hierName() const { return vlSymsp->name(); }\n");
putns(modp, "const char* " + topClassName() + "::modelName() const { return \""
+ topClassName() + "\"; }\n");
putns(modp, "unsigned " + topClassName() + "::threads() const { return "
+ cvtToStr(v3Global.opt.threads()) + "; }\n");
putns(modp, "void " + topClassName()
+ "::prepareClone() const { contextp()->prepareClone(); }\n");
putns(modp, "void " + topClassName() + "::atClone() const {\n");
if (v3Global.opt.threads() > 1) {
puts("vlSymsp->__Vm_threadPoolp = static_cast<VlThreadPool*>(");
}
@ -481,8 +489,8 @@ class EmitCModel final : public EmitCFunc {
puts(";\n}\n");
if (v3Global.opt.trace()) {
puts("std::unique_ptr<VerilatedTraceConfig> " + topClassName()
+ "::traceConfig() const {\n");
putns(modp, "std::unique_ptr<VerilatedTraceConfig> " + topClassName()
+ "::traceConfig() const {\n");
puts("return std::unique_ptr<VerilatedTraceConfig>{new VerilatedTraceConfig{");
puts(v3Global.opt.useTraceParallel() ? "true" : "false");
puts(v3Global.opt.useTraceOffload() ? ", true" : ", false");
@ -498,16 +506,17 @@ class EmitCModel final : public EmitCFunc {
putSectionDelimiter("Trace configuration");
// Forward declaration
puts("\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "("
+ v3Global.opt.traceClassBase() + "* tracep);\n");
puts("\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "("
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
+ "* tracep);\n");
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "("
+ v3Global.opt.traceClassBase() + "* tracep);\n");
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "("
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
+ "* tracep);\n");
// Static helper function
puts("\nVL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, "
+ v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n");
putsDecoration("// Callback from tracep->open()\n");
puts("\n");
putns(modp, "VL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, "
+ v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n");
putsDecoration(modp, "// Callback from tracep->open()\n");
puts(voidSelfAssign(modp));
puts(symClassAssign());
puts("if (!vlSymsp->_vm_contextp__->calcUnusedSigs()) {\n");
@ -524,16 +533,18 @@ class EmitCModel final : public EmitCFunc {
puts("}\n");
// Forward declaration
puts("\nVL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register") + "("
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
+ "* tracep);\n");
puts("\n");
putns(modp, "VL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register")
+ "(" + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
+ "* tracep);\n");
const CFuncVector traceInitFuncps
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiTraceInit(); });
for (const AstCFunc* const funcp : traceInitFuncps) emitCFuncDecl(funcp, modp);
// ::trace
puts("\nVL_ATTR_COLD void " + topClassName() + "::trace(");
puts("\n");
putns(modp, "VL_ATTR_COLD void " + topClassName() + "::trace(");
puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n");
if (optSystemC()) {
puts(/**/ "if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {\n");
@ -579,7 +590,8 @@ class EmitCModel final : public EmitCFunc {
void emitTraceOffMethods(AstNodeModule* modp) {
putSectionDelimiter("Trace configuration");
// ::trace
puts("\nVL_ATTR_COLD void " + topClassName() + "::trace(");
puts("\n");
putns(modp, "VL_ATTR_COLD void " + topClassName() + "::trace(");
puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n");
puts(/**/ "vl_fatal(__FILE__, __LINE__, __FILE__,\"'" + topClassName()
+ +"::trace()' called on model that was Verilated without --trace option\");\n");

View File

@ -40,13 +40,15 @@ class EmitCSyms final : EmitCBaseVisitorConst {
// TYPES
struct ScopeData final {
const AstNode* m_nodep;
const string m_symName;
const string m_prettyName;
const int m_timeunit;
string m_type;
ScopeData(const string& symName, const string& prettyName, int timeunit,
const string& type)
: m_symName{symName}
ScopeData(const AstNode* nodep, const string& symName, const string& prettyName,
int timeunit, const string& type)
: m_nodep{nodep}
, m_symName{symName}
, m_prettyName{prettyName}
, m_timeunit{timeunit}
, m_type{type} {}
@ -100,9 +102,9 @@ class EmitCSyms final : EmitCBaseVisitorConst {
std::vector<ScopeModPair> m_scopes; // Every scope by module
std::vector<AstCFunc*> m_dpis; // DPI functions
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
ScopeNames m_scopeNames; // Each unique AstScopeName
std::map<const std::string, ScopeFuncData> m_scopeFuncs; // Each {scope,dpi-export-func}
std::map<const std::string, ScopeVarData> m_scopeVars; // Each {scope,public-var}
ScopeNames m_scopeNames; // Each unique AstScopeName
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
int m_coverBins = 0; // Coverage bin number
@ -239,7 +241,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
// cppcheck-suppress stlFindInsert
m_scopeNames.emplace(scpSym,
ScopeData{scpSym, scpPretty, 0, "SCOPE_OTHER"});
ScopeData{varp, scpSym, scpPretty, 0, "SCOPE_OTHER"});
}
m_scopeVars.emplace(scpSym + " " + varp->name(),
ScopeVarData{scpSym, varBasePretty, varp, modp, scopep});
@ -311,7 +313,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
const int timeunit = m_modp->timeunit().powerOfTen();
m_vpiScopeCandidates.emplace(
scopeSymString(name),
ScopeData{scopeSymString(name), name_pretty, timeunit, type});
ScopeData{nodep, scopeSymString(name), name_pretty, timeunit, type});
}
}
void visit(AstScope* nodep) override {
@ -326,7 +328,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
const int timeunit = m_modp->timeunit().powerOfTen();
m_vpiScopeCandidates.emplace(
scopeSymString(nodep->name()),
ScopeData{scopeSymString(nodep->name()), name_pretty, timeunit, type});
ScopeData{nodep, scopeSymString(nodep->name()), name_pretty, timeunit, type});
}
}
void visit(AstScopeName* nodep) override {
@ -335,7 +337,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
// << " ss" << name << endl);
const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0;
m_scopeNames.emplace(
name, ScopeData{name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"});
name, ScopeData{nodep, name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"});
if (nodep->dpiExport()) {
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
m_scopeFuncs.emplace(name + " " + m_cfuncp->name(),
@ -343,9 +345,9 @@ class EmitCSyms final : EmitCBaseVisitorConst {
} else {
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
// cppcheck-suppress stlFindInsert
m_scopeNames.emplace(nodep->scopeDpiName(),
ScopeData{nodep->scopeDpiName(), nodep->scopePrettyDpiName(),
timeunit, "SCOPE_OTHER"});
m_scopeNames.emplace(nodep->scopeDpiName(), ScopeData{nodep, nodep->scopeDpiName(),
nodep->scopePrettyDpiName(),
timeunit, "SCOPE_OTHER"});
}
}
}
@ -415,7 +417,7 @@ void EmitCSyms::emitSymHdr() {
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_AS(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
putns(nodep, "#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
if (v3Global.dpi()) {
@ -486,7 +488,7 @@ void EmitCSyms::emitSymHdr() {
if (VN_IS(modp, Class)) continue;
const string name = prefixNameProtect(modp);
ofp()->printf("%-30s ", name.c_str());
puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
putns(scopep, protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
}
if (m_coverBins) {
@ -506,7 +508,8 @@ void EmitCSyms::emitSymHdr() {
if (!m_scopeNames.empty()) { // Scope names
puts("\n// SCOPE NAMES\n");
for (const auto& itr : m_scopeNames) {
puts("VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n");
putns(itr.second.m_nodep,
"VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n");
}
}
@ -522,7 +525,7 @@ void EmitCSyms::emitSymHdr() {
for (const auto& i : m_usesVfinal) {
puts("void " + symClassName() + "_" + cvtToStr(i.first) + "(");
if (i.second) { puts("int __Vfinal"); }
if (i.second) puts("int __Vfinal");
puts(");\n");
}
@ -604,12 +607,12 @@ void EmitCSyms::checkSplit(bool usesVfinal) {
}
m_ofpBase->puts(symClassName() + "_" + cvtToStr(m_funcNum) + "(");
if (usesVfinal) { m_ofpBase->puts("__Vfinal"); }
if (usesVfinal) m_ofpBase->puts("__Vfinal");
m_ofpBase->puts(");\n");
emitSymImpPreamble();
puts("void " + symClassName() + "::" + symClassName() + "_" + cvtToStr(m_funcNum) + "(");
if (usesVfinal) { puts("int __Vfinal"); }
if (usesVfinal) puts("int __Vfinal");
puts(") {\n");
}
@ -625,7 +628,7 @@ void EmitCSyms::emitSymImpPreamble() {
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_AS(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
putns(nodep, "#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
puts("\n");
// Declarations for DPI Export implementation functions
@ -651,8 +654,9 @@ void EmitCSyms::emitScopeHier(bool destroy) {
const string scopeType = it->second.m_type;
if ((name.find('.') == string::npos)
&& (scopeType == "SCOPE_MODULE" || scopeType == "SCOPE_PACKAGE")) {
puts("__Vhier." + method + "(0, &" + protect("__Vscope_" + it->second.m_symName)
+ ");\n");
putns(it->second.m_nodep, "__Vhier." + method + "(0, &"
+ protect("__Vscope_" + it->second.m_symName)
+ ");\n");
}
}
@ -799,7 +803,7 @@ void EmitCSyms::emitSymImp() {
const AstScope* const scopep = i.first;
const AstNodeModule* const modp = i.second;
puts(" , ");
puts(protect(scopep->nameDotless()));
putns(scopep, protect(scopep->nameDotless()));
puts("{this");
if (modp->isTop()) {
puts(", namep");
@ -857,9 +861,9 @@ void EmitCSyms::emitSymImp() {
const string protName = protectWordsIf(scopep->name(), scopep->protect());
if (VN_IS(modp, ClassPackage)) {
// ClassPackage modules seem to be a bit out of place, so hard code...
puts("TOP");
putns(scopep, "TOP");
} else {
puts(protectIf(aboveScopep->nameDotless(), aboveScopep->protect()));
putns(scopep, protectIf(aboveScopep->nameDotless(), aboveScopep->protect()));
}
puts(".");
puts(protName.substr(protName.rfind('.') + 1));
@ -877,8 +881,8 @@ void EmitCSyms::emitSymImp() {
// first is used by AstCoverDecl's call to __vlCoverInsert
const bool first = !modp->user1();
modp->user1(true);
puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + protect("__Vconfigure")
+ "(" + (first ? "true" : "false") + ");\n");
putns(scopep, protectIf(scopep->nameDotless(), scopep->protect()) + "."
+ protect("__Vconfigure") + "(" + (first ? "true" : "false") + ");\n");
++m_numStmts;
}
@ -886,7 +890,8 @@ void EmitCSyms::emitSymImp() {
puts("// Setup scopes\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
checkSplit(false);
puts(protect("__Vscope_" + it->second.m_symName) + ".configure(this, name(), ");
putns(it->second.m_nodep,
protect("__Vscope_" + it->second.m_symName) + ".configure(this, name(), ");
putsQuoted(protectWordsIf(it->second.m_prettyName, true));
puts(", ");
putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName)));
@ -911,7 +916,8 @@ void EmitCSyms::emitSymImp() {
AstNodeModule* const modp = it->second.m_modp;
if (funcp->dpiExportImpl()) {
checkSplit(true);
puts(protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, ");
putns(scopep,
protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, ");
putsQuoted(funcp->cname()); // Not protected - user asked for import/export
puts(", (void*)(&");
puts(prefixNameProtect(modp));
@ -972,7 +978,8 @@ void EmitCSyms::emitSymImp() {
if (pdim > 1 || udim > 1) {
puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays
}
puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,");
putns(scopep, protect("__Vscope_" + it->second.m_scopeName));
putns(varp, ".varInsert(__Vfinal,");
putsQuoted(protect(it->second.m_varBasePretty));
std::string varName;
@ -1049,16 +1056,16 @@ void EmitCSyms::emitDpiHdr() {
for (AstCFunc* nodep : m_dpis) {
if (nodep->dpiExportDispatcher()) {
if (!firstExp++) puts("\n// DPI EXPORTS\n");
putsDecoration("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii())
+ "\n");
puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "("
+ cFuncArgs(nodep) + ");\n");
putsDecoration(nodep, "// DPI export"
+ ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n");
putns(nodep, "extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "("
+ cFuncArgs(nodep) + ");\n");
} else if (nodep->dpiImportPrototype()) {
if (!firstImp++) puts("\n// DPI IMPORTS\n");
putsDecoration("// DPI import" + ifNoProtect(" at " + nodep->fileline()->ascii())
+ "\n");
puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "("
+ cFuncArgs(nodep) + ");\n");
putsDecoration(nodep, "// DPI import"
+ ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n");
putns(nodep, "extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "("
+ cFuncArgs(nodep) + ");\n");
}
}
@ -1105,19 +1112,21 @@ void EmitCSyms::emitDpiImp() {
// Prevent multi-definition if used by multiple models
puts("#ifndef VL_DPIDECL_" + nodep->name() + "_\n");
puts("#define VL_DPIDECL_" + nodep->name() + "_\n");
puts(nodep->rtnTypeVoid() + " " + nodep->name() + "(" + cFuncArgs(nodep) + ") {\n");
putns(nodep,
nodep->rtnTypeVoid() + " " + nodep->name() + "(" + cFuncArgs(nodep) + ") {\n");
puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n");
puts("return " + topClassName() + "::" + nodep->name() + "(");
string args;
putns(nodep, "return " + topClassName() + "::" + nodep->name() + "(");
string comma;
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args += ", ";
args += portp->name();
puts(comma);
comma = ", ";
putns(portp, portp->name());
}
}
}
puts(args + ");\n");
puts(");\n");
puts("}\n");
puts("#endif\n");
puts("\n");

View File

@ -695,15 +695,28 @@ int V3OutFormatter::endLevels(const char* strg) {
return levels;
}
void V3OutFormatter::puts(const char* strg) {
void V3OutFormatter::putns(const AstNode* nodep, const char* strg) {
if (!v3Global.opt.decoration()) {
putsOutput(strg);
return;
}
if (m_prependIndent && strg[0] != '\n') {
putsNoTracking(indentSpaces(endLevels(strg)));
m_prependIndent = false;
}
if (nodep && v3Global.opt.decorationNodes() && !v3Global.opt.protectIds()
&& (m_sourceLastFilenameno != nodep->fileline()->filenameno()
|| m_sourceLastLineno != nodep->fileline()->firstLineno())
&& FileLine::builtInFilename() != nodep->fileline()->filename()) {
m_sourceLastLineno = nodep->fileline()->firstLineno();
m_sourceLastFilenameno = nodep->fileline()->filenameno();
putsNoTracking("/*" + nodep->fileline()->filename() + ":"
+ cvtToStr(nodep->fileline()->lineno()) + " " + cvtToStr((void*)nodep)
+ "*/");
}
bool notstart = false;
bool wordstart = true;
bool equalsForBracket = false; // Looking for "= {"

View File

@ -30,6 +30,8 @@
#include <stack>
#include <vector>
class AstNode;
//============================================================================
// V3File: Create streams, recording dependency information
@ -122,6 +124,8 @@ private:
int m_lineno = 1;
int m_column = 0;
int m_nobreak = false; // Basic operator or begin paren, don't break next
int m_sourceLastLineno = 0;
int m_sourceLastFilenameno = 0;
bool m_prependIndent = true;
bool m_inStringLiteral = false;
int m_indentLevel = 0; // Current {} indentation
@ -141,19 +145,25 @@ public:
void blockIndent(int flag) { m_blockIndent = flag; }
// METHODS
void printf(const char* fmt...) VL_ATTR_PRINTF(2);
void puts(const char* strg);
void puts(const string& strg) { puts(strg.c_str()); }
void puts(const char* strg) { putns(nullptr, strg); }
void puts(const string& strg) { putns(nullptr, strg); }
void putns(const AstNode* nodep, const char* strg);
void putns(const AstNode* nodep, const string& strg) { putns(nodep, strg.c_str()); }
void putsNoTracking(const string& strg);
void putsQuoted(const string& strg);
void putBreak(); // Print linebreak if line is too wide
void putBreakExpr(); // Print linebreak in expression if line is too wide
void putbs(const char* strg) {
putBreakExpr();
puts(strg);
putns(nullptr, strg);
}
void putbs(const string& strg) {
putBreakExpr();
puts(strg);
putns(nullptr, strg);
}
void putnbs(const AstNode* nodep, const string& strg) {
putBreakExpr();
putns(nodep, strg);
}
bool exceededWidth() const { return m_column > m_commaWidth; }
void indentInc() { m_indentLevel += m_blockIndent; }

View File

@ -444,6 +444,23 @@ void V3Options::ccSet() { // --cc
m_systemC = false;
}
void V3Options::decorations(FileLine* fl, const string& arg) { // --decorations
if (arg == "none") {
m_decoration = false;
m_decorationNodes = false;
} else if (arg == "node") {
m_decoration = true;
m_decorationNodes = true;
} else if (arg == "medium") {
m_decoration = true;
m_decorationNodes = false;
} else {
fl->v3fatal("Unknown setting for --decorations: '"
<< arg << "'\n"
<< fl->warnMore() << "... Suggest 'none', 'medium', or 'node'");
}
}
//######################################################################
// File searching
@ -1167,7 +1184,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented();
DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort
DECL_OPTION("-debug-stack-check", OnOff, &m_debugStackCheck).undocumented();
DECL_OPTION("-decoration", OnOff, &m_decoration);
DECL_OPTION("-decoration", CbCall, [this, fl]() { decorations(fl, "medium"); });
DECL_OPTION("-decorations", CbVal, [this, fl](const char* optp) { decorations(fl, optp); });
DECL_OPTION("-no-decoration", CbCall, [this, fl]() { decorations(fl, "none"); });
DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly);
DECL_OPTION("-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 3; });
DECL_OPTION("-no-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 0; });
@ -1383,7 +1402,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes);
DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) {
m_reloopLimit = std::atoi(valp);
if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); }
if (m_reloopLimit < 2) fl->v3error("--reloop-limit must be >= 2: " << valp);
});
DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat);
DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell

View File

@ -245,6 +245,7 @@ private:
bool m_debugSelfTest = false; // main switch: --debug-self-test
bool m_debugStackCheck = false; // main switch: --debug-stack-check
bool m_decoration = true; // main switch: --decoration
bool m_decorationNodes = false; // main switch: --decoration=nodes
bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only
bool m_exe = false; // main switch: --exe
bool m_flatten = false; // main switch: --flatten
@ -430,6 +431,7 @@ public:
void addForceInc(const string& filename);
bool available() const VL_MT_SAFE { return m_available; }
void ccSet();
void decorations(FileLine* fl, const string& filename);
void notify() VL_MT_DISABLED;
// ACCESSORS (options)
@ -474,6 +476,7 @@ public:
bool debugSelfTest() const { return m_debugSelfTest; }
bool debugStackCheck() const { return m_debugStackCheck; }
bool decoration() const VL_MT_SAFE { return m_decoration; }
bool decorationNodes() const VL_MT_SAFE { return m_decorationNodes; }
bool dpiHdrOnly() const { return m_dpiHdrOnly; }
bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); }
bool dumpTreeDot() const {

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_decoration.v");
compile(
verilator_flags2 => ["--decoration"],
);
file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!);
file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!);
file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!);
ok(1);
1;

View File

@ -0,0 +1,8 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2010 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
endmodule

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_decoration.v");
compile(
verilator_flags2 => ["--no-decoration"],
);
file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!);
file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!);
file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!);
ok(1);
1;

View File

@ -0,0 +1,2 @@
%Error: Unknown setting for --decorations: 'BAD'
... Suggest 'none', 'medium', or 'node'

View File

@ -0,0 +1,22 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_decoration.v");
lint(
verilator_flags2 => ["-decorations BAD"],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_decoration.v");
compile(
verilator_flags2 => ["--decorations node"],
);
file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!);
file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!);
file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!);
ok(1);
1;