mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Internals: Move the eval loop into the runtime library (#8225)
The loops modelling the SystemVerilog scheduling regions are no longer generated. They now live in 'VerilatedEvalLoop' in the runtime library. The generated model holds one as a member, passing itself to it, and exposes each evaluation entry point to it as a pure virtual method on VerilatedModel. The model's 'eval' and 'eval_step' remain the top level entry points, and are backward compatible. V3Sched no longer emits '_eval' or '_eval_settle', etc.. Instead every evaluation entry point called from the runtime is enumerated by 'VEval', Scheduling creates all entry points, for all scheduling regions, even if they are empty, and the runtime eval loop calls everything unconditionally. If regions are empty, this is simply a call to an empty function. This will hurt performance on very small models, but should not be noticeable on anything meaningful, so it is likely best to keep to reduce complexity. A scheduling entry points evaluate a single iteration and returns whether it did any work, they are effectively the previous `_eval_phase_*` functions.
This commit is contained in:
+25
-2
@@ -22,6 +22,8 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Hasher.h"
|
||||
#include "V3InstrCount.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3String.h"
|
||||
|
||||
#include "V3Ast__gen_impl.h" // Generated by 'astgen'
|
||||
@@ -602,6 +604,15 @@ const char* AstNetlist::broken() const {
|
||||
for (const AstVar* const varp : m_deferredParamVarps) {
|
||||
BROKEN_RTN(!varp || !varp->brokeExists());
|
||||
}
|
||||
for (int i = 0; i < VEval::_ENUM_END; ++i) {
|
||||
const AstCFunc* const funcp = m_evalFuncps[i];
|
||||
const AstCFunc* const dumpp = m_dumpTriggersFuncps[i];
|
||||
BROKEN_RTN(funcp && !funcp->brokeExists());
|
||||
BROKEN_RTN(dumpp && !dumpp->brokeExists());
|
||||
// Once created, an entry point has a trigger dump iff it has triggers
|
||||
BROKEN_RTN(funcp && VEval{i}.hasTriggers() && !dumpp);
|
||||
BROKEN_RTN(dumpp && !VEval{i}.hasTriggers());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -2964,13 +2975,13 @@ void AstNetlist::deleteContents() {
|
||||
m_constPoolp = nullptr;
|
||||
m_dollarUnitPkgp = nullptr;
|
||||
m_stdPackagep = nullptr;
|
||||
m_evalp = nullptr;
|
||||
m_evalNbap = nullptr;
|
||||
m_dpiExportTriggerp = nullptr;
|
||||
m_delaySchedulerp = nullptr;
|
||||
m_nbaEventp = nullptr;
|
||||
m_nbaEventTriggerp = nullptr;
|
||||
m_topScopep = nullptr;
|
||||
m_evalFuncps.fill(nullptr);
|
||||
m_dumpTriggersFuncps.fill(nullptr);
|
||||
if (op1p()) op1p()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (op2p()) op2p()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (op3p()) op3p()->unlinkFrBackWithNext()->deleteTree();
|
||||
@@ -3014,6 +3025,18 @@ AstFuncRef* AstNetlist::stdPackageProcessSelfp(FileLine* flp) const {
|
||||
processSelfp->classOrPackagep(v3Global.rootp()->stdPackageProcessp());
|
||||
return processSelfp;
|
||||
}
|
||||
void AstNetlist::addEvalStats(const std::string& phase) {
|
||||
if (!v3Global.opt.stats()) return;
|
||||
for (int i = 0; i < VEval::_ENUM_END; ++i) {
|
||||
VEval eval{i};
|
||||
AstCFunc* const funcp = m_evalFuncps[i];
|
||||
if (!funcp) continue;
|
||||
const uint32_t nodes = funcp->nodeCount();
|
||||
const uint32_t instr = V3InstrCount::count(funcp, false);
|
||||
V3Stats::addStat("Size of eval, nodes - '" + eval.tag() + "', " + phase, nodes);
|
||||
V3Stats::addStat("Size of eval, instr - '" + eval.tag() + "', " + phase, instr);
|
||||
}
|
||||
}
|
||||
void AstNodeModule::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " L" << level();
|
||||
|
||||
Reference in New Issue
Block a user