2021-06-24 15:58:30 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Emit C++ for tree
|
|
|
|
//
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2023-01-01 15:18:39 +00:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2021-06-24 15:58:30 +00:00
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
#include "V3EmitCBase.h"
|
2022-08-05 09:56:57 +00:00
|
|
|
|
2021-06-24 16:08:07 +00:00
|
|
|
#include "V3Task.h"
|
2021-06-24 15:58:30 +00:00
|
|
|
|
2021-07-22 14:53:42 +00:00
|
|
|
//######################################################################
|
|
|
|
// EmitCParentModule implementation
|
|
|
|
|
|
|
|
EmitCParentModule::EmitCParentModule() {
|
|
|
|
const auto setAll = [](AstNodeModule* modp) -> void {
|
|
|
|
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
|
|
|
if (VN_IS(nodep, CFunc) || VN_IS(nodep, Var)) { nodep->user4p(modp); }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
for (AstNode* modp = v3Global.rootp()->modulesp(); modp; modp = modp->nextp()) {
|
2021-10-22 12:56:48 +00:00
|
|
|
setAll(VN_AS(modp, NodeModule));
|
2021-07-22 14:53:42 +00:00
|
|
|
}
|
|
|
|
setAll(v3Global.rootp()->constPoolp()->modp());
|
|
|
|
}
|
|
|
|
|
2021-06-24 15:58:30 +00:00
|
|
|
//######################################################################
|
|
|
|
// EmitCBaseVisitor implementation
|
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
2021-07-22 14:53:42 +00:00
|
|
|
modp = modp ? modp : EmitCParentModule::get(nodep);
|
2021-06-24 15:58:30 +00:00
|
|
|
string name;
|
|
|
|
if (nodep->isConstructor()) {
|
|
|
|
name += prefixNameProtect(modp);
|
|
|
|
} else if (nodep->isDestructor()) {
|
|
|
|
name += "~";
|
|
|
|
name += prefixNameProtect(modp);
|
|
|
|
} else {
|
|
|
|
if (nodep->isLoose()) {
|
|
|
|
name += prefixNameProtect(modp);
|
|
|
|
name += "__";
|
|
|
|
}
|
|
|
|
name += nodep->nameProtect();
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2023-04-11 11:25:10 +00:00
|
|
|
AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) {
|
|
|
|
AstCFile* const cfilep = createCFile(filename, slow, source);
|
|
|
|
v3Global.rootp()->addFilesp(cfilep);
|
|
|
|
return cfilep;
|
|
|
|
}
|
|
|
|
|
|
|
|
AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow,
|
|
|
|
bool source) VL_MT_SAFE {
|
2022-11-20 18:11:01 +00:00
|
|
|
AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename};
|
2021-06-24 15:58:30 +00:00
|
|
|
cfilep->slow(slow);
|
|
|
|
cfilep->source(source);
|
|
|
|
return cfilep;
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) {
|
2021-06-24 15:58:30 +00:00
|
|
|
// Return argument list for given C function
|
|
|
|
string args;
|
|
|
|
if (nodep->isLoose() && !nodep->isStatic()) {
|
|
|
|
if (nodep->isConst().trueKnown()) args += "const ";
|
2021-07-22 14:53:42 +00:00
|
|
|
args += prefixNameProtect(EmitCParentModule::get(nodep));
|
2021-06-24 15:58:30 +00:00
|
|
|
args += "* vlSelf";
|
|
|
|
}
|
|
|
|
if (!nodep->argTypes().empty()) {
|
|
|
|
if (!args.empty()) args += ", ";
|
|
|
|
args += nodep->argTypes();
|
|
|
|
}
|
|
|
|
// Might be a user function with argument list.
|
|
|
|
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
2021-11-13 18:50:44 +00:00
|
|
|
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
|
2021-06-24 15:58:30 +00:00
|
|
|
if (portp->isIO() && !portp->isFuncReturn()) {
|
|
|
|
if (args != "") args += ", ";
|
|
|
|
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) {
|
|
|
|
args += portp->dpiArgType(true, false);
|
|
|
|
} else if (nodep->funcPublic()) {
|
|
|
|
args += portp->cPubArgType(true, false);
|
|
|
|
} else {
|
|
|
|
args += portp->vlArgType(true, false, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp,
|
|
|
|
bool withScope) {
|
2021-07-20 12:52:53 +00:00
|
|
|
if (funcp->slow()) puts("VL_ATTR_COLD ");
|
2021-06-24 15:58:30 +00:00
|
|
|
if (!funcp->isConstructor() && !funcp->isDestructor()) {
|
|
|
|
puts(funcp->rtnTypeVoid());
|
|
|
|
puts(" ");
|
|
|
|
}
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
if (withScope) {
|
|
|
|
if (funcp->dpiExportDispatcher()) {
|
|
|
|
puts(topClassName() + "::");
|
|
|
|
} else if (funcp->isProperMethod()) {
|
|
|
|
puts(prefixNameProtect(modp) + "::");
|
|
|
|
}
|
|
|
|
}
|
2021-06-24 15:58:30 +00:00
|
|
|
puts(funcNameProtect(funcp, modp));
|
|
|
|
puts("(" + cFuncArgs(funcp) + ")");
|
|
|
|
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp,
|
|
|
|
bool cLinkage) {
|
2021-06-24 15:58:30 +00:00
|
|
|
ensureNewLine();
|
|
|
|
if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n");
|
|
|
|
if (cLinkage) puts("extern \"C\" ");
|
|
|
|
if (funcp->isStatic() && funcp->isProperMethod()) puts("static ");
|
|
|
|
if (funcp->isVirtual()) {
|
|
|
|
UASSERT_OBJ(funcp->isProperMethod(), funcp, "Virtual function is not a proper method");
|
|
|
|
puts("virtual ");
|
|
|
|
}
|
|
|
|
emitCFuncHeader(funcp, modp, /* withScope: */ false);
|
|
|
|
puts(";\n");
|
|
|
|
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
|
|
|
|
}
|
2021-06-24 16:08:07 +00:00
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
|
2021-06-24 16:08:07 +00:00
|
|
|
const AstBasicDType* const basicp = nodep->basicp();
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
2021-06-24 16:08:07 +00:00
|
|
|
|
|
|
|
const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void {
|
|
|
|
// This isn't very robust and may need cleanup for other data types
|
2021-10-22 14:15:42 +00:00
|
|
|
for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
|
|
|
arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
|
2021-06-24 16:08:07 +00:00
|
|
|
puts("[" + cvtToStr(arrayp->elementsConst()) + "]");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (nodep->isIO() && nodep->isSc()) {
|
|
|
|
UASSERT_OBJ(basicp, nodep, "Unimplemented: Outputting this data type");
|
|
|
|
if (nodep->attrScClocked() && nodep->isReadOnly()) {
|
|
|
|
puts("sc_in_clk ");
|
|
|
|
} else {
|
|
|
|
if (nodep->isInoutish()) {
|
|
|
|
puts("sc_inout<");
|
|
|
|
} else if (nodep->isWritable()) {
|
|
|
|
puts("sc_out<");
|
|
|
|
} else if (nodep->isNonOutput()) {
|
|
|
|
puts("sc_in<");
|
|
|
|
} else {
|
|
|
|
nodep->v3fatalSrc("Unknown type");
|
|
|
|
}
|
|
|
|
puts(nodep->scType());
|
|
|
|
puts("> ");
|
|
|
|
}
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
if (asRef) {
|
|
|
|
if (refNeedParens) puts("(");
|
|
|
|
puts("&");
|
|
|
|
}
|
2021-06-24 16:08:07 +00:00
|
|
|
puts(nodep->nameProtect());
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
if (asRef && refNeedParens) { puts(")"); }
|
2021-06-24 16:08:07 +00:00
|
|
|
emitDeclArrayBrackets(nodep);
|
|
|
|
puts(";\n");
|
|
|
|
} else if (nodep->isIO() && basicp && !basicp->isOpaque()) {
|
|
|
|
if (nodep->isInoutish()) {
|
|
|
|
puts("VL_INOUT");
|
|
|
|
} else if (nodep->isWritable()) {
|
|
|
|
puts("VL_OUT");
|
|
|
|
} else if (nodep->isNonOutput()) {
|
|
|
|
puts("VL_IN");
|
|
|
|
} else {
|
|
|
|
nodep->v3fatalSrc("Unknown type");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodep->isQuad()) {
|
|
|
|
puts("64");
|
|
|
|
} else if (nodep->widthMin() <= 8) {
|
|
|
|
puts("8");
|
|
|
|
} else if (nodep->widthMin() <= 16) {
|
|
|
|
puts("16");
|
|
|
|
} else if (nodep->isWide()) {
|
|
|
|
puts("W");
|
|
|
|
}
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
puts("(");
|
|
|
|
if (asRef) {
|
|
|
|
if (refNeedParens) puts("(");
|
|
|
|
puts("&");
|
|
|
|
}
|
|
|
|
puts(nodep->nameProtect());
|
|
|
|
if (asRef && refNeedParens) { puts(")"); }
|
2021-06-24 16:08:07 +00:00
|
|
|
emitDeclArrayBrackets(nodep);
|
|
|
|
// If it's a packed struct/array then nodep->width is the whole
|
|
|
|
// thing, msb/lsb is just lowest dimension
|
|
|
|
puts("," + cvtToStr(basicp->lo() + nodep->width() - 1) + "," + cvtToStr(basicp->lo()));
|
|
|
|
if (nodep->isWide()) puts("," + cvtToStr(nodep->widthWords()));
|
|
|
|
puts(");\n");
|
|
|
|
} else {
|
|
|
|
// strings and other fundamental c types
|
|
|
|
if (nodep->isFuncLocal() && nodep->isString()) {
|
|
|
|
const string name = nodep->name();
|
|
|
|
const string suffix = V3Task::dpiTemporaryVarSuffix();
|
|
|
|
// string temporary variable for DPI-C needs to be static because c_str() will be
|
|
|
|
// passed to C code and the lifetime of the variable must be long enough. See also
|
|
|
|
// Issue 2622.
|
|
|
|
const bool beStatic = name.size() >= suffix.size()
|
|
|
|
&& name.substr(name.size() - suffix.size()) == suffix;
|
2022-11-05 12:47:34 +00:00
|
|
|
if (beStatic) puts("static thread_local ");
|
2021-06-24 16:08:07 +00:00
|
|
|
}
|
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables
before Emit. All variables are now ordered together, without
consideration for whether they are ports, signals form the design, or
additional internal variables added by Verilator (which used to be
ordered and emitted as separate groups in Emit). For single threaded
models, this is performance neutral. For multi-threaded models, the
MTask affinity based sorting was slightly modified, so variables with no
MTask affinity are emitted last, otherwise the MTask affinity sets are
sorted using the TSP sorter as before, but again, ports, signals, and
internal variables are not differentiated. This yields a 2%+ speedup for
the multithreaded model on OpenTitan.
2021-06-29 16:57:07 +00:00
|
|
|
puts(nodep->vlArgType(true, false, false, "", asRef));
|
2021-06-24 16:08:07 +00:00
|
|
|
puts(";\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
2021-06-24 16:08:07 +00:00
|
|
|
string nl;
|
|
|
|
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
2021-11-26 22:55:36 +00:00
|
|
|
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
2021-06-24 16:08:07 +00:00
|
|
|
if (usep->useType() == useType) {
|
|
|
|
if (usep->useType().isInclude()) {
|
|
|
|
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
|
|
|
|
}
|
|
|
|
if (usep->useType().isFwdClass()) {
|
|
|
|
puts("class " + prefixNameProtect(usep) + ";\n");
|
|
|
|
}
|
|
|
|
nl = "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
puts(nl);
|
|
|
|
}
|
2021-07-07 18:16:40 +00:00
|
|
|
|
2023-03-18 16:17:25 +00:00
|
|
|
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
|
2021-12-20 14:42:15 +00:00
|
|
|
// Short circuit if nothing to do. This can save a lot of time on large designs as this
|
|
|
|
// function needs to traverse the entire module linearly.
|
|
|
|
if (!v3Global.hasSCTextSections()) return;
|
|
|
|
|
2021-07-07 18:16:40 +00:00
|
|
|
int last_line = -999;
|
|
|
|
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
2021-11-26 22:55:36 +00:00
|
|
|
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
|
2021-07-07 18:16:40 +00:00
|
|
|
if (nodep->type() == type) {
|
|
|
|
if (last_line != nodep->fileline()->lineno()) {
|
|
|
|
if (last_line < 0) {
|
|
|
|
puts("\n//*** Below code from `systemc in Verilog file\n");
|
|
|
|
}
|
|
|
|
putsDecoration(
|
|
|
|
ifNoProtect("// From `systemc at " + nodep->fileline()->ascii() + "\n"));
|
|
|
|
last_line = nodep->fileline()->lineno();
|
|
|
|
}
|
|
|
|
ofp()->putsNoTracking(textp->text());
|
|
|
|
last_line++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (last_line > 0) puts("//*** Above code from `systemc in Verilog file\n\n");
|
|
|
|
}
|