feat: Add V3Instrumentation-Pass

This commit is contained in:
Jonathan Schröter 2025-10-01 13:00:10 +02:00
parent cb3c2706a8
commit 8cd34bc05b
11 changed files with 1229 additions and 0 deletions

View File

@ -115,6 +115,7 @@ set(HEADERS
V3Inline.h
V3Inst.h
V3InstrCount.h
V3Instrumentation.h
V3Interface.h
V3LangCode.h
V3LanguageWords.h
@ -285,6 +286,7 @@ set(COMMON_SOURCES
V3Inline.cpp
V3Inst.cpp
V3InstrCount.cpp
V3Instrumentation.cpp
V3Interface.cpp
V3Life.cpp
V3LifePost.cpp

View File

@ -285,6 +285,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Inline.o \
V3Inst.o \
V3InstrCount.o \
V3Instrumentation.o \
V3Interface.o \
V3Life.o \
V3LifePost.o \

View File

@ -558,6 +558,7 @@ class V3ControlResolver final {
uint8_t m_mode = NONE;
std::unordered_map<string, V3ControlResolverHierWorkerEntry> m_hierWorkers;
FileLine* m_profileFileLine = nullptr;
std::map<string, InstrumentationTarget, LengthThenLexiographic> m_instrCfg;
V3ControlResolver() = default;
~V3ControlResolver() = default;
@ -622,6 +623,41 @@ public:
return cost;
}
}
// Helper for adding targets to the instrumentation config map
std::pair<string, string> splitPrefixAndVar(const string& target) {
auto pos = target.rfind('.');
if (pos == string::npos) {
// No prefix, return error
}
string prefix = target.substr(0, pos);
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 addInstrumentationConfigs(FileLine* fl, const string& instrFunction, int instrID,
const string& target) {
// Error MSG if the instrumentation 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!"
" ... Target string: " << target);
}
// Implement custom iterator to remove the last part of the target and insert it into the vector of the map
// If the target string is the same as one already in the map, push the var to the vector
auto [prefix, varTarget] = splitPrefixAndVar(target);
InstrumentationEntry entry{instrID, instrFunction, varTarget};
auto it = m_instrCfg.find(prefix);
if (it != m_instrCfg.end()) {
it->second.entries.push_back(entry);
} else {
// Create a new entry in the map
InstrumentationTarget newTarget;
newTarget.entries.push_back(entry);
m_instrCfg[prefix] = std::move(newTarget);
}
}
std::map<string, InstrumentationTarget, LengthThenLexiographic>& getInstrumentationConfigs() {
return m_instrCfg;
}
};
//######################################################################
@ -680,6 +716,11 @@ void V3Control::addModulePragma(const string& module, VPragmaType pragma) {
V3ControlResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Control::addInstrumentationConfigs(FileLine* fl, const string& instrumentationfunc,
int instrID, const string& target) {
V3ControlResolver::s().addInstrumentationConfigs(fl, instrumentationfunc, instrID, target);
}
void V3Control::addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
V3ControlResolver::s().addProfileData(fl, hierDpi, cost);
}
@ -810,6 +851,9 @@ int V3Control::getHierWorkers(const string& model) {
FileLine* V3Control::getHierWorkersFileLine(const string& model) {
return V3ControlResolver::s().getHierWorkersFileLine(model);
}
std::map<string, InstrumentationTarget, LengthThenLexiographic>& V3Control::getInstrumentationConfigs() {
return V3ControlResolver::s().getInstrumentationConfigs();
}
uint64_t V3Control::getProfileData(const string& hierDpi) {
return V3ControlResolver::s().getProfileData(hierDpi);
}

View File

@ -26,6 +26,31 @@
#include "V3Mutex.h"
//######################################################################
struct LengthThenLexiographic final {
// Used to sort strings by length, then lexicographically
bool operator()(const string& a, const string& b) const {
if (a.length() != b.length()) return a.length() < b.length();
return a < b;
}
};
struct InstrumentationEntry final {
int instrID;
std::string instrFunc;
std::string varTarget;
AstVar* origVarps;
AstVar* instrVarps;
};
struct InstrumentationTarget final {
std::vector<InstrumentationEntry> entries;
AstModule* origModulep;
AstModule* instrModulep;
AstModule* topModulep;
AstModule* pointingModulep;
AstCell* cellp;
bool processed = false;
bool done = false;
bool multipleCellps = false;
};
class V3Control final {
public:
@ -38,6 +63,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 addInstrumentationConfigs(FileLine* fl, const string& instrumentationfunc,
int instrID, const string& target);
static std::map<string, InstrumentationTarget, LengthThenLexiographic>& getInstrumentationConfigs();
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,

1098
src/V3Instrumentation.cpp Normal file

File diff suppressed because it is too large Load Diff

33
src/V3Instrumentation.h Normal file
View File

@ -0,0 +1,33 @@
// -*- 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
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef VERILATOR_V3INSTRUMENTATION_H_
#define VERILATOR_V3INSTRUMENTATION_H_
#include "config_build.h"
#include "verilatedos.h"
class AstNetlist;
//=========================================================================
class V3Instrumentation final {
public:
static void findTargets(AstNetlist* nodep) VL_MT_DISABLED;
static void instrument(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard

View File

@ -1919,6 +1919,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
addIncDirUser(parseFileArg(optdir, string{valp}));
});
DECL_OPTION("-instrument", OnOff, &m_instrument);
parser.finalize();
for (int i = 0; i < argc;) {

View File

@ -306,6 +306,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
int m_buildJobs = -1; // main switch: --build-jobs, -j
int m_coverageExprMax = 32; // main switch: --coverage-expr-max
@ -578,6 +579,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; }
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
int convergeLimit() const { return m_convergeLimit; }

View File

@ -63,6 +63,7 @@
#include "V3HierBlock.h"
#include "V3Inline.h"
#include "V3Inst.h"
#include "V3Instrumentation.h"
#include "V3Interface.h"
#include "V3Life.h"
#include "V3LifePost.h"
@ -151,6 +152,14 @@ static void process() {
v3Global.vlExit(0);
}
// Instrument Design with the configurations given in .vlt file
if (v3Global.opt.instrument()) {
v3Global.dpi(true);
V3Instrumentation::findTargets(v3Global.rootp());
V3Error::abortIfErrors();
V3Instrumentation::instrument(v3Global.rootp());
}
// Convert parseref's to varrefs, and other directly post parsing fixups
V3LinkParse::linkParse(v3Global.rootp());
// Cross-link signal names

View File

@ -123,6 +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; }
"isolate_assignments" { FL; return yVLT_ISOLATE_ASSIGNMENTS; }
"lint_off" { FL; return yVLT_LINT_OFF; }
"lint_on" { FL; return yVLT_LINT_ON; }
@ -149,6 +150,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
-?"-file" { FL; return yVLT_D_FILE; }
-?"-function" { FL; return yVLT_D_FUNCTION; }
-?"-hier-dpi" { FL; return yVLT_D_HIER_DPI; }
-?"-id" { FL; return yVLT_D_ID; }
-?"-instance" { FL; return yVLT_D_INSTANCE; }
-?"-levels" { FL; return yVLT_D_LEVELS; }
-?"-lines" { FL; return yVLT_D_LINES; }
-?"-match" { FL; return yVLT_D_MATCH; }
@ -157,6 +160,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
-?"-mtask" { FL; return yVLT_D_MTASK; }
-?"-rule" { FL; return yVLT_D_RULE; }
-?"-scope" { FL; return yVLT_D_SCOPE; }
-?"-target" { FL; return yVLT_D_TARGET; }
-?"-task" { FL; return yVLT_D_TASK; }
-?"-var" { FL; return yVLT_D_VAR; }
-?"-workers" { FL; return yVLT_D_WORKERS; }

View File

@ -250,6 +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_ISOLATE_ASSIGNMENTS "isolate_assignments"
%token<fl> yVLT_LINT_OFF "lint_off"
%token<fl> yVLT_LINT_ON "lint_on"
@ -276,6 +277,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yVLT_D_FILE "--file"
%token<fl> yVLT_D_FUNCTION "--function"
%token<fl> yVLT_D_HIER_DPI "--hier-dpi"
%token<fl> yVLT_D_ID "--id"
%token<fl> yVLT_D_INSTANCE "--instance"
%token<fl> yVLT_D_LEVELS "--levels"
%token<fl> yVLT_D_LINES "--lines"
%token<fl> yVLT_D_MATCH "--match"
@ -284,6 +287,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yVLT_D_MTASK "--mtask"
%token<fl> yVLT_D_RULE "--rule"
%token<fl> yVLT_D_SCOPE "--scope"
%token<fl> yVLT_D_TARGET "--target"
%token<fl> yVLT_D_TASK "--task"
%token<fl> yVLT_D_VAR "--var"
%token<fl> yVLT_D_WORKERS "--workers"
@ -7995,6 +7999,8 @@ vltItem:
{ /* Historical, now has no effect */ }
| vltInlineFront vltDModuleE vltDFTaskE
{ V3Control::addInline($<fl>1, *$2, *$3, $1); }
| yVLT_INSTRUMENT yVLT_D_MODEL yaSTRING yVLT_D_ID yaINTNUM yVLT_D_TARGET yaSTRING
{ V3Control::addInstrumentationConfigs($<fl>1, *$3, $5->toSInt(), *$7); }
| yVLT_COVERAGE_BLOCK_OFF vltDFile
{ V3Control::addCoverageBlockOff(*$2, 0); }
| yVLT_COVERAGE_BLOCK_OFF vltDFile yVLT_D_LINES yaINTNUM