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.
This commit is contained in:
Geza Lore
2021-06-30 16:35:40 +01:00
parent 22e0f3edbe
commit 708abe0dd1
55 changed files with 1244 additions and 943 deletions
+23 -4
View File
@@ -86,7 +86,13 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul
puts(funcp->rtnTypeVoid());
puts(" ");
}
if (withScope && funcp->isProperMethod()) puts(prefixNameProtect(modp) + "::");
if (withScope) {
if (funcp->dpiExportDispatcher()) {
puts(topClassName() + "::");
} else if (funcp->isProperMethod()) {
puts(prefixNameProtect(modp) + "::");
}
}
puts(funcNameProtect(funcp, modp));
puts("(" + cFuncArgs(funcp) + ")");
if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const");
@@ -108,8 +114,9 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule*
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
}
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfImp, bool asRef) {
const AstBasicDType* const basicp = nodep->basicp();
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void {
// This isn't very robust and may need cleanup for other data types
@@ -137,7 +144,12 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm
puts(nodep->scType());
puts("> ");
}
if (asRef) {
if (refNeedParens) puts("(");
puts("&");
}
puts(nodep->nameProtect());
if (asRef && refNeedParens) { puts(")"); }
emitDeclArrayBrackets(nodep);
puts(";\n");
} else if (nodep->isIO() && basicp && !basicp->isOpaque()) {
@@ -159,9 +171,16 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm
puts("16");
} else if (nodep->isWide()) {
puts("W");
refNeedParens = true;
}
puts("(" + nodep->nameProtect());
puts("(");
if (asRef) {
if (refNeedParens) puts("(");
puts("&");
}
puts(nodep->nameProtect());
if (asRef && refNeedParens) { puts(")"); }
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole
// thing, msb/lsb is just lowest dimension
@@ -180,7 +199,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm
&& name.substr(name.size() - suffix.size()) == suffix;
if (beStatic) puts("static VL_THREAD_LOCAL ");
}
puts(nodep->vlArgType(true, false, false, prefixIfImp));
puts(nodep->vlArgType(true, false, false, prefixIfImp, asRef));
puts(";\n");
}
}