style: Changed naming from instrumentation to hook-insertion

This commit is contained in:
Jonathan Schröter 2025-11-27 10:53:24 +01:00
parent d43e918faf
commit fab0b69f0b
11 changed files with 273 additions and 273 deletions

View File

@ -117,7 +117,7 @@ set(HEADERS
V3Inline.h
V3Inst.h
V3InstrCount.h
V3Instrument.h
V3InsertHook.h
V3Interface.h
V3LangCode.h
V3LanguageWords.h
@ -290,7 +290,7 @@ set(COMMON_SOURCES
V3Inline.cpp
V3Inst.cpp
V3InstrCount.cpp
V3Instrument.cpp
V3InsertHook.cpp
V3Interface.cpp
V3Life.cpp
V3LifePost.cpp

View File

@ -287,7 +287,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Inline.o \
V3Inst.o \
V3InstrCount.o \
V3Instrument.o \
V3InsertHook.o \
V3Interface.o \
V3Life.o \
V3LifePost.o \

View File

@ -576,7 +576,7 @@ class V3ControlResolver final {
uint8_t m_mode = NONE;
std::unordered_map<string, V3ControlResolverHierWorkerEntry> m_hierWorkers;
FileLine* m_profileFileLine = nullptr;
std::map<string, InstrumentTarget, LengthThenLexiographic> m_instrCfg;
std::map<string, HookInsertTarget, LengthThenLexiographic> m_hookInsCfg;
V3ControlResolver() = default;
~V3ControlResolver() = default;
@ -641,7 +641,7 @@ public:
return cost;
}
}
// Helper for adding targets to the instrumentation config map
// Helper for adding targets to the hook-insertion config map
std::pair<string, string> splitPrefixAndVar(const string& target) {
auto pos = target.rfind('.');
if (pos == string::npos) {
@ -651,13 +651,13 @@ public:
string varTarget = target.substr(pos + 1);
return {prefix, varTarget};
}
// Add the instrumentation config data to the map to create the initial map (Used in verilog.y)
void addInstrumentCfg(FileLine* fl, const string& instrFunction, int instrID,
// Add the hook-insertion config data to the map to create the initial map (Used in verilog.y)
void addHookInsCfg(FileLine* fl, const string& insFunction, int insID,
const string& target) {
// Error MSG if the instrumentation of the top module is not possible
// Error MSG if the hook-insertion of the top module is not possible
if ((std::count(target.begin(), target.end(), '.') < 2)) {
v3fatal(
"In .vlt defined target tries to instrument the highest MODULE, is not possible!"
"In .vlt defined target tries to insert-hook to the highest MODULE, which is not possible!"
" ... Target string: "
<< target);
}
@ -667,19 +667,19 @@ public:
auto result = splitPrefixAndVar(target);
auto prefix = result.first;
auto varTarget = result.second;
InstrumentEntry entry{instrID, instrFunction, varTarget, {}, {}};
auto it = m_instrCfg.find(prefix);
if (it != m_instrCfg.end()) {
HookInsertEntry entry{insID, insFunction, varTarget, {}, {}};
auto it = m_hookInsCfg.find(prefix);
if (it != m_hookInsCfg.end()) {
it->second.entries.push_back(entry);
} else {
// Create a new entry in the map
InstrumentTarget newTarget;
HookInsertTarget newTarget;
newTarget.entries.push_back(entry);
m_instrCfg[prefix] = std::move(newTarget);
m_hookInsCfg[prefix] = std::move(newTarget);
}
}
std::map<string, InstrumentTarget, LengthThenLexiographic>& getInstrumentCfg() {
return m_instrCfg;
std::map<string, HookInsertTarget, LengthThenLexiographic>& getHookInsCfg() {
return m_hookInsCfg;
}
};
@ -739,9 +739,9 @@ void V3Control::addModulePragma(const string& module, VPragmaType pragma) {
V3ControlResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Control::addInstrumentCfg(FileLine* fl, const string& instrumentfunc, int instrID,
void V3Control::addHookInsCfg(FileLine* fl, const string& insfunc, int insID,
const string& target) {
V3ControlResolver::s().addInstrumentCfg(fl, instrumentfunc, instrID, target);
V3ControlResolver::s().addHookInsCfg(fl, insfunc, insID, target);
}
void V3Control::addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
@ -905,8 +905,8 @@ int V3Control::getHierWorkers(const string& model) {
FileLine* V3Control::getHierWorkersFileLine(const string& model) {
return V3ControlResolver::s().getHierWorkersFileLine(model);
}
std::map<string, InstrumentTarget, LengthThenLexiographic>& V3Control::getInstrumentCfg() {
return V3ControlResolver::s().getInstrumentCfg();
std::map<string, HookInsertTarget, LengthThenLexiographic>& V3Control::getHookInsCfg() {
return V3ControlResolver::s().getHookInsCfg();
}
uint64_t V3Control::getProfileData(const string& hierDpi) {
return V3ControlResolver::s().getProfileData(hierDpi);

View File

@ -33,18 +33,18 @@ struct LengthThenLexiographic final {
return a < b;
}
};
struct InstrumentEntry final {
int instrID;
std::string instrFunc;
struct HookInsertEntry final {
int insID;
std::string insFunc;
std::string varTarget;
AstVar* origVarps;
AstVar* instrVarps;
AstVar* insVarps;
bool found = false;
};
struct InstrumentTarget final {
std::vector<InstrumentEntry> entries;
struct HookInsertTarget final {
std::vector<HookInsertEntry> entries;
AstModule* origModulep;
AstModule* instrModulep;
AstModule* insModulep;
AstModule* topModulep;
AstModule* pointingModulep;
AstCell* cellp;
@ -70,9 +70,9 @@ public:
static void addIgnoreMatch(V3ErrorCode code, const string& filename, const string& contents,
const string& match);
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
static void addInstrumentCfg(FileLine* fl, const string& instrumentfunc, int instrID,
static void addHookInsCfg(FileLine* fl, const string& insfunc, int insID,
const string& target);
static std::map<string, InstrumentTarget, LengthThenLexiographic>& getInstrumentCfg();
static std::map<string, HookInsertTarget, LengthThenLexiographic>& getHookInsCfg();
static void addModulePragma(const string& module, VPragmaType pragma);
static void addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost);
static void addProfileData(FileLine* fl, const string& model, const string& key,

View File

@ -1,10 +1,10 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//**************************************************************************
// DESCRIPTION: Verilator:
//
// Code available from: https://verilator.org
//
//*************************************************************************
//**************************************************************************
//
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
@ -13,18 +13,18 @@
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
// V3Instrumentation's Transformations:
// The instrumentation configuration map is populated with the relevant nodes, as defined by the
// target string specified in the instrumentation configuration within the .vlt file.
// V3HookInsert's Transformations:
// The hook-insertion configuration map is populated with the relevant nodes, as defined by the
// target string specified in the hook-insertion configuration within the .vlt file.
// Additionally, the AST (Abstract Syntax Tree) is modified to insert the necessary extra nodes
// required for instrumentation.
// required for hook-insertion.
// Furthermore, the links between Module, Cell, and Var nodes are adjusted to ensure correct
// connectivity for instrumentation purposes.
// connectivity for hook-insertion purposes.
//*************************************************************************
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3Instrument.h"
#include "V3InsertHook.h"
#include "V3Control.h"
#include "V3File.h"
@ -39,8 +39,8 @@
VL_DEFINE_DEBUG_FUNCTIONS;
//##################################################################################
// Instrumentation class finder
class InstrumentTargetFndr final : public VNVisitor {
// Hook-insertion class finder
class HookInsTargetFndr final : public VNVisitor {
AstNetlist* m_netlist
= nullptr; // Enable traversing from the beginning if the visitor is to deep
AstNodeModule* m_cellModp = nullptr; // Stores the modulep of a Cell node
@ -51,7 +51,7 @@ class InstrumentTargetFndr final : public VNVisitor {
bool m_foundModp = false; // If the visitor found the relevant model
bool m_foundVarp = false; // If the visitor found the relevant variable
bool m_initModp = true; // If the visitor is in the first module node of the netlist
size_t m_instrIdx = 0;
size_t m_insIdx = 0;
string m_currHier; // Stores the current hierarchy of the visited nodes (Module, Cell, Var)
string m_target; // Stores the currently visited target string from the config map
@ -74,31 +74,31 @@ class InstrumentTargetFndr final : public VNVisitor {
// Helper function to check if a parameter was already added to the tree previously
bool hasParam(AstModule* modp) {
for (AstNode* n = modp->op2p(); n; n = n->nextp()) {
if (n->name() == "INSTRUMENT") { return true; }
if (n->name() == "HOOKINS") { return true; }
}
return false;
}
// Helper function to check if a pin was already added to the tree previously
bool hasPin(AstCell* cellp) {
for (AstNode* n = cellp->paramsp(); n; n = n->nextp()) {
if (n->name() == "INSTRUMENT") { return true; }
if (n->name() == "HOOKINS") { return true; }
}
return false;
}
// Check if the multipleCellps flag is set for the given target
bool hasMultiple(const std::string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { return it->second.multipleCellps; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { return it->second.multipleCellps; }
return false;
}
// Check if the direct predecessor in the target string has been instrumented,
// to create the correct link between the already instrumented module and the current one.
// Check if the direct predecessor in the target string has been hook-inserted,
// to create the correct link between the already hook-inserted module and the current one.
bool hasPrior(AstModule* modulep, const string& target) {
const auto& instrCfg = V3Control::getInstrumentCfg();
const auto& insCfg = V3Control::getHookInsCfg();
auto priorTarget = reduce2Depth(split(target), KeyDepth::RelevantModule);
auto it = instrCfg.find(priorTarget);
return it != instrCfg.end() && it->second.processed;
auto it = insCfg.find(priorTarget);
return it != insCfg.end() && it->second.processed;
}
bool targetHasFullName(const string& fullname, const string& target) {
return fullname == target;
@ -137,7 +137,7 @@ class InstrumentTargetFndr final : public VNVisitor {
}
// Helper function for adding the parameters into the tree
void addParam(AstModule* modp) {
AstVar* paramp = new AstVar{modp->fileline(), VVarType::GPARAM, "INSTRUMENT",
AstVar* paramp = new AstVar{modp->fileline(), VVarType::GPARAM, "HOOKINS",
VFlagChildDType{}, nullptr};
paramp->valuep(new AstConst{modp->fileline(), AstConst::Signed32{}, 0});
paramp->dtypep(paramp->valuep()->dtypep());
@ -145,34 +145,34 @@ class InstrumentTargetFndr final : public VNVisitor {
modp->addStmtsp(paramp);
}
// Helper function for adding the parameters into the tree
void addPin(AstCell* cellp, bool isInstrumentPath) {
void addPin(AstCell* cellp, bool isInsPath) {
int pinnum = 0;
if (isInstrumentPath) {
if (isInsPath) {
for (AstNode* n = cellp->pinsp(); n; n = n->nextp()) { pinnum++; }
AstPin* pinp = new AstPin{cellp->fileline(), pinnum + 1, "INSTRUMENT",
// The pin is set to 1 to enable the instrumentation path
AstPin* pinp = new AstPin{cellp->fileline(), pinnum + 1, "HOOKINS",
// The pin is set to 1 to enable the hook-insertion path
new AstConst{cellp->fileline(), AstConst::Signed32{}, 1}};
pinp->param(true);
cellp->addParamsp(pinp);
} else {
for (AstNode* n = cellp->pinsp(); n; n = n->nextp()) { pinnum++; }
AstPin* pinp = new AstPin{cellp->fileline(), pinnum + 1, "INSTRUMENT",
new AstParseRef{cellp->fileline(), "INSTRUMENT"}};
AstPin* pinp = new AstPin{cellp->fileline(), pinnum + 1, "HOOKINS",
new AstParseRef{cellp->fileline(), "HOOKINS"}};
pinp->param(true);
cellp->addParamsp(pinp);
}
}
// Edit the instrumentation data for the cell in the map
void editInstrData(AstCell* cellp, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.cellp = cellp; }
// Edit the hook-insertion data for the cell in the map
void editInsData(AstCell* cellp, const string& target) {
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.cellp = cellp; }
}
// Edit the instrumentation data for the pointing module in the map
void editInstrData(AstModule* modulep, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.pointingModulep = modulep; }
// Edit the hook-insertion data for the pointing module in the map
void editInsData(AstModule* modulep, const string& target) {
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.pointingModulep = modulep; }
}
// Check for multiple cells pointing to the next module
void multCellForModp(AstCell* cellp) {
@ -189,53 +189,53 @@ class InstrumentTargetFndr final : public VNVisitor {
}
// Insert the cell node that is/will pointing/point to the targeted module
void setCell(AstCell* cellp, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.cellp = cellp; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.cellp = cellp; }
}
// Insert the original and instrumented module nodes to the map
void setInstrModule(AstModule* origModulep, AstModule* instrModulep, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) {
// Insert the original and hook-inserted module nodes to the map
void setInsModule(AstModule* origModulep, AstModule* insModulep, const string& target) {
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) {
it->second.origModulep = origModulep;
it->second.instrModulep = instrModulep;
it->second.insModulep = insModulep;
}
}
// Set the multipleCellps flag
void setMultiple(const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.multipleCellps = true; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.multipleCellps = true; }
}
// Insert the module node that includes the cell pointing to the targeted module
// to the map
void setPointingMod(AstModule* modulep, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.pointingModulep = modulep; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.pointingModulep = modulep; }
}
// Set the processed flag
void setProcessed(const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.processed = true; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.processed = true; }
}
// Insert the top module node of the netlist to the map
void setTopMod(AstModule* modulep, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) { it->second.topModulep = modulep; }
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) { it->second.topModulep = modulep; }
}
// Insert the original and instrumented variable nodes to the map
void setVar(AstVar* varp, AstVar* instVarp, const string& target) {
auto& instrCfg = V3Control::getInstrumentCfg();
auto it = instrCfg.find(target);
if (it != instrCfg.end()) {
// Insert the original and hook-inserted variable nodes to the map
void setVar(AstVar* varp, AstVar* insVarp, const string& target) {
auto& insCfg = V3Control::getHookInsCfg();
auto it = insCfg.find(target);
if (it != insCfg.end()) {
for (auto& entry : it->second.entries) {
if (entry.varTarget == varp->name()) {
entry.origVarps = varp;
entry.instrVarps = instVarp;
entry.insVarps = insVarp;
entry.found = true;
return;
}
@ -250,9 +250,9 @@ class InstrumentTargetFndr final : public VNVisitor {
//Iterates over the existing module nodes in the netlist.
//For the first module in the netlist the node name is checked if it is at the first position
//in the target string provided by the configuration file. If not an error is thown, otherwise
//the modules is checked for an already existing INSTRUMENT parameter. If there is no
//INSTRUMENT parameter present we add it to the module. This parameter is used to control the
//instrumentation of the target. The module is then added to the map of the instrumentation
//the modules is checked for an already existing HOOKINS parameter. If there is no
//HOOKINS parameter present we add it to the module. This parameter is used to control the
//hook-insertion of the target. The module is then added to the map of the hook-insertion
//configs as the top module. Additionally the hierarchy the function viewed is currently add is
//initialized with the module name. This module hierarchy is used to identify the correct
//target path in the netlist. The function iterates over the children of the module, with the
@ -265,9 +265,9 @@ class InstrumentTargetFndr final : public VNVisitor {
//The module node displayed by the m_modp variable is then checked if this is the module
//containing the target variable (relevant module) or if it the module containing the cell
//pointing to the relevant module (pointing module). If the module node suits one of these two
//conditions the module nodes are added to the instrumentation configs map. Independetly from
//these conditions the INSTRUMENT parameter is added to the module nodes in the target path.
//This parameter is used to control the instrumentation of the target.
//conditions the module nodes are added to the hook-insertion configs map. Independetly from
//these conditions the HOOKINS parameter is added to the module nodes in the target path.
//This parameter is used to control the hook-insertion of the target.
void visit(AstModule* nodep) override {
if (m_initModp) {
if (targetHasTop(nodep->name(), m_target)) {
@ -293,32 +293,32 @@ class InstrumentTargetFndr final : public VNVisitor {
} else if (m_cellModp != nullptr
&& (nodep = findModp(m_netlist, VN_CAST(m_cellModp, Module))) != nullptr) {
if (targetHasFullName(m_currHier, m_target)) {
AstModule* instrModp = nullptr;
AstModule* insModp = nullptr;
m_foundModp = true;
m_targetModp = nodep;
m_cellModp = nullptr;
// Check for prior changes made to the tree
if (hasPrior(nodep, m_currHier)) {
auto& instrCfg = V3Control::getInstrumentCfg();
instrModp
= instrCfg.find(reduce2Depth(split(m_currHier), KeyDepth::RelevantModule))
->second.instrModulep;
editInstrData(instrModp, m_currHier);
auto& insCfg = V3Control::getHookInsCfg();
insModp
= insCfg.find(reduce2Depth(split(m_currHier), KeyDepth::RelevantModule))
->second.insModulep;
editInsData(insModp, m_currHier);
AstCell* cellp = nullptr;
for (AstNode* n = instrModp->op2p(); n; n = n->nextp()) {
for (AstNode* n = insModp->op2p(); n; n = n->nextp()) {
if (VN_IS(n, Cell) && (VN_CAST(n, Cell)->modp() == nodep)
&& instrCfg.find(m_currHier)->second.cellp->name() == n->name()) {
&& insCfg.find(m_currHier)->second.cellp->name() == n->name()) {
cellp = VN_CAST(n, Cell);
break;
}
}
editInstrData(cellp, m_currHier);
editInsData(cellp, m_currHier);
}
if (!hasParam(nodep)) { addParam(nodep); }
instrModp = nodep->cloneTree(false);
instrModp->name(nodep->name() + "__inst__" + std::to_string(m_instrIdx));
if (hasMultiple(m_target)) { instrModp->inLibrary(true); }
setInstrModule(nodep, instrModp, m_target);
insModp = nodep->cloneTree(false);
insModp->name(nodep->name() + "__hookIns__" + std::to_string(m_insIdx));
if (hasMultiple(m_target)) { insModp->inLibrary(true); }
setInsModule(nodep, insModp, m_target);
iterateChildren(nodep);
} else if (targetHasPointingMod(m_currHier, m_target)) {
m_foundModp = true;
@ -356,14 +356,14 @@ class InstrumentTargetFndr final : public VNVisitor {
//false. The in the current module existing cells are checked if there are multiple cells
//linking to the next module in the target string. After that the m_modp is updated to match
//the cell's module pointer, which is needed for the next call of the module visitor. Next the
//pin for the INSTRUMENT parameter is added to the cell. This parameter is added either as a
//pin for the HOOKINS parameter is added to the cell. This parameter is added either as a
//constant or as a reference, depending on the traversal stage. If there are multiple cells
//linking to the next module in the target string, the multiple flag is set in the
//instrumentation config map. For the inistial module the found cell is then added to the
//instrumentation configuration map with the current hierarchy as the target path. Otherwise
//the cell is added to the instrumentation configuration map, when the current hierarchy with
//hook-insertion config map. For the inistial module the found cell is then added to the
//hook-insertion configuration map with the current hierarchy as the target path. Otherwise
//the cell is added to the hook-insertion configuration map, when the current hierarchy with
//the cell name fully matches a target path, with the last two entrances removed (Module, Var).
//This function ensures that the correct cells in the design hierarchy are instrumented and
//This function ensures that the correct cells in the design hierarchy are hook-inserted and
//tracked, supporting both unique and repeated module instances.
void visit(AstCell* nodep) override {
if (m_initModp) {
@ -414,11 +414,11 @@ class InstrumentTargetFndr final : public VNVisitor {
//module of the target hierarchy. Since we therefore know that we will not traverse any further
//in the hierarchy of the model, we can check for this variable. If a variable is found, with
//its name added to the current hierarchy, that siuts the target string, an edited version and
//the original version are added to the instrumentation config map.
//the original version are added to the hook-insertion config map.
void visit(AstVar* nodep) override {
if (m_targetModp != nullptr) {
const InstrumentTarget& target
= V3Control::getInstrumentCfg().find(m_currHier)->second;
const HookInsertTarget& target
= V3Control::getHookInsCfg().find(m_currHier)->second;
for (const auto& entry : target.entries) {
if (nodep->name() == entry.varTarget) {
int width = 0;
@ -446,8 +446,8 @@ class InstrumentTargetFndr final : public VNVisitor {
setVar(nodep, varp, m_target);
if (string::npos == m_currHier.rfind('.')) {
AstModule* modulep = m_modp->cloneTree(false);
modulep->name(m_modp->name() + "__inst__" + std::to_string(m_instrIdx));
setInstrModule(m_modp, modulep, m_currHier);
modulep->name(m_modp->name() + "__hookIns__" + std::to_string(m_insIdx));
setInsModule(m_modp, modulep, m_currHier);
m_initModp = false;
}
m_foundVarp = true;
@ -466,9 +466,9 @@ class InstrumentTargetFndr final : public VNVisitor {
public:
// CONSTRUCTOR
//-------------------------------------------------------------------------------
explicit InstrumentTargetFndr(AstNetlist* nodep) {
const auto& instrCfg = V3Control::getInstrumentCfg();
for (const auto& pair : instrCfg) {
explicit HookInsTargetFndr(AstNetlist* nodep) {
const auto& insCfg = V3Control::getHookInsCfg();
for (const auto& pair : insCfg) {
m_netlist = nodep;
m_target = pair.first;
m_initModp = true;
@ -481,15 +481,15 @@ public:
m_error = false;
m_targetModp = nullptr;
m_modp = nullptr;
m_instrIdx++;
m_insIdx++;
}
};
~InstrumentTargetFndr() override = default;
~HookInsTargetFndr() override = default;
};
//##################################################################################
// Instrumentation class functions
class InstrumentFunc final : public VNVisitor {
// Hook-insertion class functions
class HookInsFunc final : public VNVisitor {
bool m_assignw = false; // Flag if a assignw exists in the netlist
bool m_assignNode = false; // Set to true to indicate that the visitor is in an assign
bool m_addedport = false; // Flag if a port was already added
@ -497,13 +497,13 @@ class InstrumentFunc final : public VNVisitor {
bool m_addedFunc = false; // Flag if a function was already added
bool m_interface = false; // Flag if the ParseRef node is part of an interface
int m_pinnum = 0; // Pinnumber for the new Port nodes
string m_targetKey; // Stores the target string from the instrumentation config
string m_targetKey; // Stores the target string from the hook-insertion config
string m_task_name;
size_t m_targetIndex = 0; // Index of the target variable in the instrumentation config
size_t m_targetIndex = 0; // Index of the target variable in the hook-insertion config
AstAlways* m_alwaysp = nullptr; // Stores the added always node
AstAssignW* m_assignwp = nullptr; // Stores the added assignw node
AstGenBlock* m_instGenBlock
= nullptr; // Store the GenBlock node for instrumentation hierarchy check
AstGenBlock* m_insGenBlock
= nullptr; // Store the GenBlock node for hook-insertion hierarchy check
AstTask* m_taskp = nullptr; // // Stores the created task node
AstFunc* m_funcp = nullptr; // Stores the created function node
AstFuncRef* m_funcrefp = nullptr; // Stores the created funcref node
@ -512,10 +512,10 @@ class InstrumentFunc final : public VNVisitor {
AstModule* m_current_module = nullptr; // Stores the currenty visited module
AstModule* m_current_module_cell_check
= nullptr; // Stores the module node(used by cell visitor)
AstVar* m_tmp_varp = nullptr; // Stores the instrumented variable node
AstVar* m_tmp_varp = nullptr; // Stores the hook-inserted variable node
AstVar* m_orig_varp = nullptr; // Stores the original variable node
AstVar* m_orig_varp_instMod
= nullptr; // Stores the original variable node in instrumented module node
AstVar* m_orig_varp_insMod
= nullptr; // Stores the original variable node in hook-inserted module node
AstVar* m_dpi_trigger
= nullptr; // Stores the variable noded for the dpi-trigger, which ensures the changing of
// a signal and the execution of the DPI function
@ -523,54 +523,54 @@ class InstrumentFunc final : public VNVisitor {
// METHODS
//----------------------------------------------------------------------------------
// Find the relevant instrumentation config in the map corresponding to the given key
const InstrumentTarget* getInstrCfg(const std::string& key) {
const auto& map = V3Control::getInstrumentCfg();
auto instrCfg = map.find(key);
if (instrCfg != map.end()) {
return &instrCfg->second;
// Find the relevant hook-insertion config in the map corresponding to the given key
const HookInsertTarget* getInsCfg(const std::string& key) {
const auto& map = V3Control::getHookInsCfg();
auto insCfg = map.find(key);
if (insCfg != map.end()) {
return &insCfg->second;
} else {
return nullptr;
}
}
// Get the Cell nodep pointer from the configuration map for the given key
AstCell* getMapEntryCell(const std::string& key) {
if (auto cfg = getInstrCfg(key)) { return cfg->cellp; }
if (auto cfg = getInsCfg(key)) { return cfg->cellp; }
return nullptr;
}
// Get the instrumented Module node pointer from the configuration map for the given key
AstModule* getMapEntryInstModule(const std::string& key) {
if (auto cfg = getInstrCfg(key)) { return cfg->instrModulep; }
// Get the hook-inserted Module node pointer from the configuration map for the given key
AstModule* getMapEntryInsModule(const std::string& key) {
if (auto cfg = getInsCfg(key)) { return cfg->insModulep; }
return nullptr;
}
// Get the Module node pointer pointing to the instrumented/original module from the
// Get the Module node pointer pointing to the hook-inserted/original module from the
// configuration map for the given key
AstModule* getMapEntryPointingModule(const std::string& key) {
if (auto cfg = getInstrCfg(key)) { return cfg->pointingModulep; }
if (auto cfg = getInsCfg(key)) { return cfg->pointingModulep; }
return nullptr;
}
// Get the instrumented variable node pointer from the configuration map for the given key
AstVar* getMapEntryInstVar(const std::string& key, size_t index) {
if (auto cfg = getInstrCfg(key)) {
// Get the hook-inserted variable node pointer from the configuration map for the given key
AstVar* getMapEntryInsVar(const std::string& key, size_t index) {
if (auto cfg = getInsCfg(key)) {
const auto& entries = cfg->entries;
if (index < entries.size()) { return entries[index].instrVarps; }
if (index < entries.size()) { return entries[index].insVarps; }
}
return nullptr;
}
// Get the original variable node pointer from the configuration map for the given key
AstVar* getMapEntryVar(const std::string& key, size_t index) {
if (auto cfg = getInstrCfg(key)) {
if (auto cfg = getInsCfg(key)) {
const auto& entries = cfg->entries;
if (index < entries.size()) { return entries[index].origVarps; }
}
return nullptr;
}
// Check if the given module node pointer is an instrumented module entry in the configuration
// Check if the given module node pointer is an hook-inserted module entry in the configuration
// map for the given key
bool isInstModEntry(AstModule* nodep, const std::string& key) {
const auto& map = V3Control::getInstrumentCfg();
const auto instrCfg = map.find(key);
if (instrCfg != map.end() && instrCfg->second.instrModulep == nodep) {
bool isInsModEntry(AstModule* nodep, const std::string& key) {
const auto& map = V3Control::getHookInsCfg();
const auto insCfg = map.find(key);
if (insCfg != map.end() && insCfg->second.insModulep == nodep) {
return true;
} else {
return false;
@ -578,47 +578,47 @@ class InstrumentFunc final : public VNVisitor {
}
// Check if the given module node pointer is the top module entry in the configuration map
bool isTopModEntry(AstModule* nodep) {
auto& instrCfg = V3Control::getInstrumentCfg();
for (const auto& pair : instrCfg) {
auto& insCfg = V3Control::getHookInsCfg();
for (const auto& pair : insCfg) {
if (nodep == pair.second.topModulep) { return true; }
}
return false;
}
// Check if the given module node pointer is the pointing module entry in the configuration map
bool isPointingModEntry(AstModule* nodep) {
auto& instrCfg = V3Control::getInstrumentCfg();
for (const auto& pair : instrCfg) {
auto& insCfg = V3Control::getHookInsCfg();
for (const auto& pair : insCfg) {
if (nodep == pair.second.pointingModulep) { return true; }
}
return false;
}
// Check if the given module node pointer has already been instrumented/done flag has been set
// Check if the given module node pointer has already been hook-inserted/done flag has been set
bool isDone(AstModule* nodep) {
auto& instrCfg = V3Control::getInstrumentCfg();
for (const auto& pair : instrCfg) {
if (nodep == pair.second.instrModulep) { return pair.second.done; }
auto& insCfg = V3Control::getHookInsCfg();
for (const auto& pair : insCfg) {
if (nodep == pair.second.insModulep) { return pair.second.done; }
}
return true;
}
// Check if the multipleCellps flag is set for the given key in the configuration map
bool hasMultiple(const std::string& key) {
const auto& map = V3Control::getInstrumentCfg();
const auto instrCfg = map.find(key);
if (instrCfg != map.end()) {
return instrCfg->second.multipleCellps;
const auto& map = V3Control::getHookInsCfg();
const auto insCfg = map.find(key);
if (insCfg != map.end()) {
return insCfg->second.multipleCellps;
} else {
return false;
}
}
// Check if the module and instances defined in the target string were found in
// the previous step
bool hasNullptr(const std::pair<const string, InstrumentTarget>& pair) {
bool hasNullptr(const std::pair<const string, HookInsertTarget>& pair) {
bool moduleNullptr = pair.second.origModulep == nullptr;
bool cellNullptr = pair.second.cellp == nullptr;
return moduleNullptr || cellNullptr;
}
// Check if the, in the target string, defined variable was found in the previous step
bool isFound(const std::pair<const string, InstrumentTarget>& pair) {
bool isFound(const std::pair<const string, HookInsertTarget>& pair) {
for (auto& entry : pair.second.entries) {
if (entry.found == false) { return entry.found; }
}
@ -626,23 +626,23 @@ class InstrumentFunc final : public VNVisitor {
}
// Get the fault case for the given key in the configuration map
int getMapEntryFaultCase(const std::string& key, size_t index) {
const auto& map = V3Control::getInstrumentCfg();
const auto instrCfg = map.find(key);
if (instrCfg != map.end()) {
const auto& entries = instrCfg->second.entries;
if (index < entries.size()) { return entries[index].instrID; }
const auto& map = V3Control::getHookInsCfg();
const auto insCfg = map.find(key);
if (insCfg != map.end()) {
const auto& entries = insCfg->second.entries;
if (index < entries.size()) { return entries[index].insID; }
return -1; // Return -1 if index is out of bounds
} else {
return -1;
}
}
// Get the instrumentation function name for the given key in the configuration map
// Get the callback function name from the hook-insertion for the given key in the configuration map
string getMapEntryFunction(const std::string& key, size_t index) {
const auto& map = V3Control::getInstrumentCfg();
const auto instrCfg = map.find(key);
if (instrCfg != map.end()) {
const auto& entries = instrCfg->second.entries;
if (index < entries.size()) { return entries[index].instrFunc; }
const auto& map = V3Control::getHookInsCfg();
const auto insCfg = map.find(key);
if (insCfg != map.end()) {
const auto& entries = insCfg->second.entries;
if (index < entries.size()) { return entries[index].insFunc; }
return "";
} else {
return "";
@ -650,12 +650,12 @@ class InstrumentFunc final : public VNVisitor {
}
// Set the done flag for the given module node pointer in the configuraiton map
void setDone(AstModule* nodep) {
auto& instrCfg = V3Control::getInstrumentCfg();
for (auto& pair : instrCfg) {
if (nodep == pair.second.instrModulep) { pair.second.done = true; }
auto& insCfg = V3Control::getHookInsCfg();
for (auto& pair : insCfg) {
if (nodep == pair.second.insModulep) { pair.second.done = true; }
}
}
void instrAssigns(AstNodeAssign* nodep) {
void insAssigns(AstNodeAssign* nodep) {
if (m_current_module != nullptr && m_orig_varp != nullptr && m_assignwp != nodep) {
m_assignNode = true;
VDirection dir = m_orig_varp->direction();
@ -733,16 +733,16 @@ class InstrumentFunc final : public VNVisitor {
//ASTNETLIST VISITOR FUNCTION:
//Loop over map entries for module nodes and add them to the tree
void visit(AstNetlist* nodep) override {
const auto& instrCfg = V3Control::getInstrumentCfg();
for (const auto& pair : instrCfg) {
const auto& insCfg = V3Control::getHookInsCfg();
for (const auto& pair : insCfg) {
if (hasNullptr(pair) || !isFound(pair)) {
v3error(
"Verilator-configfile: Incomplete instrumentation configuration for target '"
"Verilator-configfile: Incomplete hook-insertion configuration for target '"
<< pair.first
<< "'. Please check previous Errors from V3Instrument:findTargets and ensure"
<< " all necessary components are correct defined.");
} else {
nodep->addModulesp(pair.second.instrModulep);
nodep->addModulesp(pair.second.insModulep);
m_targetKey = pair.first;
iterateChildren(nodep);
m_assignw = false;
@ -752,33 +752,33 @@ class InstrumentFunc final : public VNVisitor {
//ASTMODULE VISITOR FUNCTION:
//This function is called for each module node in the netlist.
//It checks if the module node is part of the instrumentation configuratio map.
//Depending on the type of the module node (Instrumented, Top, Pointing, or Original),
//It checks if the module node is part of the hook-insertion configuration map.
//Depending on the type of the module node (Hook-inserted, Top, Pointing, or Original),
//it performs different actions:
// - If the module is an instrumented module entry and has not been done, it creates a new
//task for the instrumentation function, adds the temporary variable, and creates a task
//reference to the instrumentation function.
// - If the module is an hook-inserted module entry and has not been done, it creates a new
//task for the hook-insertion function, adds the temporary variable, and creates a task
//reference to the callback function.
// - If the module is a pointing module or a top module and has no multiple cellps, it
// checks
//the cell for the target key and counts the pins. This pin count is used in the CELL VISITOR
//FUNCTION to set a siutable pin number for the INSTRUMENT parameter. Look there fore further
//FUNCTION to set a siutable pin number for the HOOKINS parameter. Look there fore further
//information.
// - If the module is a pointing module and has multiple cellps, it creates a begin block
// with
//a conditional statement to select between the instrumented and original cell.
//a conditional statement to select between the hook-inserted and original cell.
// Additionally like in the previous case, the pin count is used to set a suitable pin
//number for the INSTRUMENT parameter.\ Since the cell which need to be edited are located not
//number for the HOOKINS parameter.\ Since the cell which need to be edited are located not
//in the original module, but in the pointing/top module, the current_module_cell_check
//variable is set to the module visited by the function and fulfilling this condition.
void visit(AstModule* nodep) override {
const auto& instrCfg = V3Control::getInstrumentCfg().find(m_targetKey);
const InstrumentTarget& target = instrCfg->second;
const auto& insCfg = V3Control::getHookInsCfg().find(m_targetKey);
const HookInsertTarget& target = insCfg->second;
const auto& entries = target.entries;
for (m_targetIndex = 0; m_targetIndex < entries.size(); ++m_targetIndex) {
m_tmp_varp = getMapEntryInstVar(m_targetKey, m_targetIndex);
m_tmp_varp = getMapEntryInsVar(m_targetKey, m_targetIndex);
m_orig_varp = getMapEntryVar(m_targetKey, m_targetIndex);
m_task_name = getMapEntryFunction(m_targetKey, m_targetIndex);
if (isInstModEntry(nodep, m_targetKey) && !isDone(nodep)) {
if (isInsModEntry(nodep, m_targetKey) && !isDone(nodep)) {
m_current_module = nodep;
for (AstNode* n = nodep->op2p(); n; n = n->nextp()) {
if (VN_IS(n, Task) && n->name() == m_task_name) {
@ -855,23 +855,23 @@ class InstrumentFunc final : public VNVisitor {
&& (isPointingModEntry(nodep) || isTopModEntry(nodep))
&& !hasMultiple(m_targetKey)) {
m_current_module_cell_check = nodep;
AstCell* instCellp = getMapEntryCell(m_targetKey);
for (AstNode* n = instCellp->pinsp(); n; n = n->nextp()) { m_pinnum++; }
AstCell* insCellp = getMapEntryCell(m_targetKey);
for (AstNode* n = insCellp->pinsp(); n; n = n->nextp()) { m_pinnum++; }
iterateChildren(nodep);
} else if (isPointingModEntry(nodep) && hasMultiple(m_targetKey)) {
m_current_module_cell_check = nodep;
AstCell* instCellp = getMapEntryCell(m_targetKey)->cloneTree(false);
instCellp->modp(getMapEntryInstModule(m_targetKey));
for (AstNode* n = instCellp->pinsp(); n; n = n->nextp()) { m_pinnum++; }
m_instGenBlock = new AstGenBlock{nodep->fileline(), "", instCellp, false};
AstCell* insCellp = getMapEntryCell(m_targetKey)->cloneTree(false);
insCellp->modp(getMapEntryInsModule(m_targetKey));
for (AstNode* n = insCellp->pinsp(); n; n = n->nextp()) { m_pinnum++; }
m_insGenBlock = new AstGenBlock{nodep->fileline(), "", insCellp, false};
AstGenIf* genifp = new AstGenIf{
nodep->fileline(), new AstParseRef{nodep->fileline(), "INSTRUMENT"},
m_instGenBlock,
nodep->fileline(), new AstParseRef{nodep->fileline(), "HOOKINS"},
m_insGenBlock,
new AstGenBlock{nodep->fileline(), "",
getMapEntryCell(m_targetKey)->cloneTree(false), false}};
nodep->addStmtsp(genifp);
iterateChildren(m_instGenBlock);
iterateChildren(m_insGenBlock);
iterateChildren(nodep);
}
m_current_module = nullptr;
@ -883,7 +883,7 @@ class InstrumentFunc final : public VNVisitor {
m_funcp = nullptr;
m_addedFunc = false;
m_addedport = false;
m_instGenBlock = nullptr;
m_insGenBlock = nullptr;
}
m_dpi_trigger = nullptr;
m_loopp = nullptr;
@ -893,9 +893,9 @@ class InstrumentFunc final : public VNVisitor {
//ASTPORT VISITOR FUNCTION:
//When the target variable is an ouput port, this function is called.
//If no port is added yet, two new ports are added to the current module.
//This enabled the instrumentation of the ouput port and link this instrumented port to the
//This enabled the hook-insertion of the ouput port and link this hook-inserted port to the
//modules reading from the original port. The idea behind this function is to set the
//instrumented port on the position of the original port in the module and move the original
//hook-inserted port on the position of the original port in the module and move the original
//port to another pin number. This should ensure the linking over the name and the port
//position in the module should work.
void visit(AstPort* nodep) override {
@ -913,28 +913,28 @@ class InstrumentFunc final : public VNVisitor {
}
//ASTCELL VISITOR FUNCTION:
//This function visits the cell nodes in the module pointing to the instrumented module.
//This function visits the cell nodes in the module pointing to the hook-inserted module.
//Depending if hasMultiple is set for the target key, two different actions are performed:
// - If hasMultiple is false, the cell is modified to link to the instrumented module and
// - If hasMultiple is false, the cell is modified to link to the hook-inserted module and
// the
//children are iterated. This ensures that the instrumented mopdule is used in the cell. Also
//children are iterated. This ensures that the hook-inserted mopdule is used in the cell. Also
//if the original variable is an output variable, the children of this cell nodes are visited
//by the ASTPIN VISITOR FUNCTION.
// - If hasMultiple is true, the cell is unlinked from the back and deleted.
// This ensures that the cell is not used anymore in the module, and the conditional
//statment deciding between the instrumented and the original cell can be created/used. A third
//action is performed if the variable beeing instrumented is an ouput variable. In this case
//statment deciding between the hook-inserted and the original cell can be created/used. A third
//action is performed if the variable beeing hook-inserted is an ouput variable. In this case
//the children of this cell nodes are visited by the ASTPIN VISITOR FUNCTION.
void visit(AstCell* nodep) override {
if (m_current_module_cell_check != nullptr && !hasMultiple(m_targetKey)
&& nodep == getMapEntryCell(m_targetKey)) {
nodep->modp(getMapEntryInstModule(m_targetKey));
nodep->modp(getMapEntryInsModule(m_targetKey));
if (m_orig_varp->direction() == VDirection::OUTPUT) { iterateChildren(nodep); }
} else if (m_current_module_cell_check != nullptr && hasMultiple(m_targetKey)
&& nodep == getMapEntryCell(m_targetKey)) {
nodep->unlinkFrBack();
nodep->deleteTree();
} else if (m_instGenBlock != nullptr && nodep->modp() == getMapEntryInstModule(m_targetKey)
} else if (m_insGenBlock != nullptr && nodep->modp() == getMapEntryInsModule(m_targetKey)
&& m_orig_varp->direction() == VDirection::OUTPUT) {
iterateChildren(nodep);
} else if (m_current_module != nullptr && m_orig_varp->direction() == VDirection::INPUT) {
@ -943,8 +943,8 @@ class InstrumentFunc final : public VNVisitor {
}
//ASTPIN VISITOR FUNCTION:
//The function is used to change the pin name of the original variable to the instrumented
//variable name. This is done to ensure that the pin is correctly linked to the instrumented
//The function is used to change the pin name of the original variable to the hook-inserted
//variable name. This is done to ensure that the pin is correctly linked to the hook-inserted
//variable in the cell.
void visit(AstPin* nodep) override {
if (nodep->name() == m_orig_varp->name()
@ -959,14 +959,14 @@ class InstrumentFunc final : public VNVisitor {
//The function is used to further specify the task node created at the module visitor.
void visit(AstTask* nodep) override {
if (m_addedTask == false && nodep == m_taskp && m_current_module != nullptr) {
AstVar* instrID = nullptr;
AstVar* insID = nullptr;
AstVar* var_x_task = nullptr;
AstVar* tmp_var_task = nullptr;
instrID = new AstVar{nodep->fileline(), VVarType::PORT, "instrID", VFlagChildDType{},
insID = new AstVar{nodep->fileline(), VVarType::PORT, "insID", VFlagChildDType{},
new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::INT,
VSigning::SIGNED, 32, 0}};
instrID->direction(VDirection::INPUT);
insID->direction(VDirection::INPUT);
var_x_task = m_orig_varp->cloneTree(false);
var_x_task->varType(VVarType::PORT);
@ -976,7 +976,7 @@ class InstrumentFunc final : public VNVisitor {
tmp_var_task->varType(VVarType::PORT);
tmp_var_task->direction(VDirection::OUTPUT);
nodep->addStmtsp(instrID);
nodep->addStmtsp(insID);
nodep->addStmtsp(var_x_task);
nodep->addStmtsp(tmp_var_task);
}
@ -986,14 +986,14 @@ class InstrumentFunc final : public VNVisitor {
//The function is used to further specify the function node created at the module visitor.
void visit(AstFunc* nodep) override {
if (m_addedFunc == false && nodep == m_funcp && m_current_module != nullptr) {
AstVar* instrID = nullptr;
AstVar* insID = nullptr;
AstVar* dpi_trigger = nullptr;
AstVar* var_x_func = nullptr;
instrID = new AstVar{nodep->fileline(), VVarType::PORT, "instrID", VFlagChildDType{},
insID = new AstVar{nodep->fileline(), VVarType::PORT, "insID", VFlagChildDType{},
new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::INT,
VSigning::SIGNED, 32, 0}};
instrID->direction(VDirection::INPUT);
insID->direction(VDirection::INPUT);
var_x_func = m_orig_varp->cloneTree(false);
var_x_func->varType(VVarType::PORT);
@ -1002,7 +1002,7 @@ class InstrumentFunc final : public VNVisitor {
dpi_trigger->varType(VVarType::PORT);
dpi_trigger->direction(VDirection::INPUT);
nodep->addStmtsp(instrID);
nodep->addStmtsp(insID);
nodep->addStmtsp(dpi_trigger);
nodep->addStmtsp(var_x_func);
}
@ -1047,7 +1047,7 @@ class InstrumentFunc final : public VNVisitor {
void visit(AstVar* nodep) override {
if (m_current_module != nullptr && nodep->name() == m_orig_varp->name()) {
m_orig_varp_instMod = nodep;
m_orig_varp_insMod = nodep;
}
}
@ -1061,13 +1061,13 @@ class InstrumentFunc final : public VNVisitor {
static_cast<uint32_t>(getMapEntryFaultCase(m_targetKey, m_targetIndex))};
AstVarRef* added_varrefp
= new AstVarRef{nodep->fileline(), m_orig_varp_instMod, VAccess::READ};
= new AstVarRef{nodep->fileline(), m_orig_varp_insMod, VAccess::READ};
nodep->addPinsp(new AstArg{nodep->fileline(), "", constp_id});
nodep->addPinsp(new AstArg{nodep->fileline(), "", added_varrefp});
nodep->addPinsp(new AstArg{nodep->fileline(), "",
new AstParseRef{nodep->fileline(), m_tmp_varp->name()}});
m_orig_varp_instMod = nullptr;
m_orig_varp_insMod = nullptr;
}
}
@ -1086,12 +1086,12 @@ class InstrumentFunc final : public VNVisitor {
= new AstVarRef{nodep->fileline(), m_dpi_trigger, VAccess::READ};
AstVarRef* added_varrefp
= new AstVarRef{nodep->fileline(), m_orig_varp_instMod, VAccess::READ};
= new AstVarRef{nodep->fileline(), m_orig_varp_insMod, VAccess::READ};
nodep->addPinsp(new AstArg{nodep->fileline(), "", constp_id});
nodep->addPinsp(new AstArg{nodep->fileline(), "", added_triggerp});
nodep->addPinsp(new AstArg{nodep->fileline(), "", added_varrefp});
m_orig_varp_instMod = nullptr;
m_orig_varp_insMod = nullptr;
m_funcrefp = nullptr;
}
}
@ -1100,21 +1100,21 @@ class InstrumentFunc final : public VNVisitor {
//Sets the m_assignw flag to true if the current module is not null.
//Necessary for the AstParseRef visitor function to determine if the current node is part of an
//assignment.
void visit(AstAssignW* nodep) override { instrAssigns(nodep); }
void visit(AstAssign* nodep) override { instrAssigns(nodep); }
void visit(AstAssignDly* nodep) override { instrAssigns(nodep); }
void visit(AstAssignForce* nodep) override { instrAssigns(nodep); }
void visit(AstAssignW* nodep) override { insAssigns(nodep); }
void visit(AstAssign* nodep) override { insAssigns(nodep); }
void visit(AstAssignDly* nodep) override { insAssigns(nodep); }
void visit(AstAssignForce* nodep) override { insAssigns(nodep); }
//ASTPARSE REF VISITOR FUNCTION:
//The function is used to change the parseref nodes to link to the instrumented variable
//The function is used to change the parseref nodes to link to the hook-inserted variable
//instead of the original variable. Depending on the direction of the original variable,
//different actions are performed:
// - If the original variable is not an output variable and the assignment is true, the
//parseref node is changed to link to the instrumented variable. This ensures that the
//instrumented variable is used in the assignment.
//parseref node is changed to link to the hook-inserted variable. This ensures that the
//hook-inserted variable is used in the assignment.
// - If the original variable is an input variable, every parseref node is changed to link
// to
//the instrumented variable. This ensures that the instrumented variable is used as the new
//the hook-inserted variable. This ensures that the hook-inserted variable is used as the new
//input.
void visit(AstParseRef* nodep) override {
if (m_current_module != nullptr && m_orig_varp != nullptr
@ -1130,24 +1130,24 @@ class InstrumentFunc final : public VNVisitor {
public:
// CONSTRUCTORS
explicit InstrumentFunc(AstNetlist* nodep) { iterate(nodep); }
~InstrumentFunc() override = default;
explicit HookInsFunc(AstNetlist* nodep) { iterate(nodep); }
~HookInsFunc() override = default;
};
//##################################################################################
// Instrumentation class functions
// Hook-insertion class functions
// Function to find instrumentation targets and additional information for the instrumentation
// Function to find hook-insertion targets and additional information for the hook-insertion
// process
void V3Instrument::findTargets(AstNetlist* nodep) {
void V3InsertHook::findTargets(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ InstrumentTargetFndr{nodep}; }
V3Global::dumpCheckGlobalTree("instrumentationFinder", 0, dumpTreeEitherLevel() >= 3);
{ HookInsTargetFndr{nodep}; }
V3Global::dumpCheckGlobalTree("hookInsertFinder", 0, dumpTreeEitherLevel() >= 3);
}
// Function for the actual instrumentation process
void V3Instrument::instrument(AstNetlist* nodep) {
// Function for the actual hook-insertion process
void V3InsertHook::insertHooks(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ InstrumentFunc{nodep}; }
V3Global::dumpCheckGlobalTree("instrumentationFunction", 0, dumpTreeEitherLevel() >= 3);
{ HookInsFunc{nodep}; }
V3Global::dumpCheckGlobalTree("hookInsertFunction", 0, dumpTreeEitherLevel() >= 3);
}

View File

@ -14,8 +14,8 @@
//
//*************************************************************************
#ifndef VERILATOR_V3INSTRUMENT_H_
#define VERILATOR_V3INSTRUMENT_H_
#ifndef VERILATOR_V3INSERTHOOK_H_
#define VERILATOR_V3INSERTHOOK_H_
#include "config_build.h"
#include "verilatedos.h"
@ -24,10 +24,10 @@ class AstNetlist;
//=========================================================================
class V3Instrument final {
class V3InsertHook final {
public:
static void findTargets(AstNetlist* nodep) VL_MT_DISABLED;
static void instrument(AstNetlist* nodep) VL_MT_DISABLED;
static void insertHooks(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard

View File

@ -1946,7 +1946,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
addIncDirUser(parseFileArg(optdir, string{valp}));
});
DECL_OPTION("-instrument", OnOff, &m_instrument);
DECL_OPTION("-insert-hook", OnOff, &m_insertHook);
DECL_OPTION("-dump-signals", OnOff, &m_dumpSignals);
parser.finalize();

View File

@ -309,7 +309,7 @@ private:
bool m_waiverMultiline = false; // main switch: --waiver-multiline
bool m_xInitialEdge = false; // main switch: --x-initial-edge
bool m_xmlOnly = false; // main switch: --xml-only
bool m_instrument = false; // main switch: --instrument
bool m_insertHook = false; // main switch: --insert-hook
int m_buildJobs = -1; // main switch: --build-jobs, -j
int m_coverageExprMax = 32; // main switch: --coverage-expr-max
@ -587,7 +587,7 @@ public:
bool xmlOnly() const { return m_xmlOnly; }
bool serializeOnly() const { return m_xmlOnly || m_jsonOnly; }
bool topIfacesSupported() const { return lintOnly() && !hierarchical(); }
bool instrument() const { return m_instrument; }
bool insertHook() const { return m_insertHook; }
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
int convergeLimit() const { return m_convergeLimit; }

View File

@ -65,7 +65,7 @@
#include "V3HierBlock.h"
#include "V3Inline.h"
#include "V3Inst.h"
#include "V3Instrument.h"
#include "V3InsertHook.h"
#include "V3Interface.h"
#include "V3Life.h"
#include "V3LifePost.h"
@ -156,11 +156,11 @@ static void process() {
if (v3Global.opt.dumpSignals()) { V3DumpSignals::dumpSignals(v3Global.rootp()); }
// Instrument Design with the configurations given in .vlt file
if (v3Global.opt.instrument()) {
// Hook-insert design with the configurations given in .vlt file
if (v3Global.opt.insertHook()) {
v3Global.dpi(true);
V3Instrument::findTargets(v3Global.rootp());
V3Instrument::instrument(v3Global.rootp());
V3InsertHook::findTargets(v3Global.rootp());
V3InsertHook::insertHooks(v3Global.rootp());
}
// Convert parseref's to varrefs, and other directly post parsing fixups

View File

@ -123,7 +123,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"hier_params" { FL; return yVLT_HIER_PARAMS; }
"hier_workers" { FL; return yVLT_HIER_WORKERS; }
"inline" { FL; return yVLT_INLINE; }
"instrument" { FL; return yVLT_INSTRUMENT; }
"insert_hook" { FL; return yVLT_INSERTHOOK; }
"isolate_assignments" { FL; return yVLT_ISOLATE_ASSIGNMENTS; }
"lint_off" { FL; return yVLT_LINT_OFF; }
"lint_on" { FL; return yVLT_LINT_ON; }

View File

@ -250,7 +250,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yVLT_HIER_PARAMS "hier_params"
%token<fl> yVLT_HIER_WORKERS "hier_workers"
%token<fl> yVLT_INLINE "inline"
%token<fl> yVLT_INSTRUMENT "instrument"
%token<fl> yVLT_INSERTHOOK "insert_hook"
%token<fl> yVLT_ISOLATE_ASSIGNMENTS "isolate_assignments"
%token<fl> yVLT_LINT_OFF "lint_off"
%token<fl> yVLT_LINT_ON "lint_on"
@ -8013,8 +8013,8 @@ vltItem:
{ /* Historical, now has no effect */ }
| vltInlineFront vltDModuleE vltDFTaskE
{ V3Control::addInline($<fl>1, *$2, *$3, $1); }
| yVLT_INSTRUMENT yVLT_D_CALLBACK yaSTRING yVLT_D_ID yaINTNUM yVLT_D_TARGET yaSTRING
{ V3Control::addInstrumentCfg($<fl>1, *$3, $5->toSInt(), *$7); }
| yVLT_INSERTHOOK yVLT_D_CALLBACK yaSTRING yVLT_D_ID yaINTNUM yVLT_D_TARGET yaSTRING
{ V3Control::addHookInsCfg($<fl>1, *$3, $5->toSInt(), *$7); }
| yVLT_COVERAGE_BLOCK_OFF vltDFile
{ V3Control::addCoverageBlockOff(*$2, 0); }
| yVLT_COVERAGE_BLOCK_OFF vltDFile yVLT_D_LINES yaINTNUM