Refactor loops in V3Active ; add three tests to vlt_all, so they run with threading
Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
parent
1ec09f9d2d
commit
a30e729852
159
src/V3Active.cpp
159
src/V3Active.cpp
|
|
@ -627,59 +627,45 @@ public:
|
|||
class CovergroupSamplingVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Reuse active naming infrastructure
|
||||
AstScope* m_scopep = nullptr; // Current scope
|
||||
bool m_inFirstPass = true; // First pass collects CFuncs, second pass adds sampling
|
||||
std::unordered_map<const AstClass*, AstCFunc*>
|
||||
m_covergroupSampleFuncs; // Class -> sample CFunc
|
||||
|
||||
// Helper to get the clocking event from a covergroup class
|
||||
AstSenTree* getCovergroupEvent(AstClass* classp) {
|
||||
// The AstCovergroup (holding the SenTree) was left in membersp by V3Covergroup
|
||||
for (AstNode* memberp = classp->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) {
|
||||
if (cgp->eventp()) return cgp->eventp();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
std::unordered_map<const AstClass*, AstSenTree*>
|
||||
m_covergroupEvents; // Class -> sampling event (if any)
|
||||
|
||||
// VISITORS
|
||||
void visit(AstScope* nodep) override {
|
||||
m_scopep = nodep;
|
||||
m_namer.main(nodep); // Initialize active naming for this scope
|
||||
|
||||
// First pass: collect sample CFuncs from covergroup class scopes
|
||||
// First pass: collect sample CFuncs and sampling events from covergroup class scopes
|
||||
if (m_inFirstPass) {
|
||||
// Check if this is a covergroup class scope (contains sample CFunc)
|
||||
for (AstNode* itemp = m_scopep->blocksp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCFunc* const cfuncp = VN_CAST(itemp, CFunc)) {
|
||||
if (cfuncp->name().find("sample") != string::npos) {
|
||||
// This is a covergroup class scope - find the class and store the CFunc
|
||||
// The scope name is like "TOP.t__03a__03acg", extract class name
|
||||
string scopeName = nodep->name();
|
||||
size_t dotPos = scopeName.find('.');
|
||||
if (dotPos != string::npos) {
|
||||
string className = scopeName.substr(dotPos + 1);
|
||||
// Search netlist for the matching covergroup class
|
||||
for (AstNode* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = modp->nextp()) {
|
||||
if (AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (classp->isCovergroup() && classp->name() == className) {
|
||||
m_covergroupSampleFuncs[classp] = cfuncp;
|
||||
cfuncp->isCovergroupSample(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
AstClass* const classp = VN_CAST(nodep->modp(), Class);
|
||||
if (classp && classp->isCovergroup()) {
|
||||
for (AstNode* itemp = nodep->blocksp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCFunc* const cfuncp = VN_CAST(itemp, CFunc)) {
|
||||
if (cfuncp->name().find("sample") != string::npos) {
|
||||
m_covergroupSampleFuncs[classp] = cfuncp;
|
||||
cfuncp->isCovergroupSample(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (AstNode* memberp = classp->membersp(); memberp;) {
|
||||
AstNode* const nextp = memberp->nextp();
|
||||
if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) {
|
||||
// Unlink eventp from cgp so it survives cgp's deletion,
|
||||
// then take ownership in the map for use during the second pass.
|
||||
if (cgp->eventp()) m_covergroupEvents[classp] = cgp->eventp()->unlinkFrBack();
|
||||
cgp->unlinkFrBack();
|
||||
VL_DO_DANGLING(cgp->deleteTree(), cgp);
|
||||
break;
|
||||
}
|
||||
memberp = nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterateChildren(nodep);
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
|
||||
void visit(AstVarScope* nodep) override {
|
||||
|
|
@ -701,50 +687,17 @@ class CovergroupSamplingVisitor final : public VNVisitor {
|
|||
if (!classp || !classp->isCovergroup()) return;
|
||||
|
||||
// Check if this covergroup has an automatic sampling event
|
||||
AstSenTree* const eventp = getCovergroupEvent(classp);
|
||||
if (!eventp) return; // No automatic sampling for this covergroup
|
||||
const auto evtIt = m_covergroupEvents.find(classp);
|
||||
if (evtIt == m_covergroupEvents.end()) return; // No automatic sampling for this covergroup
|
||||
AstSenTree* const eventp = evtIt->second;
|
||||
|
||||
// Get the sample CFunc - we need to find it in the class scope
|
||||
// The class scope name is like "TOP.t__03a__03acg" for class "t__03a__03acg"
|
||||
const string classScopeName = string("TOP.") + classp->name();
|
||||
|
||||
AstCFunc* sampleCFuncp = nullptr;
|
||||
// Search through all scopes to find the class scope and its sample CFunc
|
||||
for (AstNode* scopeNode = m_scopep; scopeNode; scopeNode = scopeNode->backp()) {
|
||||
if (AstNetlist* netlistp = VN_CAST(scopeNode, Netlist)) {
|
||||
// Found netlist, search its modules for scopes
|
||||
for (AstNode* modp = netlistp->modulesp(); modp; modp = modp->nextp()) {
|
||||
if (AstScope* scopep = VN_CAST(modp, Scope)) {
|
||||
if (scopep->name() == classScopeName) {
|
||||
// Found the class scope, now find the sample CFunc
|
||||
for (AstNode* itemp = scopep->blocksp(); itemp;
|
||||
itemp = itemp->nextp()) {
|
||||
if (AstCFunc* cfuncp = VN_CAST(itemp, CFunc)) {
|
||||
if (cfuncp->name().find("sample") != string::npos) {
|
||||
sampleCFuncp = cfuncp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sampleCFuncp) {
|
||||
// Fallback: try the cached version
|
||||
auto it = m_covergroupSampleFuncs.find(classp);
|
||||
if (it != m_covergroupSampleFuncs.end()) { sampleCFuncp = it->second; }
|
||||
}
|
||||
|
||||
if (!sampleCFuncp) {
|
||||
// Get the sample CFunc from the map populated during the first pass
|
||||
const auto it = m_covergroupSampleFuncs.find(classp);
|
||||
if (it == m_covergroupSampleFuncs.end()) {
|
||||
UINFO(4, "Could not find sample() CFunc for covergroup " << classp->name() << endl);
|
||||
return; // CFunc not found
|
||||
return;
|
||||
}
|
||||
UASSERT_OBJ(sampleCFuncp, nodep, "Sample CFunc is null for covergroup");
|
||||
AstCFunc* const sampleCFuncp = it->second;
|
||||
|
||||
// Create a VarRef to the covergroup instance for the method call
|
||||
FileLine* const fl = nodep->fileline();
|
||||
|
|
@ -761,35 +714,11 @@ class CovergroupSamplingVisitor final : public VNVisitor {
|
|||
// Set argTypes to "vlSymsp" so the emit code will pass it automatically
|
||||
cmethodCallp->argTypes("vlSymsp");
|
||||
|
||||
// Clone the sensitivity for this active block
|
||||
// Each VarRef in the sensitivity needs to be updated for the current scope
|
||||
// Clone the sensitivity for this active block.
|
||||
// V3Scope has already resolved all VarRefs in eventp, so the clone
|
||||
// inherits correct varScopep values with no fixup needed.
|
||||
AstSenTree* senTreep = eventp->cloneTree(false);
|
||||
|
||||
// Fix up VarRefs in the cloned sensitivity - they need varScopep set
|
||||
senTreep->foreach([this](AstVarRef* refp) {
|
||||
if (!refp->varScopep() && refp->varp()) {
|
||||
// Find the VarScope for this Var in the current scope
|
||||
AstVarScope* vscp = nullptr;
|
||||
for (AstNode* itemp = m_scopep->varsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstVarScope* const vsp = VN_CAST(itemp, VarScope)) {
|
||||
if (vsp->varp() == refp->varp()) {
|
||||
vscp = vsp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vscp) {
|
||||
refp->varScopep(vscp);
|
||||
UINFO(4, "Fixed VarRef in SenTree: " << refp->varp()->name() << " -> "
|
||||
<< vscp->name() << endl);
|
||||
} else {
|
||||
refp->v3fatalSrc("Could not find VarScope for clock signal '"
|
||||
<< refp->varp()->name() << "' in scope " << m_scopep->name()
|
||||
<< " when creating covergroup sampling active");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Get or create the AstActive node for this sensitivity
|
||||
// senTreep is a template used by getActive() which clones it into the AstActive;
|
||||
// delete it afterwards as it is not added to the AST directly.
|
||||
|
|
@ -814,7 +743,7 @@ public:
|
|||
|
||||
UINFO(4, "CovergroupSamplingVisitor: Starting" << endl);
|
||||
|
||||
// First pass: collect sample CFuncs from covergroup class scopes
|
||||
// First pass: collect sample CFuncs and sampling events; delete AstCovergroup holders
|
||||
m_inFirstPass = true;
|
||||
iterate(nodep);
|
||||
|
||||
|
|
@ -822,6 +751,10 @@ public:
|
|||
m_inFirstPass = false;
|
||||
iterate(nodep);
|
||||
|
||||
// Release the owned AstSenTree nodes that were unlinked from AstCovergroup during
|
||||
// the first pass; they are no longer needed after all clones have been made.
|
||||
for (auto& [classp, evtp] : m_covergroupEvents) VL_DO_DANGLING(evtp->deleteTree(), evtp);
|
||||
|
||||
UINFO(4, "CovergroupSamplingVisitor: Complete" << endl);
|
||||
}
|
||||
~CovergroupSamplingVisitor() override = default;
|
||||
|
|
@ -834,21 +767,5 @@ void V3Active::activeAll(AstNetlist* nodep) {
|
|||
UINFO(2, __FUNCTION__ << ":");
|
||||
{ ActiveVisitor{nodep}; } // Destruct before checking
|
||||
{ CovergroupSamplingVisitor{nodep}; } // Add automatic covergroup sampling
|
||||
// Delete AstCovergroup nodes (event holders) left in covergroup classes by
|
||||
// V3CoverageFunctional. They were kept in the AST to avoid orphaned SenTree nodes;
|
||||
// now that V3Active has consumed them we can delete them.
|
||||
for (AstNode* modp = nodep->modulesp(); modp; modp = modp->nextp()) {
|
||||
if (AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (!classp->isCovergroup()) continue;
|
||||
for (AstNode* memberp = classp->membersp(); memberp;) {
|
||||
AstNode* const nextp = memberp->nextp();
|
||||
if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) {
|
||||
cgp->unlinkFrBack();
|
||||
VL_DO_DANGLING(cgp->deleteTree(), cgp);
|
||||
}
|
||||
memberp = nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue