2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Emit C++ for tree
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3EmitC.h"
|
|
|
|
|
#include "V3EmitCBase.h"
|
2024-03-16 15:02:17 +01:00
|
|
|
#include "V3ExecGraph.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3LanguageWords.h"
|
2024-01-06 22:14:58 +01:00
|
|
|
#include "V3StackCount.h"
|
|
|
|
|
#include "V3Stats.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2018-10-14 13:04:18 +02:00
|
|
|
#include <algorithm>
|
2006-08-26 13:35:28 +02:00
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Symbol table emitting
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
// Some handy short-hands to reduce verbosity
|
|
|
|
|
static constexpr auto symClassName = &EmitCUtil::symClassName;
|
|
|
|
|
static constexpr auto topClassName = &EmitCUtil::topClassName;
|
|
|
|
|
|
2023-03-18 17:17:25 +01:00
|
|
|
class EmitCSyms final : EmitCBaseVisitorConst {
|
2008-12-05 16:54:14 +01:00
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on Netlist
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNodeModule::user1() -> bool. Set true __Vconfigure called
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser1InUse m_inuser1;
|
2008-12-05 16:54:14 +01:00
|
|
|
|
2009-12-09 04:12:59 +01:00
|
|
|
// TYPES
|
2024-01-20 21:06:46 +01:00
|
|
|
struct ScopeData final {
|
2024-01-25 03:51:47 +01:00
|
|
|
const AstNode* m_nodep;
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string m_symName;
|
|
|
|
|
const std::string m_prettyName;
|
|
|
|
|
const std::string m_defName;
|
2021-11-26 23:55:36 +01:00
|
|
|
const int m_timeunit;
|
2025-11-05 00:00:26 +01:00
|
|
|
std::string m_type; // TODO: this should be an enum
|
|
|
|
|
ScopeData(const AstNode* nodep, const std::string& symName, const std::string& prettyName,
|
|
|
|
|
const std::string& defName, int timeunit, const std::string& type)
|
2024-01-25 03:51:47 +01:00
|
|
|
: m_nodep{nodep}
|
|
|
|
|
, m_symName{symName}
|
2020-08-16 15:55:36 +02:00
|
|
|
, m_prettyName{prettyName}
|
2024-11-12 17:28:39 +01:00
|
|
|
, m_defName{defName}
|
2020-08-16 15:55:36 +02:00
|
|
|
, m_timeunit{timeunit}
|
2023-02-04 03:26:21 +01:00
|
|
|
, m_type{type} {}
|
2010-03-17 13:22:49 +01:00
|
|
|
};
|
2024-01-20 21:06:46 +01:00
|
|
|
struct ScopeFuncData final {
|
2025-11-05 00:00:26 +01:00
|
|
|
const AstScopeName* const m_scopep;
|
|
|
|
|
const AstCFunc* const m_cfuncp;
|
|
|
|
|
const AstNodeModule* const m_modp;
|
|
|
|
|
ScopeFuncData(const AstScopeName* scopep, const AstCFunc* funcp, const AstNodeModule* modp)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_scopep{scopep}
|
2020-10-31 13:59:35 +01:00
|
|
|
, m_cfuncp{funcp}
|
2020-08-16 15:55:36 +02:00
|
|
|
, m_modp{modp} {}
|
2009-12-20 14:27:00 +01:00
|
|
|
};
|
2024-01-20 21:06:46 +01:00
|
|
|
struct ScopeVarData final {
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string m_scopeName;
|
|
|
|
|
const std::string m_varBasePretty;
|
|
|
|
|
const AstVar* const m_varp;
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeModule* const m_modp;
|
2025-11-05 00:00:26 +01:00
|
|
|
const AstScope* const m_scopep;
|
|
|
|
|
ScopeVarData(const std::string& scopeName, const std::string& varBasePretty,
|
|
|
|
|
const AstVar* varp, const AstNodeModule* modp, const AstScope* scopep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_scopeName{scopeName}
|
|
|
|
|
, m_varBasePretty{varBasePretty}
|
|
|
|
|
, m_varp{varp}
|
|
|
|
|
, m_modp{modp}
|
|
|
|
|
, m_scopep{scopep} {}
|
2010-03-17 13:22:49 +01:00
|
|
|
};
|
2021-03-13 00:10:45 +01:00
|
|
|
using ScopeNames = std::map<const std::string, ScopeData>;
|
2025-11-05 00:00:26 +01:00
|
|
|
using ScopeModPair = std::pair<const AstScope*, AstNodeModule*>;
|
|
|
|
|
using ModVarPair = std::pair<const AstNodeModule*, const AstVar*>;
|
2009-12-05 16:38:49 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2020-10-31 13:59:35 +01:00
|
|
|
AstCFunc* m_cfuncp = nullptr; // Current function
|
2020-08-16 15:55:36 +02:00
|
|
|
AstNodeModule* m_modp = nullptr; // Current module
|
2019-10-02 03:57:45 +02:00
|
|
|
std::vector<ScopeModPair> m_scopes; // Every scope by module
|
2020-04-15 01:55:00 +02:00
|
|
|
std::vector<AstCFunc*> m_dpis; // DPI functions
|
|
|
|
|
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
2021-03-12 23:26:53 +01:00
|
|
|
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}
|
2025-01-16 21:02:36 +01:00
|
|
|
ScopeNames m_scopeNames; // Each unique AstScopeName. Dpi scopes added later
|
|
|
|
|
ScopeNames m_dpiScopeNames; // Each unique AstScopeName for DPI export
|
2020-04-15 01:55:00 +02:00
|
|
|
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
2025-11-05 00:00:26 +01:00
|
|
|
// The actual hierarchy of scopes
|
|
|
|
|
std::map<const std::string, std::vector<std::string>> m_vpiScopeHierarchy;
|
2020-08-16 15:55:36 +02:00
|
|
|
int m_coverBins = 0; // Coverage bin number
|
2021-11-26 23:55:36 +01:00
|
|
|
const bool m_dpiHdrOnly; // Only emit the DPI header
|
2025-11-08 11:36:12 +01:00
|
|
|
std::vector<std::string> m_splitFuncNames; // Split file names
|
2024-03-24 14:14:31 +01:00
|
|
|
VDouble0 m_statVarScopeBytes; // Statistic tracking
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
2009-12-09 04:12:59 +01:00
|
|
|
void emitSymHdr();
|
2019-09-04 12:15:41 +02:00
|
|
|
void emitSymImpPreamble();
|
2025-11-08 11:36:12 +01:00
|
|
|
void emitScopeHier(std::vector<std::string>& stmts, bool destroy);
|
2025-11-13 00:54:22 +01:00
|
|
|
void emitSymImp(const AstNetlist* netlistp);
|
2009-12-09 04:12:59 +01:00
|
|
|
void emitDpiHdr();
|
|
|
|
|
void emitDpiImp();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2025-11-13 00:54:22 +01:00
|
|
|
void emitSplit(std::vector<std::string>& stmts, const std::string& name, size_t max_stmts);
|
2025-11-08 11:36:12 +01:00
|
|
|
|
|
|
|
|
std::vector<std::string> getSymCtorStmts();
|
|
|
|
|
std::vector<std::string> getSymDtorStmts();
|
|
|
|
|
|
|
|
|
|
static size_t stmtCost(const std::string& stmt) {
|
|
|
|
|
if (stmt.empty()) return 0;
|
|
|
|
|
if (VString::startsWith(stmt, "/")) return 0;
|
|
|
|
|
return static_cast<size_t>(AstNode::INSTR_COUNT_SYM);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 20:55:46 +02:00
|
|
|
static void nameCheck(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Prevent GCC compile time error; name check all things that reach C++ code
|
2025-11-05 00:00:26 +01:00
|
|
|
if (nodep->name().empty()) return;
|
|
|
|
|
const AstCFunc* const cfuncp = VN_CAST(nodep, CFunc);
|
|
|
|
|
if (!cfuncp || (!cfuncp->isConstructor() && !cfuncp->isDestructor())) {
|
|
|
|
|
const std::string rsvd = V3LanguageWords::isKeyword(nodep->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (rsvd != "") {
|
|
|
|
|
// Generally V3Name should find all of these and throw SYMRSVDWORD.
|
|
|
|
|
// We'll still check here because the compiler errors
|
|
|
|
|
// resulting if we miss this warning are SO nasty
|
2020-04-15 01:55:00 +02:00
|
|
|
nodep->v3error("Symbol matching " + rsvd
|
|
|
|
|
+ " reserved word reached emitter,"
|
|
|
|
|
" should have hit SYMRSVDWORD: "
|
|
|
|
|
<< nodep->prettyNameQ());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
static std::string scopeSymString(const std::string& scpname) {
|
|
|
|
|
std::string out = scpname;
|
|
|
|
|
std::string::size_type pos;
|
|
|
|
|
while ((pos = out.find("__PVT__")) != std::string::npos) out.replace(pos, 7, "");
|
|
|
|
|
if (VString::startsWith(out, "TOP__DOT__")) out.replace(0, 10, "");
|
|
|
|
|
if (VString::startsWith(out, "TOP.")) out.replace(0, 4, "");
|
|
|
|
|
while ((pos = out.find('.')) != std::string::npos) out.replace(pos, 1, "__");
|
|
|
|
|
while ((pos = out.find("__DOT__")) != std::string::npos) out.replace(pos, 7, "__");
|
2019-10-02 03:57:45 +02:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
static string scopeDecodeIdentifier(const std::string& scpname) {
|
|
|
|
|
std::string::size_type pos = std::string::npos;
|
2023-11-07 13:47:55 +01:00
|
|
|
|
2019-10-02 03:57:45 +02:00
|
|
|
// Remove hierarchy
|
2023-11-07 13:47:55 +01:00
|
|
|
size_t i = 0;
|
|
|
|
|
// always makes progress
|
|
|
|
|
while (i < scpname.length()) {
|
|
|
|
|
if (scpname[i] == '\\') {
|
|
|
|
|
while (i < scpname.length() && scpname[i] != ' ') ++i;
|
|
|
|
|
++i; // Proc ' ', it should always be there. Then grab '.' on next cycle
|
|
|
|
|
} else {
|
|
|
|
|
while (i < scpname.length() && scpname[i] != '.') ++i;
|
|
|
|
|
if (i < scpname.length()) pos = i++;
|
2023-02-01 23:30:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
return pos != std::string::npos ? scpname.substr(pos + 1) : scpname;
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
|
|
|
|
|
2024-03-19 01:47:28 +01:00
|
|
|
/// (scp, m_vpiScopeCandidates, m_scopeNames) -> m_scopeNames
|
|
|
|
|
/// Look for parent scopes of scp in m_vpiScopeCandidates (separated by __DOT__ or ".")
|
|
|
|
|
/// Then add/update entry in m_scopeNames if not already there
|
2025-11-05 00:00:26 +01:00
|
|
|
void varHierarchyScopes(std::string scp) {
|
2024-03-19 01:47:28 +01:00
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
std::string::size_type prd_pos = scp.rfind('.');
|
|
|
|
|
std::string::size_type dot_pos = scp.rfind("__DOT__");
|
2024-03-19 01:47:28 +01:00
|
|
|
|
2019-10-02 03:57:45 +02:00
|
|
|
while (!scp.empty()) {
|
2023-02-05 22:16:39 +01:00
|
|
|
const auto scpit = m_vpiScopeCandidates.find(scopeSymString(scp));
|
2019-10-02 03:57:45 +02:00
|
|
|
if ((scpit != m_vpiScopeCandidates.end())
|
2020-04-15 01:55:00 +02:00
|
|
|
&& (m_scopeNames.find(scp) == m_scopeNames.end())) {
|
2023-10-28 14:38:02 +02:00
|
|
|
// If not in m_scopeNames, add it, otherwise just update m_type
|
|
|
|
|
const auto pair = m_scopeNames.emplace(scpit->second.m_symName, scpit->second);
|
|
|
|
|
if (!pair.second) pair.first->second.m_type = scpit->second.m_type;
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
2024-03-19 01:47:28 +01:00
|
|
|
|
|
|
|
|
// resize and advance pointers
|
2025-01-13 13:40:34 +01:00
|
|
|
if ((prd_pos < dot_pos || prd_pos == string::npos) && dot_pos != string::npos) {
|
2024-03-19 01:47:28 +01:00
|
|
|
scp.resize(dot_pos);
|
|
|
|
|
dot_pos = scp.rfind("__DOT__");
|
|
|
|
|
} else {
|
|
|
|
|
if (prd_pos == string::npos) break;
|
|
|
|
|
scp.resize(prd_pos);
|
|
|
|
|
prd_pos = scp.rfind('.');
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-17 13:22:49 +01:00
|
|
|
void varsExpand() {
|
2019-09-09 13:50:21 +02:00
|
|
|
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
|
2019-05-19 22:13:13 +02:00
|
|
|
// It would be less code if each module inserted its own variables.
|
2025-01-16 21:02:36 +01:00
|
|
|
// Someday.
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const ScopeModPair& smPair : m_scopes) {
|
|
|
|
|
const AstScope* const scopep = smPair.first;
|
|
|
|
|
const AstNodeModule* const smodp = smPair.second;
|
|
|
|
|
for (const ModVarPair& mvPair : m_modVars) {
|
|
|
|
|
const AstNodeModule* const modp = mvPair.first;
|
|
|
|
|
const AstVar* const varp = mvPair.second;
|
|
|
|
|
if (modp != smodp) continue;
|
|
|
|
|
|
|
|
|
|
// Need to split the module + var name into the
|
|
|
|
|
// original-ish full scope and variable name under that scope.
|
|
|
|
|
// The module instance name is included later, when we
|
|
|
|
|
// know the scopes this module is under
|
|
|
|
|
std::string whole = scopep->name() + "__DOT__" + varp->name();
|
|
|
|
|
std::string scpName;
|
|
|
|
|
std::string varBase;
|
|
|
|
|
if (VString::startsWith(whole, "__DOT__TOP")) whole.replace(0, 10, "");
|
|
|
|
|
const std::string::size_type dpos = whole.rfind("__DOT__");
|
|
|
|
|
if (dpos != std::string::npos) {
|
|
|
|
|
scpName = whole.substr(0, dpos);
|
|
|
|
|
varBase = whole.substr(dpos + std::strlen("__DOT__"));
|
|
|
|
|
} else {
|
|
|
|
|
varBase = whole;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
// UINFO(9, "For " << scopep->name() << " - " << varp->name() << " Scp "
|
|
|
|
|
// << scpName << "Var " << varBase);
|
|
|
|
|
const std::string varBasePretty = AstNode::vpiName(VName::dehash(varBase));
|
|
|
|
|
const std::string scpPretty = AstNode::prettyName(VName::dehash(scpName));
|
|
|
|
|
const std::string scpSym = scopeSymString(VName::dehash(scpName));
|
|
|
|
|
// UINFO(9, " scnameins sp " << scpName << " sp " << scpPretty << " ss "
|
|
|
|
|
// << scpSym);
|
|
|
|
|
if (v3Global.opt.vpi()) varHierarchyScopes(scpName);
|
|
|
|
|
|
|
|
|
|
m_scopeNames.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(scpSym), //
|
|
|
|
|
std::forward_as_tuple(varp, scpSym, scpPretty, "<null>", 0, "SCOPE_OTHER"));
|
|
|
|
|
|
|
|
|
|
m_scopeVars.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(scpSym + " " + varp->name()), //
|
|
|
|
|
std::forward_as_tuple(scpSym, varBasePretty, varp, modp, scopep));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-03-17 13:22:49 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-02 03:57:45 +02:00
|
|
|
void buildVpiHierarchy() {
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const auto& itpair : m_scopeNames) {
|
|
|
|
|
const std::string symName = itpair.second.m_symName;
|
|
|
|
|
std::string above = symName;
|
|
|
|
|
if (VString::startsWith(above, "TOP.")) above.replace(0, 4, "");
|
2019-10-02 03:57:45 +02:00
|
|
|
|
|
|
|
|
while (!above.empty()) {
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string::size_type pos = above.rfind("__");
|
|
|
|
|
if (pos == std::string::npos) break;
|
2019-10-02 03:57:45 +02:00
|
|
|
above.resize(pos);
|
|
|
|
|
if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) {
|
2021-04-26 15:50:25 +02:00
|
|
|
m_vpiScopeHierarchy[above].push_back(symName);
|
2019-10-02 03:57:45 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-26 15:50:25 +02:00
|
|
|
m_vpiScopeHierarchy[symName] = std::vector<string>();
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Collect list of scopes
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateChildrenConst(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
varsExpand();
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.vpi()) buildVpiHierarchy();
|
2019-10-02 03:57:45 +02:00
|
|
|
|
2025-01-16 21:02:36 +01:00
|
|
|
if (v3Global.dpi()) {
|
|
|
|
|
// add dpi scopes to m_scopeNames if not already there
|
2025-08-21 10:43:37 +02:00
|
|
|
for (const auto& scp : m_dpiScopeNames) m_scopeNames.emplace(scp.first, scp.second);
|
2025-01-16 21:02:36 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Sort by names, so line/process order matters less
|
2025-11-05 00:00:26 +01:00
|
|
|
std::stable_sort(m_scopes.begin(), m_scopes.end(),
|
|
|
|
|
[](const ScopeModPair& a, const ScopeModPair& b) {
|
|
|
|
|
return a.first->name() < b.first->name();
|
|
|
|
|
});
|
|
|
|
|
std::stable_sort(m_dpis.begin(), m_dpis.end(), //
|
|
|
|
|
[](const AstCFunc* ap, const AstCFunc* bp) {
|
|
|
|
|
if (ap->dpiImportPrototype() != bp->dpiImportPrototype()) {
|
|
|
|
|
return bp->dpiImportPrototype();
|
|
|
|
|
}
|
|
|
|
|
return ap->name() < bp->name();
|
|
|
|
|
});
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Output
|
2019-08-28 03:36:59 +02:00
|
|
|
if (!m_dpiHdrOnly) {
|
2019-09-04 12:15:41 +02:00
|
|
|
// Must emit implementation first to determine number of splits
|
2025-11-08 11:36:12 +01:00
|
|
|
emitSymImp(nodep);
|
2019-09-04 12:15:41 +02:00
|
|
|
emitSymHdr();
|
2019-08-28 03:36:59 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (v3Global.dpi()) {
|
|
|
|
|
emitDpiHdr();
|
2019-08-28 03:36:59 +02:00
|
|
|
if (!m_dpiHdrOnly) emitDpiImp();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConstPool* nodep) override {} // Ignore
|
|
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
nameCheck(nodep);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modp);
|
2024-11-10 16:51:48 +01:00
|
|
|
m_modp = nodep;
|
|
|
|
|
iterateChildrenConst(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2024-04-02 05:11:15 +02:00
|
|
|
void visit(AstCellInlineScope* nodep) override {
|
2025-11-05 00:00:26 +01:00
|
|
|
if (!v3Global.opt.vpi()) return;
|
|
|
|
|
|
|
|
|
|
const std::string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" //
|
|
|
|
|
: "SCOPE_MODULE";
|
|
|
|
|
const std::string name = nodep->scopep()->shortName() + "__DOT__" + nodep->name();
|
|
|
|
|
const int timeunit = m_modp->timeunit().powerOfTen();
|
|
|
|
|
m_vpiScopeCandidates.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(scopeSymString(name)), //
|
|
|
|
|
std::forward_as_tuple(nodep, scopeSymString(name), AstNode::vpiName(name),
|
|
|
|
|
type == "SCOPE_MODULE" ? nodep->origModName() : "<null>",
|
|
|
|
|
timeunit, type));
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstScope* nodep) override {
|
2020-04-05 15:30:23 +02:00
|
|
|
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
|
2019-05-19 22:13:13 +02:00
|
|
|
nameCheck(nodep);
|
2019-10-02 03:57:45 +02:00
|
|
|
|
2023-10-28 12:24:04 +02:00
|
|
|
m_scopes.emplace_back(nodep, m_modp);
|
2019-10-02 03:57:45 +02:00
|
|
|
|
|
|
|
|
if (v3Global.opt.vpi() && !nodep->isTop()) {
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string type = VN_IS(nodep->modp(), Package) ? "SCOPE_PACKAGE" //
|
|
|
|
|
: "SCOPE_MODULE";
|
2021-06-21 00:32:57 +02:00
|
|
|
const int timeunit = m_modp->timeunit().powerOfTen();
|
2025-11-05 00:00:26 +01:00
|
|
|
m_vpiScopeCandidates.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(scopeSymString(nodep->name())), //
|
|
|
|
|
std::forward_as_tuple(nodep, scopeSymString(nodep->name()),
|
|
|
|
|
AstNode::vpiName(nodep->shortName()),
|
|
|
|
|
nodep->modp()->origName(), timeunit, type));
|
2019-10-02 03:57:45 +02:00
|
|
|
}
|
2024-04-02 05:11:15 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstScopeName* nodep) override {
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string name = nodep->scopeSymName();
|
2023-02-05 22:16:39 +01:00
|
|
|
// UINFO(9, "scnameins sp " << nodep->name() << " sp " << nodep->scopePrettySymName()
|
2025-05-23 02:29:32 +02:00
|
|
|
// << " ss" << name);
|
2021-06-21 00:32:57 +02:00
|
|
|
const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0;
|
2025-11-05 00:00:26 +01:00
|
|
|
m_dpiScopeNames.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(name), //
|
|
|
|
|
std::forward_as_tuple(nodep, name, nodep->scopePrettySymName(), "<null>", timeunit,
|
|
|
|
|
"SCOPE_OTHER"));
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->dpiExport()) {
|
2020-10-31 13:59:35 +01:00
|
|
|
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
|
2025-11-05 00:00:26 +01:00
|
|
|
m_scopeFuncs.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(name + " " + m_cfuncp->name()), //
|
|
|
|
|
std::forward_as_tuple(nodep, m_cfuncp, m_modp));
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2025-11-05 00:00:26 +01:00
|
|
|
// Note emplace does not construct when duplicate key
|
|
|
|
|
m_dpiScopeNames.emplace( //
|
|
|
|
|
std::piecewise_construct, //
|
|
|
|
|
std::forward_as_tuple(nodep->scopeDpiName()), //
|
|
|
|
|
std::forward_as_tuple(nodep, nodep->scopeDpiName(), nodep->scopePrettyDpiName(),
|
|
|
|
|
"<null>", timeunit, "SCOPE_OTHER"));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
nameCheck(nodep);
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateChildrenConst(nodep);
|
2025-11-05 00:00:26 +01:00
|
|
|
// Record if public, ignoring locals
|
|
|
|
|
if ((nodep->isSigUserRdPublic() || nodep->isSigUserRWPublic()) && !m_cfuncp) {
|
2025-02-15 06:52:41 +01:00
|
|
|
m_modVars.emplace_back(m_modp, nodep);
|
2025-11-05 00:00:26 +01:00
|
|
|
}
|
2010-03-17 13:22:49 +01:00
|
|
|
}
|
2025-08-04 14:29:56 +02:00
|
|
|
void visit(AstNodeCoverDecl* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Assign numbers to all bins, so we know how big of an array to use
|
|
|
|
|
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
2025-08-04 14:29:56 +02:00
|
|
|
nodep->binNum(m_coverBins);
|
|
|
|
|
m_coverBins += nodep->size();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2008-12-05 16:54:14 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCFunc* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
nameCheck(nodep);
|
2021-06-10 23:41:33 +02:00
|
|
|
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) m_dpis.push_back(nodep);
|
2020-10-31 13:59:35 +01:00
|
|
|
VL_RESTORER(m_cfuncp);
|
2024-11-10 16:51:48 +01:00
|
|
|
m_cfuncp = nodep;
|
|
|
|
|
iterateChildrenConst(nodep);
|
2009-12-09 04:12:59 +01:00
|
|
|
}
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//---------------------------------------
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConst*) override {}
|
2023-03-18 17:17:25 +01:00
|
|
|
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-04-04 14:31:14 +02:00
|
|
|
explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_dpiHdrOnly{dpiHdrOnly} {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2009-12-09 04:12:59 +01:00
|
|
|
void EmitCSyms::emitSymHdr() {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(6, __FUNCTION__ << ": ");
|
2025-11-09 18:41:13 +01:00
|
|
|
openNewOutputHeaderFile(symClassName(), "Symbol table internal header");
|
2009-12-03 02:09:13 +01:00
|
|
|
puts("//\n");
|
2019-07-07 15:00:57 +02:00
|
|
|
puts("// Internal details; most calling programs do not need this header,\n");
|
|
|
|
|
puts("// unless using verilator public meta comments.\n");
|
2009-12-03 02:09:13 +01:00
|
|
|
|
2019-12-24 01:00:17 +01:00
|
|
|
ofp()->putsGuard();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-12-24 01:00:17 +01:00
|
|
|
puts("\n");
|
2017-02-09 13:43:43 +01:00
|
|
|
ofp()->putsIntTopInclude();
|
2021-07-24 16:00:33 +02:00
|
|
|
puts("#include \"verilated.h\"\n");
|
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 16:30:20 +02:00
|
|
|
if (v3Global.needTraceDumper()) {
|
2025-09-28 02:54:26 +02:00
|
|
|
for (const string& base : v3Global.opt.traceSourceLangs())
|
|
|
|
|
puts("#include \"" + base + ".h\"\n");
|
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 16:30:20 +02:00
|
|
|
}
|
2022-03-25 20:46:50 +01:00
|
|
|
if (v3Global.opt.usesProfiler()) puts("#include \"verilated_profiler.h\"\n");
|
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 16:30:20 +02:00
|
|
|
|
|
|
|
|
puts("\n// INCLUDE MODEL CLASS\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts("\n#include \"" + topClassName() + ".h\"\n");
|
2010-01-17 21:10:37 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
puts("\n// INCLUDE MODULE CLASSES\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
for (AstNodeModule *nodep = v3Global.rootp()->modulesp(), *nextp; nodep; nodep = nextp) {
|
|
|
|
|
nextp = VN_AS(nodep->nextp(), NodeModule);
|
2020-04-05 15:30:23 +02:00
|
|
|
if (VN_IS(nodep, Class)) continue; // Class included earlier
|
2025-08-26 04:05:40 +02:00
|
|
|
putns(nodep, "#include \"" + EmitCUtil::prefixNameProtect(nodep) + ".h\"\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-20 14:27:00 +01:00
|
|
|
if (v3Global.dpi()) {
|
2018-08-25 15:52:45 +02:00
|
|
|
puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
std::set<std::string> types; // Remove duplicates and sort
|
|
|
|
|
for (const auto& itpair : m_scopeFuncs) {
|
|
|
|
|
const AstCFunc* const funcp = itpair.second.m_cfuncp;
|
|
|
|
|
if (!funcp->dpiExportImpl()) continue;
|
|
|
|
|
const std::string cbtype
|
|
|
|
|
= protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
|
|
|
|
|
const std::string functype = funcp->rtnTypeVoid() + " (*) (" + cFuncArgs(funcp) + ")";
|
|
|
|
|
types.emplace("using " + cbtype + " = " + functype + ";\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const std::string& type : types) puts(type);
|
2009-12-20 14:27:00 +01:00
|
|
|
}
|
|
|
|
|
|
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 16:30:20 +02:00
|
|
|
puts("\n// SYMS CLASS (contains all model state)\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts("class alignas(VL_CACHE_LINE_BYTES) " + symClassName()
|
2023-05-03 03:21:10 +02:00
|
|
|
+ " final : public VerilatedSyms {\n");
|
2006-08-30 23:07:55 +02:00
|
|
|
ofp()->putsPrivate(false); // public:
|
2006-08-26 13:35:28 +02:00
|
|
|
|
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 16:30:20 +02:00
|
|
|
puts("// INTERNAL STATE\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts(topClassName() + "* const __Vm_modelp;\n");
|
2020-04-15 01:55:00 +02:00
|
|
|
|
2020-03-02 03:39:23 +01:00
|
|
|
if (v3Global.needTraceDumper()) {
|
|
|
|
|
// __Vm_dumperp is local, otherwise we wouldn't know what design's eval()
|
|
|
|
|
// should call a global dumpperp
|
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 16:30:20 +02:00
|
|
|
puts("bool __Vm_dumping = false; // Dumping is active\n");
|
2020-03-02 03:39:23 +01:00
|
|
|
puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n");
|
|
|
|
|
puts(v3Global.opt.traceClassLang()
|
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 16:30:20 +02:00
|
|
|
+ "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex) = nullptr;"
|
|
|
|
|
" /// Trace class for $dump*\n");
|
2020-03-02 03:39:23 +01:00
|
|
|
}
|
2017-09-23 04:27:03 +02:00
|
|
|
if (v3Global.opt.trace()) {
|
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 16:30:20 +02:00
|
|
|
puts("bool __Vm_activity = false;"
|
|
|
|
|
" ///< Used by trace routines to determine change occurred\n");
|
|
|
|
|
puts("uint32_t __Vm_baseCode = 0;"
|
|
|
|
|
" ///< Used by trace routines when tracing multiple models\n");
|
|
|
|
|
}
|
2023-10-26 16:38:47 +02:00
|
|
|
if (v3Global.hasEvents()) {
|
|
|
|
|
if (v3Global.assignsEvents()) {
|
|
|
|
|
puts("std::vector<VlAssignableEvent> __Vm_triggeredEvents;\n");
|
|
|
|
|
} else {
|
|
|
|
|
puts("std::vector<VlEvent*> __Vm_triggeredEvents;\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-29 00:54:18 +02:00
|
|
|
if (v3Global.hasClasses()) puts("VlDeleter __Vm_deleter;\n");
|
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 16:30:20 +02:00
|
|
|
puts("bool __Vm_didInit = false;\n");
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.mtasks()) {
|
2022-03-25 20:46:50 +01:00
|
|
|
puts("\n// MULTI-THREADING\n");
|
2023-08-30 13:02:55 +02:00
|
|
|
puts("VlThreadPool* __Vm_threadPoolp;\n");
|
2022-09-06 15:59:40 +02:00
|
|
|
puts("bool __Vm_even_cycle__ico = false;\n");
|
|
|
|
|
puts("bool __Vm_even_cycle__act = false;\n");
|
|
|
|
|
puts("bool __Vm_even_cycle__nba = false;\n");
|
2017-09-23 04:27:03 +02:00
|
|
|
}
|
2006-08-30 03:14:29 +02:00
|
|
|
|
2022-07-12 12:41:15 +02:00
|
|
|
if (v3Global.opt.profExec()) {
|
|
|
|
|
puts("\n// EXECUTION PROFILING\n");
|
|
|
|
|
puts("VlExecutionProfiler* const __Vm_executionProfilerp;\n");
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-13 16:19:00 +02:00
|
|
|
if (v3Global.opt.profPgo()) {
|
|
|
|
|
puts("\n// PGO PROFILING\n");
|
|
|
|
|
puts("VlPgoProfiler<" + std::to_string(ExecMTask::numUsedIds()) + "> _vm_pgoProfiler;\n");
|
|
|
|
|
}
|
|
|
|
|
|
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 16:30:20 +02:00
|
|
|
puts("\n// MODULE INSTANCE STATE\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const ScopeModPair& itpair : m_scopes) {
|
|
|
|
|
const AstScope* const scopep = itpair.first;
|
|
|
|
|
const AstNodeModule* const modp = itpair.second;
|
2020-04-05 15:30:23 +02:00
|
|
|
if (VN_IS(modp, Class)) continue;
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string name = EmitCUtil::prefixNameProtect(modp);
|
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 16:30:20 +02:00
|
|
|
ofp()->printf("%-30s ", name.c_str());
|
2025-08-26 04:05:40 +02:00
|
|
|
putns(scopep, VIdProtect::protectIf(scopep->nameDotless(), scopep->protect()) + ";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-05 16:54:14 +01:00
|
|
|
if (m_coverBins) {
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("\n// COVERAGE\n");
|
2023-10-21 14:53:56 +02:00
|
|
|
puts(v3Global.opt.threads() > 1 ? "std::atomic<uint32_t>" : "uint32_t");
|
2020-02-04 00:43:41 +01:00
|
|
|
puts(" __Vcoverage[");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts(std::to_string(m_coverBins));
|
2020-02-04 00:43:41 +01:00
|
|
|
puts("];\n");
|
2008-12-05 16:54:14 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-02 03:57:45 +02:00
|
|
|
if (!m_scopeNames.empty()) { // Scope names
|
|
|
|
|
puts("\n// SCOPE NAMES\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const auto& itpair : m_scopeNames) {
|
|
|
|
|
const ScopeData& sd = itpair.second;
|
2025-11-08 16:56:15 +01:00
|
|
|
putns(sd.m_nodep, "VerilatedScope* " + protect("__Vscopep_" + sd.m_symName) + ";\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-02 03:57:45 +02:00
|
|
|
if (v3Global.opt.vpi()) {
|
|
|
|
|
puts("\n// SCOPE HIERARCHY\n");
|
|
|
|
|
puts("VerilatedHierarchy __Vhier;\n");
|
|
|
|
|
}
|
|
|
|
|
|
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 16:30:20 +02:00
|
|
|
puts("\n// CONSTRUCTORS\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts(symClassName() + "(VerilatedContext* contextp, const char* namep, " + topClassName()
|
|
|
|
|
+ "* modelp);\n");
|
|
|
|
|
puts("~" + symClassName() + "();\n");
|
2006-08-30 23:07:55 +02:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
for (const std::string& funcName : m_splitFuncNames) { puts("void " + funcName + "();\n"); }
|
2019-09-04 12:15:41 +02:00
|
|
|
|
2006-08-30 03:14:29 +02:00
|
|
|
puts("\n// METHODS\n");
|
2025-11-08 22:48:00 +01:00
|
|
|
puts("const char* name() const { return TOP.vlNamep; }\n");
|
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 16:30:20 +02:00
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
if (v3Global.hasEvents()) {
|
2023-10-26 16:38:47 +02:00
|
|
|
if (v3Global.assignsEvents()) {
|
2024-09-02 18:19:49 +02:00
|
|
|
puts("void fireEvent(VlAssignableEvent& event) {\n");
|
2023-10-26 16:38:47 +02:00
|
|
|
} else {
|
2024-09-02 18:19:49 +02:00
|
|
|
puts("void fireEvent(VlEvent& event) {\n");
|
2023-10-26 16:38:47 +02:00
|
|
|
}
|
2024-09-02 18:19:49 +02:00
|
|
|
puts("if (VL_LIKELY(!event.isTriggered())) {\n");
|
2023-10-26 16:38:47 +02:00
|
|
|
if (v3Global.assignsEvents()) {
|
|
|
|
|
puts("__Vm_triggeredEvents.push_back(event);\n");
|
|
|
|
|
} else {
|
|
|
|
|
puts("__Vm_triggeredEvents.push_back(&event);\n");
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
puts("}\n");
|
2024-09-02 18:19:49 +02:00
|
|
|
puts("event.fire();\n");
|
|
|
|
|
puts("}\n");
|
2022-05-15 17:03:32 +02:00
|
|
|
puts("void clearTriggeredEvents() {\n");
|
2023-10-26 16:38:47 +02:00
|
|
|
if (v3Global.assignsEvents()) {
|
|
|
|
|
puts("for (auto& event : __Vm_triggeredEvents) event.clearTriggered();\n");
|
|
|
|
|
} else {
|
|
|
|
|
puts("for (const auto eventp : __Vm_triggeredEvents) eventp->clearTriggered();\n");
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
puts("__Vm_triggeredEvents.clear();\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
}
|
|
|
|
|
|
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 16:30:20 +02:00
|
|
|
if (v3Global.needTraceDumper()) {
|
|
|
|
|
if (!optSystemC()) puts("void _traceDump();\n");
|
|
|
|
|
puts("void _traceDumpOpen();\n");
|
|
|
|
|
puts("void _traceDumpClose();\n");
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.savable()) {
|
|
|
|
|
puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n");
|
|
|
|
|
puts("void " + protect("__Vdeserialize") + "(VerilatedDeserialize& os);\n");
|
2012-08-27 03:13:47 +02:00
|
|
|
}
|
2023-05-03 03:21:10 +02:00
|
|
|
puts("};\n");
|
2019-12-24 01:00:17 +01:00
|
|
|
|
|
|
|
|
ofp()->putsEndGuard();
|
2024-10-01 03:42:36 +02:00
|
|
|
closeOutputFile();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-04 12:15:41 +02:00
|
|
|
void EmitCSyms::emitSymImpPreamble() {
|
2006-08-26 13:35:28 +02:00
|
|
|
puts("\n");
|
|
|
|
|
|
|
|
|
|
// Includes
|
2025-08-26 04:05:40 +02:00
|
|
|
puts("#include \"" + EmitCUtil::pchClassName() + ".h\"\n");
|
2021-06-10 23:41:33 +02:00
|
|
|
puts("\n");
|
|
|
|
|
// Declarations for DPI Export implementation functions
|
|
|
|
|
bool needsNewLine = false;
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const auto& itpair : m_scopeFuncs) {
|
|
|
|
|
const AstCFunc* const funcp = itpair.second.m_cfuncp;
|
2021-06-10 23:41:33 +02:00
|
|
|
if (!funcp->dpiExportImpl()) continue;
|
2025-11-05 00:00:26 +01:00
|
|
|
emitCFuncDecl(funcp, itpair.second.m_modp);
|
2021-06-10 23:41:33 +02:00
|
|
|
needsNewLine = true;
|
|
|
|
|
}
|
|
|
|
|
if (needsNewLine) puts("\n");
|
2019-09-04 12:15:41 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
void EmitCSyms::emitScopeHier(std::vector<std::string>& stmts, bool destroy) {
|
2025-11-05 00:00:26 +01:00
|
|
|
if (!v3Global.opt.vpi()) return;
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
if (destroy) {
|
|
|
|
|
stmts.emplace_back("// Tear down scope hierarchy");
|
|
|
|
|
} else {
|
|
|
|
|
stmts.emplace_back("// Set up scope hierarchy");
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string method = destroy ? "remove" : "add";
|
|
|
|
|
for (const auto& itpair : m_scopeNames) {
|
|
|
|
|
if (itpair.first == "TOP") continue;
|
|
|
|
|
const ScopeData& sd = itpair.second;
|
|
|
|
|
const std::string& name = sd.m_prettyName;
|
|
|
|
|
const std::string& scopeType = sd.m_type;
|
|
|
|
|
if (name.find('.') != string::npos) continue;
|
|
|
|
|
if (scopeType != "SCOPE_MODULE" && scopeType != "SCOPE_PACKAGE") continue;
|
2025-11-08 16:56:15 +01:00
|
|
|
const std::string id = protect("__Vscopep_" + sd.m_symName);
|
|
|
|
|
stmts.emplace_back("__Vhier." + method + "(0, " + id + ");");
|
2025-11-05 00:00:26 +01:00
|
|
|
}
|
|
|
|
|
for (const auto& itpair : m_vpiScopeHierarchy) {
|
2025-11-08 11:36:12 +01:00
|
|
|
const std::string fromName = scopeSymString(itpair.first);
|
2025-11-08 16:56:15 +01:00
|
|
|
const std::string fromId = protect("__Vscopep_" + m_scopeNames.at(fromName).m_symName);
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const std::string& name : itpair.second) {
|
2025-11-08 11:36:12 +01:00
|
|
|
const std::string toName = scopeSymString(name);
|
2025-11-08 16:56:15 +01:00
|
|
|
const std::string toId = protect("__Vscopep_" + m_scopeNames.at(toName).m_symName);
|
|
|
|
|
stmts.emplace_back("__Vhier." + method + "(" + fromId + ", " + toId + ");");
|
2020-12-17 18:21:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-07 21:42:29 +01:00
|
|
|
|
|
|
|
|
if (destroy) {
|
|
|
|
|
stmts.emplace_back("// Clear keys from hierarchy map after values have been removed");
|
|
|
|
|
stmts.emplace_back("__Vhier.clear();");
|
|
|
|
|
}
|
2020-12-17 18:21:40 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
std::vector<std::string> EmitCSyms::getSymCtorStmts() {
|
|
|
|
|
std::vector<std::string> stmts;
|
2021-09-27 04:51:11 +02:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
const auto add = [&stmts](const std::string& stmt) { stmts.emplace_back(stmt); };
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2024-01-06 22:14:58 +01:00
|
|
|
{
|
|
|
|
|
uint64_t stackSize = V3StackCount::count(v3Global.rootp());
|
|
|
|
|
if (v3Global.opt.debugStackCheck()) stackSize += 1024 * 1024 * 1024;
|
2024-03-24 14:14:31 +01:00
|
|
|
V3Stats::addStat("Size prediction, Stack (bytes)", stackSize);
|
2025-10-03 12:49:13 +02:00
|
|
|
// TODO: 'm_statVarScopeBytes' is always 0, AstVarScope doesn't reach here (V3Descope)
|
2024-03-24 14:14:31 +01:00
|
|
|
V3Stats::addStat("Size prediction, Heap, from Var Scopes (bytes)", m_statVarScopeBytes);
|
|
|
|
|
V3Stats::addStat(V3Stats::STAT_MODEL_SIZE, stackSize + m_statVarScopeBytes);
|
2025-11-08 11:36:12 +01:00
|
|
|
|
|
|
|
|
add("// Check resources");
|
|
|
|
|
add("Verilated::stackCheck(" + std::to_string(stackSize) + ");");
|
2024-01-06 22:14:58 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Setup sub module instances");
|
2025-11-07 20:57:10 +01:00
|
|
|
for (const ScopeModPair& itpair : m_scopes) {
|
|
|
|
|
const AstScope* const scopep = itpair.first;
|
|
|
|
|
const AstNodeModule* const modp = itpair.second;
|
|
|
|
|
if (modp->isTop()) continue;
|
2025-11-08 11:36:12 +01:00
|
|
|
const std::string name = V3OutFormatter::quoteNameControls(
|
|
|
|
|
VIdProtect::protectWordsIf(scopep->prettyName(), scopep->protect()));
|
|
|
|
|
add(protect(scopep->nameDotless()) + ".ctor(this, \"" + name + "\");");
|
2025-11-07 20:57:10 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-25 20:46:50 +01:00
|
|
|
if (v3Global.opt.profPgo()) {
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Configure profiling for PGO\n");
|
2025-09-13 16:19:00 +02:00
|
|
|
if (!v3Global.opt.hierChild()) {
|
2025-11-08 11:36:12 +01:00
|
|
|
add("_vm_pgoProfiler.writeHeader(_vm_contextp__->profVltFilename());");
|
2025-09-13 16:19:00 +02:00
|
|
|
}
|
2021-09-27 04:51:11 +02:00
|
|
|
if (v3Global.opt.mtasks()) {
|
2022-10-20 14:48:44 +02:00
|
|
|
v3Global.rootp()->topModulep()->foreach([&](const AstExecGraph* execGraphp) {
|
2024-03-26 00:06:25 +01:00
|
|
|
for (const V3GraphVertex& vtx : execGraphp->depGraphp()->vertices()) {
|
|
|
|
|
const ExecMTask& mt = static_cast<const ExecMTask&>(vtx);
|
2025-11-08 11:36:12 +01:00
|
|
|
add("_vm_pgoProfiler.addCounter(" + std::to_string(mt.id()) + ", \""
|
|
|
|
|
+ mt.hashName() + "\");");
|
2022-10-20 14:48:44 +02:00
|
|
|
}
|
|
|
|
|
});
|
2021-09-27 04:51:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Configure time unit / time precision");
|
2021-06-19 18:12:56 +02:00
|
|
|
if (!v3Global.rootp()->timeunit().isNone()) {
|
2025-11-08 11:36:12 +01:00
|
|
|
const std::string unit = std::to_string(v3Global.rootp()->timeunit().powerOfTen());
|
|
|
|
|
add("_vm_contextp__->timeunit(" + unit + ");");
|
2021-06-19 18:12:56 +02:00
|
|
|
}
|
|
|
|
|
if (!v3Global.rootp()->timeprecision().isNone()) {
|
2025-11-08 11:36:12 +01:00
|
|
|
const std::string prec = std::to_string(v3Global.rootp()->timeprecision().powerOfTen());
|
|
|
|
|
add("_vm_contextp__->timeprecision(" + prec + ");");
|
2021-06-19 18:12:56 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Setup each module's pointers to their submodules");
|
2020-10-30 23:00:40 +01:00
|
|
|
for (const auto& i : m_scopes) {
|
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 16:30:20 +02:00
|
|
|
const AstScope* const scopep = i.first;
|
|
|
|
|
const AstNodeModule* const modp = i.second;
|
2025-11-05 00:00:26 +01:00
|
|
|
const AstScope* const abovep = scopep->aboveScopep();
|
|
|
|
|
if (!abovep) continue;
|
|
|
|
|
|
|
|
|
|
const std::string protName = VIdProtect::protectWordsIf(scopep->name(), scopep->protect());
|
2025-11-08 11:36:12 +01:00
|
|
|
std::string stmt;
|
2025-11-05 00:00:26 +01:00
|
|
|
if (VN_IS(modp, ClassPackage)) {
|
|
|
|
|
// ClassPackage modules seem to be a bit out of place, so hard code...
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += "TOP";
|
2025-11-05 00:00:26 +01:00
|
|
|
} else {
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += VIdProtect::protectIf(abovep->nameDotless(), abovep->protect());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += ".";
|
|
|
|
|
stmt += protName.substr(protName.rfind('.') + 1);
|
|
|
|
|
stmt += " = &";
|
|
|
|
|
stmt += VIdProtect::protectIf(scopep->nameDotless(), scopep->protect()) + ";";
|
|
|
|
|
add(stmt);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Setup each module's pointer back to symbol table (for public functions)");
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const ScopeModPair& i : m_scopes) {
|
|
|
|
|
const AstScope* const scopep = i.first;
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNodeModule* const modp = i.second;
|
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 16:30:20 +02:00
|
|
|
// first is used by AstCoverDecl's call to __vlCoverInsert
|
|
|
|
|
const bool first = !modp->user1();
|
|
|
|
|
modp->user1(true);
|
2025-11-08 11:36:12 +01:00
|
|
|
add(VIdProtect::protectIf(scopep->nameDotless(), scopep->protect()) + "."
|
|
|
|
|
+ protect("__Vconfigure") + "(" + (first ? "true" : "false") + ");");
|
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 16:30:20 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Setup scopes");
|
|
|
|
|
for (const auto& itpair : m_scopeNames) {
|
|
|
|
|
const ScopeData& sd = itpair.second;
|
|
|
|
|
std::string stmt;
|
2025-11-08 22:48:00 +01:00
|
|
|
stmt += protect("__Vscopep_" + sd.m_symName) + " = new VerilatedScope{this, \"";
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += V3OutFormatter::quoteNameControls(
|
|
|
|
|
VIdProtect::protectWordsIf(sd.m_prettyName, true));
|
|
|
|
|
stmt += "\", \"";
|
|
|
|
|
stmt += V3OutFormatter::quoteNameControls(protect(scopeDecodeIdentifier(sd.m_prettyName)));
|
|
|
|
|
stmt += "\", \"";
|
|
|
|
|
stmt += V3OutFormatter::quoteNameControls(sd.m_defName);
|
|
|
|
|
stmt += "\", ";
|
|
|
|
|
stmt += std::to_string(sd.m_timeunit);
|
2025-11-08 16:56:15 +01:00
|
|
|
stmt += ", VerilatedScope::" + sd.m_type + "};";
|
2025-11-08 11:36:12 +01:00
|
|
|
add(stmt);
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
emitScopeHier(stmts, false);
|
2019-09-04 12:15:41 +02:00
|
|
|
|
2025-11-08 14:29:44 +01:00
|
|
|
if (v3Global.dpi()) {
|
|
|
|
|
for (const std::string vfinal : {"0", "1"}) {
|
|
|
|
|
add("// Setup export functions - final: " + vfinal);
|
|
|
|
|
for (const auto& itpair : m_scopeFuncs) {
|
|
|
|
|
const ScopeFuncData& sfd = itpair.second;
|
|
|
|
|
const AstScopeName* const scopep = sfd.m_scopep;
|
|
|
|
|
const AstCFunc* const funcp = sfd.m_cfuncp;
|
|
|
|
|
const AstNodeModule* const modp = sfd.m_modp;
|
|
|
|
|
if (!funcp->dpiExportImpl()) continue;
|
|
|
|
|
|
|
|
|
|
std::string stmt;
|
2025-11-08 16:56:15 +01:00
|
|
|
stmt += protect("__Vscopep_" + scopep->scopeSymName()) + "->exportInsert(";
|
2025-11-08 14:29:44 +01:00
|
|
|
stmt += vfinal + ", \"";
|
|
|
|
|
// Not protected - user asked for import/export
|
|
|
|
|
stmt += V3OutFormatter::quoteNameControls(funcp->cname());
|
|
|
|
|
stmt += "\", (void*)(&";
|
|
|
|
|
stmt += EmitCUtil::prefixNameProtect(modp);
|
|
|
|
|
stmt += "__";
|
|
|
|
|
stmt += funcp->nameProtect();
|
|
|
|
|
stmt += "));";
|
|
|
|
|
add(stmt);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-08 14:29:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// It would be less code if each module inserted its own variables. Someday.
|
|
|
|
|
if (!m_scopeVars.empty()) {
|
|
|
|
|
add("// Setup public variables");
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const auto& itpair : m_scopeVars) {
|
|
|
|
|
const ScopeVarData& svd = itpair.second;
|
|
|
|
|
const AstScope* const scopep = svd.m_scopep;
|
|
|
|
|
const AstVar* const varp = svd.m_varp;
|
2019-05-19 22:13:13 +02:00
|
|
|
int pdim = 0;
|
|
|
|
|
int udim = 0;
|
2025-11-05 00:00:26 +01:00
|
|
|
std::string bounds;
|
|
|
|
|
if (const AstBasicDType* const basicp = varp->basicp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Range is always first, it's not in "C" order
|
2020-04-15 01:55:00 +02:00
|
|
|
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
|
2025-11-05 00:00:26 +01:00
|
|
|
// Skip AstRefDType/AstTypedef, or return same node
|
|
|
|
|
dtypep = dtypep->skipRefp();
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
2020-04-15 01:55:00 +02:00
|
|
|
bounds += " ,";
|
2025-11-05 00:00:26 +01:00
|
|
|
bounds += std::to_string(adtypep->left());
|
2020-04-15 01:55:00 +02:00
|
|
|
bounds += ",";
|
2025-11-05 00:00:26 +01:00
|
|
|
bounds += std::to_string(adtypep->right());
|
2025-01-10 01:04:26 +01:00
|
|
|
if (VN_IS(dtypep, PackArrayDType))
|
2020-04-15 01:55:00 +02:00
|
|
|
pdim++;
|
2025-01-10 01:04:26 +01:00
|
|
|
else
|
2020-04-15 01:55:00 +02:00
|
|
|
udim++;
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = adtypep->subDTypep();
|
2020-04-15 01:55:00 +02:00
|
|
|
} else {
|
2025-01-10 01:04:26 +01:00
|
|
|
if (basicp->isRanged()) {
|
|
|
|
|
bounds += " ,";
|
2025-11-05 00:00:26 +01:00
|
|
|
bounds += std::to_string(basicp->left());
|
2025-01-10 01:04:26 +01:00
|
|
|
bounds += ",";
|
2025-11-05 00:00:26 +01:00
|
|
|
bounds += std::to_string(basicp->right());
|
2025-01-10 01:04:26 +01:00
|
|
|
pdim++;
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
break; // AstBasicDType - nothing below, 1
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-10 01:04:26 +01:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
std::string stmt;
|
2025-11-08 16:56:15 +01:00
|
|
|
stmt += protect("__Vscopep_" + svd.m_scopeName) + "->varInsert(\"";
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += V3OutFormatter::quoteNameControls(protect(svd.m_varBasePretty)) + '"';
|
2020-06-13 00:38:01 +02:00
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
const std::string varName
|
|
|
|
|
= VIdProtect::protectIf(scopep->nameDotless(), scopep->protect()) + "."
|
|
|
|
|
+ protect(varp->name());
|
2020-06-13 00:38:01 +02:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
if (!varp->isParam()) {
|
|
|
|
|
stmt += ", &(";
|
|
|
|
|
stmt += varName;
|
|
|
|
|
stmt += "), false, ";
|
|
|
|
|
} else if (varp->vlEnumType() == "VLVT_STRING"
|
|
|
|
|
&& !VN_IS(varp->subDTypep(), UnpackArrayDType)) {
|
|
|
|
|
stmt += ", const_cast<void*>(static_cast<const void*>(";
|
|
|
|
|
stmt += varName;
|
|
|
|
|
stmt += ".c_str())), true, ";
|
2020-06-13 00:38:01 +02:00
|
|
|
} else {
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += ", const_cast<void*>(static_cast<const void*>(&(";
|
|
|
|
|
stmt += varName;
|
|
|
|
|
stmt += "))), true, ";
|
2020-06-13 00:38:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
stmt += varp->vlEnumType(); // VLVT_UINT32 etc
|
|
|
|
|
stmt += ", ";
|
|
|
|
|
stmt += varp->vlEnumDir(); // VLVD_IN etc
|
|
|
|
|
stmt += ", ";
|
|
|
|
|
stmt += std::to_string(udim);
|
|
|
|
|
stmt += ", ";
|
|
|
|
|
stmt += std::to_string(pdim);
|
|
|
|
|
stmt += bounds;
|
|
|
|
|
stmt += ");";
|
|
|
|
|
add(stmt);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-08 11:36:12 +01:00
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
return stmts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> EmitCSyms::getSymDtorStmts() {
|
|
|
|
|
std::vector<std::string> stmts;
|
|
|
|
|
|
|
|
|
|
const auto add = [&stmts](const std::string& stmt) { stmts.emplace_back(stmt); };
|
|
|
|
|
|
|
|
|
|
emitScopeHier(stmts, true);
|
|
|
|
|
if (v3Global.needTraceDumper()) add("if (__Vm_dumping) _traceDumpClose();");
|
|
|
|
|
if (v3Global.opt.profPgo()) {
|
|
|
|
|
add("_vm_pgoProfiler.write(\"" + topClassName()
|
|
|
|
|
+ "\", _vm_contextp__->profVltFilename());");
|
|
|
|
|
}
|
2025-11-08 16:56:15 +01:00
|
|
|
add("// Tear down scopes");
|
|
|
|
|
for (const auto& itpair : m_scopeNames) {
|
|
|
|
|
const ScopeData& sd = itpair.second;
|
|
|
|
|
const std::string id = protect("__Vscopep_" + sd.m_symName);
|
|
|
|
|
add("VL_DO_CLEAR(delete " + id + ", " + id + " = nullptr);");
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
add("// Tear down sub module instances");
|
|
|
|
|
for (const ScopeModPair& itpair : vlstd::reverse_view(m_scopes)) {
|
|
|
|
|
const AstScope* const scopep = itpair.first;
|
|
|
|
|
const AstNodeModule* const modp = itpair.second;
|
|
|
|
|
if (modp->isTop()) continue;
|
|
|
|
|
add(protect(scopep->nameDotless()) + ".dtor();");
|
|
|
|
|
}
|
|
|
|
|
return stmts;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 00:54:22 +01:00
|
|
|
void EmitCSyms::emitSplit(std::vector<std::string>& stmts, const std::string& name,
|
2025-11-08 11:36:12 +01:00
|
|
|
size_t maxCost) {
|
|
|
|
|
size_t nSubFunctions = 0;
|
|
|
|
|
// Reduce into a balanced tree of sub-function calls until we end up with a single statement
|
|
|
|
|
while (stmts.size() > 1) {
|
|
|
|
|
size_t nSplits = 0;
|
|
|
|
|
size_t nStmts = stmts.size();
|
|
|
|
|
for (size_t splitStart = 0, splitEnd = 0; splitStart < nStmts; splitStart = splitEnd) {
|
|
|
|
|
// Gather up at at most 'maxCost' worth of statements in this split,
|
|
|
|
|
// but always at least 2 (if less than 2, the reduction makes no
|
|
|
|
|
// progress and the loop will not terminate).
|
|
|
|
|
size_t cost = 0;
|
|
|
|
|
while (((cost < maxCost) || (splitEnd - splitStart < 2)) && splitEnd < nStmts) {
|
|
|
|
|
cost += stmtCost(stmts[splitEnd++]);
|
|
|
|
|
}
|
|
|
|
|
UASSERT(splitStart < splitEnd, "Empty split");
|
|
|
|
|
|
|
|
|
|
// Create new sub-function and emit current range of statementss
|
|
|
|
|
const std::string nStr = std::to_string(nSubFunctions++);
|
|
|
|
|
// Name of sub-function we are emitting now
|
|
|
|
|
const std::string funcName = symClassName() + "__" + name + "__" + nStr;
|
|
|
|
|
m_splitFuncNames.emplace_back(funcName);
|
|
|
|
|
// Open split file
|
2025-11-09 18:41:13 +01:00
|
|
|
openNewOutputSourceFile(funcName, true, true, "Symbol table implementation internals");
|
2025-11-08 11:36:12 +01:00
|
|
|
// Emit header
|
|
|
|
|
emitSymImpPreamble();
|
|
|
|
|
// Open sub-function definition in the split file
|
|
|
|
|
puts("void " + symClassName() + "::" + funcName + "() {\n");
|
|
|
|
|
|
|
|
|
|
// Emit statements
|
|
|
|
|
for (size_t j = splitStart; j < splitEnd; ++j) {
|
2025-11-09 18:41:13 +01:00
|
|
|
ofp()->putsNoTracking(" ");
|
|
|
|
|
ofp()->putsNoTracking(stmts[j]);
|
|
|
|
|
ofp()->putsNoTracking("\n");
|
2025-11-08 11:36:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close sub-function
|
|
|
|
|
puts("}\n");
|
|
|
|
|
// Close split file
|
|
|
|
|
closeOutputFile();
|
|
|
|
|
|
|
|
|
|
// Replace statements with a call to the sub-function
|
|
|
|
|
stmts[nSplits++] = funcName + "();";
|
|
|
|
|
}
|
|
|
|
|
// The statements at the front are now the calls to the sub-functions, drop the rest
|
|
|
|
|
stmts.resize(nSplits);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 00:54:22 +01:00
|
|
|
void EmitCSyms::emitSymImp(const AstNetlist* netlistp) {
|
2025-11-08 11:36:12 +01:00
|
|
|
UINFO(6, __FUNCTION__ << ": ");
|
|
|
|
|
|
|
|
|
|
// Get the body of the constructor and destructor
|
|
|
|
|
std::vector<std::string> ctorStmts = getSymCtorStmts();
|
|
|
|
|
std::vector<std::string> dtorStmts = getSymDtorStmts();
|
|
|
|
|
|
|
|
|
|
// Check if needs splitting and if so split into sub-functions
|
|
|
|
|
if (const size_t maxCost = static_cast<size_t>(v3Global.opt.outputSplitCFuncs())) {
|
|
|
|
|
size_t totalCost = 200; // Starting from 200 to consider all other contents in main file
|
|
|
|
|
if (totalCost <= maxCost) {
|
|
|
|
|
for (const std::string& stmt : ctorStmts) {
|
|
|
|
|
totalCost += stmtCost(stmt);
|
|
|
|
|
if (totalCost > maxCost) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (totalCost <= maxCost) {
|
|
|
|
|
for (const std::string& stmt : dtorStmts) {
|
|
|
|
|
totalCost += stmtCost(stmt);
|
|
|
|
|
if (totalCost > maxCost) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Split them if needed
|
|
|
|
|
if (totalCost > maxCost) {
|
|
|
|
|
v3Global.useParallelBuild(true); // Splitting files, so using parallel build.
|
|
|
|
|
emitSplit(ctorStmts, "ctor", maxCost);
|
|
|
|
|
emitSplit(dtorStmts, "dtor", maxCost);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-09 18:41:13 +01:00
|
|
|
openNewOutputSourceFile(symClassName(), true, true, "Symbol table implementation internals");
|
2025-11-08 11:36:12 +01:00
|
|
|
emitSymImpPreamble();
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
const std::string ctorArgs
|
|
|
|
|
= "VerilatedContext* contextp, const char* namep, " + topClassName() + "* modelp";
|
|
|
|
|
puts(symClassName() + "::" + symClassName() + "(" + ctorArgs + ")\n");
|
|
|
|
|
puts(" : VerilatedSyms{contextp}\n");
|
|
|
|
|
puts(" // Setup internal state of the Syms class\n");
|
|
|
|
|
puts(" , __Vm_modelp{modelp}\n");
|
|
|
|
|
if (v3Global.opt.mtasks()) {
|
|
|
|
|
puts(" , __Vm_threadPoolp{static_cast<VlThreadPool*>(contextp->threadPoolp())}\n");
|
|
|
|
|
}
|
|
|
|
|
if (v3Global.opt.profExec()) {
|
|
|
|
|
puts(" , __Vm_executionProfilerp{static_cast<VlExecutionProfiler*>(contextp->"
|
|
|
|
|
"enableExecutionProfiler(&VlExecutionProfiler::construct))}\n");
|
|
|
|
|
}
|
|
|
|
|
if (v3Global.opt.profPgo() && !v3Global.opt.libCreate().empty()) {
|
|
|
|
|
puts(" , _vm_pgoProfiler{" + std::to_string(v3Global.currentHierBlockCost()) + "}\n");
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const AstScope* const scopep = netlistp->topScopep()->scopep();
|
|
|
|
|
puts(" // Setup top module instance\n");
|
|
|
|
|
puts(" , " + protect(scopep->nameDotless()) + "{this, namep}\n");
|
|
|
|
|
}
|
|
|
|
|
puts("{\n");
|
|
|
|
|
for (const std::string& stmt : ctorStmts) {
|
2025-11-09 18:41:13 +01:00
|
|
|
ofp()->putsNoTracking(" ");
|
|
|
|
|
ofp()->putsNoTracking(stmt);
|
|
|
|
|
ofp()->putsNoTracking("\n");
|
2009-12-20 14:27:00 +01:00
|
|
|
}
|
2025-11-08 11:36:12 +01:00
|
|
|
puts("}\n");
|
2009-12-20 14:27:00 +01:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
// Destructor
|
|
|
|
|
puts("\n" + symClassName() + "::~" + symClassName() + "() {\n");
|
|
|
|
|
for (const std::string& stmt : dtorStmts) {
|
2025-11-09 18:41:13 +01:00
|
|
|
ofp()->putsNoTracking(" ");
|
|
|
|
|
ofp()->putsNoTracking(stmt);
|
|
|
|
|
ofp()->putsNoTracking("\n");
|
2025-11-08 11:36:12 +01:00
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
puts("}\n");
|
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 16:30:20 +02:00
|
|
|
|
2025-11-08 11:36:12 +01:00
|
|
|
// Methods
|
|
|
|
|
if (v3Global.needTraceDumper()) {
|
|
|
|
|
if (!optSystemC()) {
|
|
|
|
|
puts("\nvoid " + symClassName() + "::_traceDump() {\n");
|
|
|
|
|
puts("const VerilatedLockGuard lock{__Vm_dumperMutex};\n");
|
|
|
|
|
// Caller checked for __Vm_dumperp non-nullptr
|
|
|
|
|
puts("__Vm_dumperp->dump(VL_TIME_Q());\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
puts("\nvoid " + symClassName() + "::_traceDumpOpen() {\n");
|
|
|
|
|
puts("const VerilatedLockGuard lock{__Vm_dumperMutex};\n");
|
|
|
|
|
puts("if (VL_UNLIKELY(!__Vm_dumperp)) {\n");
|
|
|
|
|
puts("__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n");
|
|
|
|
|
puts("__Vm_modelp->trace(__Vm_dumperp, 0, 0);\n");
|
|
|
|
|
puts("const std::string dumpfile = _vm_contextp__->dumpfileCheck();\n");
|
|
|
|
|
puts("__Vm_dumperp->open(dumpfile.c_str());\n");
|
|
|
|
|
puts("__Vm_dumping = true;\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
|
|
|
|
|
puts("\nvoid " + symClassName() + "::_traceDumpClose() {\n");
|
|
|
|
|
puts("const VerilatedLockGuard lock{__Vm_dumperMutex};\n");
|
|
|
|
|
puts("__Vm_dumping = false;\n");
|
|
|
|
|
puts("VL_DO_CLEAR(delete __Vm_dumperp, __Vm_dumperp = nullptr);\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.savable()) {
|
|
|
|
|
for (const bool& de : {false, true}) {
|
|
|
|
|
const std::string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
|
|
|
|
|
const std::string funcname = protect(de ? "__Vdeserialize" : "__Vserialize");
|
|
|
|
|
const std::string op = de ? ">>" : "<<";
|
|
|
|
|
puts("\nvoid " + symClassName() + "::" + funcname + "(" + classname + "& os) {\n");
|
|
|
|
|
puts("// Internal state\n");
|
|
|
|
|
if (v3Global.opt.trace()) puts("os" + op + "__Vm_activity;\n");
|
|
|
|
|
puts("os " + op + " __Vm_didInit;\n");
|
|
|
|
|
puts("// Module instance state\n");
|
|
|
|
|
for (const ScopeModPair& itpair : m_scopes) {
|
|
|
|
|
const AstScope* const scopep = itpair.first;
|
|
|
|
|
const std::string scopeName
|
|
|
|
|
= VIdProtect::protectIf(scopep->nameDotless(), scopep->protect());
|
|
|
|
|
puts(scopeName + "." + funcname + "(os);\n");
|
|
|
|
|
}
|
|
|
|
|
puts("}\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
closeOutputFile();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-09 04:12:59 +01:00
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
void EmitCSyms::emitDpiHdr() {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(6, __FUNCTION__ << ": ");
|
2025-11-09 18:41:13 +01:00
|
|
|
|
|
|
|
|
openNewOutputHeaderFile(topClassName() + "__Dpi",
|
|
|
|
|
"Prototypes for DPI import and export functions.");
|
2009-12-09 04:12:59 +01:00
|
|
|
puts("//\n");
|
|
|
|
|
puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n");
|
2020-01-25 02:10:44 +01:00
|
|
|
puts("// Manually include this file where DPI .c import functions are declared to ensure\n");
|
2009-12-09 04:12:59 +01:00
|
|
|
puts("// the C functions match the expectations of the DPI imports.\n");
|
2021-08-24 03:43:54 +02:00
|
|
|
|
|
|
|
|
ofp()->putsGuard();
|
|
|
|
|
|
2009-12-09 04:12:59 +01:00
|
|
|
puts("\n");
|
2011-05-12 12:32:29 +02:00
|
|
|
puts("#include \"svdpi.h\"\n");
|
|
|
|
|
puts("\n");
|
2009-12-09 04:12:59 +01:00
|
|
|
puts("#ifdef __cplusplus\n");
|
|
|
|
|
puts("extern \"C\" {\n");
|
|
|
|
|
puts("#endif\n");
|
|
|
|
|
puts("\n");
|
2012-03-20 21:01:53 +01:00
|
|
|
|
2011-08-05 03:58:45 +02:00
|
|
|
int firstExp = 0;
|
|
|
|
|
int firstImp = 0;
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const AstCFunc* const nodep : m_dpis) {
|
|
|
|
|
if (!nodep->dpiExportDispatcher() && !nodep->dpiImportPrototype()) continue;
|
|
|
|
|
|
|
|
|
|
const std::string sourceLoc = VIdProtect::ifNoProtect(" at " + nodep->fileline()->ascii());
|
2021-06-10 23:41:33 +02:00
|
|
|
if (nodep->dpiExportDispatcher()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!firstExp++) puts("\n// DPI EXPORTS\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
putsDecoration(nodep, "// DPI export" + sourceLoc + "\n");
|
|
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!firstImp++) puts("\n// DPI IMPORTS\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
putsDecoration(nodep, "// DPI import" + sourceLoc + "\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
putns(nodep, "extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "("
|
|
|
|
|
+ cFuncArgs(nodep) + ");\n");
|
2009-12-09 04:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
puts("\n");
|
|
|
|
|
puts("#ifdef __cplusplus\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
puts("#endif\n");
|
2021-08-24 03:43:54 +02:00
|
|
|
|
|
|
|
|
ofp()->putsEndGuard();
|
2025-11-09 18:41:13 +01:00
|
|
|
|
|
|
|
|
closeOutputFile();
|
2009-12-09 04:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
2009-12-20 14:27:00 +01:00
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
void EmitCSyms::emitDpiImp() {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(6, __FUNCTION__ << ": ");
|
2025-11-09 18:41:13 +01:00
|
|
|
openNewOutputSourceFile(topClassName() + "__Dpi", false, true,
|
|
|
|
|
"Implementation of DPI export functions");
|
2009-12-20 14:27:00 +01:00
|
|
|
puts("//\n");
|
|
|
|
|
puts("// Verilator compiles this file in when DPI functions are used.\n");
|
|
|
|
|
puts("// If you have multiple Verilated designs with the same DPI exported\n");
|
|
|
|
|
puts("// function names, you will get multiple definition link errors from here.\n");
|
|
|
|
|
puts("// This is an unfortunate result of the DPI specification.\n");
|
|
|
|
|
puts("// To solve this, either\n");
|
2025-11-05 00:00:26 +01:00
|
|
|
puts("// 1. Call " + topClassName() + "::{export_function} instead,\n");
|
2009-12-20 14:27:00 +01:00
|
|
|
puts("// and do not even bother to compile this file\n");
|
|
|
|
|
puts("// or 2. Compile all __Dpi.cpp files in the same compiler run,\n");
|
|
|
|
|
puts("// and #ifdefs already inserted here will sort everything out.\n");
|
|
|
|
|
puts("\n");
|
2012-03-20 21:01:53 +01:00
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
puts("#include \"" + topClassName() + "__Dpi.h\"\n");
|
|
|
|
|
puts("#include \"" + topClassName() + ".h\"\n");
|
2009-12-20 14:27:00 +01:00
|
|
|
puts("\n");
|
|
|
|
|
|
2025-11-05 00:00:26 +01:00
|
|
|
for (const AstCFunc* const nodep : m_dpis) {
|
|
|
|
|
if (!nodep->dpiExportDispatcher()) continue;
|
|
|
|
|
|
|
|
|
|
const std::string name = nodep->name();
|
|
|
|
|
const std::string sourceLoc = VIdProtect::ifNoProtect(" at " + nodep->fileline()->ascii());
|
|
|
|
|
|
|
|
|
|
// Prevent multi-definition if used by multiple models
|
|
|
|
|
puts("#ifndef VL_DPIDECL_" + name + "_\n");
|
|
|
|
|
puts("#define VL_DPIDECL_" + name + "_\n");
|
|
|
|
|
putns(nodep, nodep->rtnTypeVoid() + " " + name + "(" + cFuncArgs(nodep) + ") {\n");
|
|
|
|
|
puts("// DPI export" + sourceLoc + "\n");
|
|
|
|
|
putns(nodep, "return " + topClassName() + "::" + name + "(");
|
|
|
|
|
std::string comma;
|
|
|
|
|
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
|
|
|
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
|
|
|
|
|
if (portp->isIO() && !portp->isFuncReturn()) {
|
|
|
|
|
puts(comma);
|
|
|
|
|
comma = ", ";
|
|
|
|
|
putns(portp, portp->name());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-05 00:00:26 +01:00
|
|
|
puts(");\n");
|
|
|
|
|
puts("}\n");
|
|
|
|
|
puts("#endif\n");
|
|
|
|
|
puts("\n");
|
2009-12-20 14:27:00 +01:00
|
|
|
}
|
2025-11-09 18:41:13 +01:00
|
|
|
closeOutputFile();
|
2009-12-20 14:27:00 +01:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// EmitC class functions
|
|
|
|
|
|
2019-08-28 03:36:59 +02:00
|
|
|
void V3EmitC::emitcSyms(bool dpiHdrOnly) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2023-10-29 02:11:28 +02:00
|
|
|
EmitCSyms{v3Global.rootp(), dpiHdrOnly};
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|