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:
Geza Lore
2026-08-27 07:53:02 -04:00
committed by GitHub
parent 59f221986c
commit 8546d5db06
44 changed files with 2204 additions and 1418 deletions
+7 -2
View File
@@ -51,12 +51,17 @@ def profcfunc(filename: str) -> None:
# Find modules
verilated_mods = {}
for func in funcs:
match = re.search(r'(.*)::eval(_step)?\(', func)
# Match only the model entry points: 'eval', 'eval_step', 'eval_end_step',
# and the 'evalXxx' region entry points, but not e.g. a user's '::evaluate'
match = re.match(r'([A-Za-z_][A-Za-z_0-9]*)::eval(_step|_end_step|[A-Z][A-Za-z_0-9]*)?\(',
func)
if match:
prefix = match.group(1)
if prefix.startswith('Verilated'): # Run-time library, not a model
continue
if Args.debug:
print("-got _eval %s prefix=%s" % (func, prefix))
verilated_mods[prefix] = re.compile(r'^' + prefix)
verilated_mods[prefix] = re.compile(r'^' + re.escape(prefix))
# pprint(verilated_mods)
# Sort by Verilog name
+76 -68
View File
@@ -425,8 +425,9 @@ logic.
To achieve this, we invoke ``V3Order::order`` on all of the combinational
and hybrid logic, and iterate the resulting evaluation function until no
more hybrid logic is triggered. This yields the `_eval_settle` function,
which is invoked at the beginning of simulation after the `_eval_initial`.
more hybrid logic is triggered. This yields the `_eval_stl` function, which
the runtime event loop iterates at the beginning of simulation, after the
`_eval_initial`.
Partitioning logic for correct NBA updates
@@ -500,51 +501,66 @@ and clock signals on separate evaluations, as was necessary with earlier
versions of Verilator).
Constructing the top level `_eval` function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Constructing the region evaluation functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To construct the top level `_eval` function, which updates the state of the
circuit to the end of the current time step, we invoke ``V3Order::order``
separately on the 'ico', 'act' and 'nba' logic, which yields the
`_eval_ico`, `_eval_act`, and `_eval_nba` functions. We then put these all
together with the corresponding functions that compute the respective
trigger expressions into the top level `_eval` function, which on the high
level has the form:
To update the state of the circuit to the end of the current time step, we
invoke ``V3Order::order`` separately on the 'ico', 'act' and 'nba' logic,
which yields the `_eval_body__ico`, `_eval_body__act`, and
`_eval_body__nba` functions. Each of these is then combined with the
function computing the respective trigger expressions into a single entry
point per region, `_eval_ico`, `_eval_act` and `_eval_nba`. A region entry
point evaluates one iteration of its region, and returns whether it did any
work, meaning the region has not converged yet and must be evaluated again.
On the high level, `_eval_act` has the form:
.. code-block:: C++
void _eval() {
// Update combinational logic dependent on top level inputs ('ico' region)
while (true) {
_eval__triggers__ico();
// If no 'ico' region trigger is active
if (!ico_triggers.any()) break;
_eval_ico();
}
// Iterate 'act' and 'nba' regions together
while (true) {
// Iterate 'act' region, this computes all derived clocks updaed in the
// Active scheduling region, but does not commit any NBAs that executed
// in 'act' region logic.
while (true) {
_eval__triggers__act();
// If no 'act' region trigger is active
if (!act_triggers.any()) break;
// Remember what 'act' triggers were active, 'nba' uses the same
latch_act_triggers_for_nba();
_eval_act();
}
// If no 'nba' region trigger is active
if (!nba_triggers.any()) break;
// Evaluate all other Active region logic, and commit NBAs
_eval_nba();
}
bool _eval_act() {
_eval_triggers_vec__act();
// Remember what 'act' triggers were active, 'nba' uses the same
latch_act_triggers_for_nba();
const bool execute = act_triggers.any();
// Compute all derived clocks updated in the Active scheduling region,
// but do not commit any NBAs that executed in 'act' region logic.
if (execute) _eval_body__act();
return execute;
}
The loops iterating these regions are not generated. They live in the
runtime library, in ``VerilatedEvalLoop``, and the model exposes its region
entry points to it as virtual methods of ``VerilatedModel``. The generated
model holds a ``VerilatedEvalLoop`` as a member, which its ``eval_step``
runs, and which on the high level has the form:
.. code-block:: C++
void VerilatedEvalLoop::evalImpl() {
// Update combinational logic dependent on top level inputs ('ico' region)
uint32_t icoIterCount = 0;
do {
if (++icoIterCount > m_convergeLimit) didNotConverge("Input combinational");
} while (m_model.evalIco(icoIterCount == 1));
// Iterate 'act' and 'nba' regions together
uint32_t nbaIterCount = 0;
do {
if (++nbaIterCount > m_convergeLimit) didNotConverge("NBA");
// Iterate the 'act' region to convergence
uint32_t actIterCount = 0;
do {
if (++actIterCount > m_convergeLimit) didNotConverge("Active");
} while (m_model.evalAct());
// Evaluate all other Active region logic, and commit NBAs
} while (m_model.evalNba());
}
The remaining regions ('inact', 'obs' and 'react') nest around these in the
same manner, each iterating the loops of all regions that precede it in the
SystemVerilog scheduling order. The runtime event loop calls every region
unconditionally, so scheduling emits an entry point for each one even when
the design has no logic in it. Such an entry point immediately returns
false, ending its loop after a single iteration.
Timing
------
@@ -730,7 +746,8 @@ they wouldn't be evaluated and next coroutine after resumption would fire
the event `a` then it is impossible to get to know whether await or fire on
event `a` was called first - which is necessary to know.
There are two functions for managing timing logic called by ``_eval()``:
There are two functions for managing timing logic called by the 'act'
region:
- ``_timing_ready()``, which commits all coroutines whose triggers were not
set in the current iteration,
@@ -751,36 +768,27 @@ Thanks to this separation a coroutine:
(``test_regress/t/t_event_control_double_lost.v``) - which is possible
when triggers are not evaluated right before awaiting.
All coroutines are committed and resumed in the 'act' eval loop. With
timing features enabled, the ``_eval()`` function takes this form:
All coroutines are committed and resumed in the 'act' region. With timing
features enabled, the 'act' region entry point takes this form:
::
void _eval() {
while (true) {
_eval__triggers__ico();
if (!ico_triggers.any()) break;
_eval_ico();
}
while (true) {
while (true) {
_eval__triggers__act();
// Commit all non-triggered coroutines
_timing_commit();
if (!act_triggers.any()) break;
latch_act_triggers_for_nba();
// Resume all triggered coroutines
_timing_resume();
_eval_act();
}
if (!nba_triggers.any()) break;
_eval_nba();
bool _eval_act() {
_eval_triggers_vec__act();
// Commit all non-triggered coroutines
_timing_commit();
const bool execute = act_triggers.any();
if (execute) {
latch_act_triggers_for_nba();
// Resume all triggered coroutines
_timing_resume();
_eval_body__act();
}
return execute;
}
Forks
+100
View File
@@ -4036,6 +4036,106 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
}
//===========================================================================
// VerilatedEvalLoop:: Methods
void VerilatedEvalLoop::didNotConverge(const char* namep,
void (VerilatedModel::*dumpTriggersp)()) {
if (dumpTriggersp) (m_model.*dumpTriggersp)();
const std::string msg = "DIDNOTCONVERGE: "s + namep
+ " region did not converge after '--converge-limit' of "
+ std::to_string(m_convergeLimit) + " tries";
VL_FATAL_MT("", 0, "", msg.c_str());
VL_UNREACHABLE; // VL_FATAL_MT does not return
}
template <bool Profiling>
void VerilatedEvalLoop::evalImpl() {
VL_DEBUG_IF(VL_DBG_MSGF("+ Eval\n"););
if VL_CONSTEXPR_CXX17 (Profiling) {
// Advance the profiling window
if (VL_UNLIKELY(m_profTopLevel)) m_profilerp->configure();
m_profilerp->sectionPush("eval");
}
m_model.evalBegin();
// Initialization on first time step only
if (VL_UNLIKELY(!m_model.m_didInit)) {
VL_DEBUG_IF(VL_DBG_MSGF("+ Initial\n"););
// Static initializers
m_model.evalStatic();
// Initial blocks
m_model.evalInitial();
// The 'Settle' region, iterated until it converges
uint32_t stlIterCount = 0;
do {
checkConvergence(++stlIterCount, "Settle", &VerilatedModel::dumpTriggersStl);
} while (m_model.evalStl(stlIterCount == 1));
m_model.m_didInit = true;
}
// Sampled values are collected before anything can read them
m_model.evalSample();
// The 'Input combinational' region updates combinational logic driven from primary inputs
{
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop ico");
uint32_t icoIterCount = 0;
do {
checkConvergence(++icoIterCount, "Input combinational",
&VerilatedModel::dumpTriggersIco);
} while (m_model.evalIco(icoIterCount == 1));
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop ico
}
// The remaining regions are nested: each iteration of a region's loop
// re-runs the loops of all regions that precede it in the scheduling order.
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop react");
uint32_t reactIterCount = 0;
do {
checkConvergence(++reactIterCount, "Reactive", &VerilatedModel::dumpTriggersReact);
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop obs");
uint32_t obsIterCount = 0;
do {
checkConvergence(++obsIterCount, "Observed", &VerilatedModel::dumpTriggersObs);
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop nba");
uint32_t nbaIterCount = 0;
do {
checkConvergence(++nbaIterCount, "NBA", &VerilatedModel::dumpTriggersNba);
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop inact");
uint32_t inactIterCount = 0;
do {
checkConvergence(++inactIterCount, "Inactive");
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop act");
uint32_t actIterCount = 0;
do {
checkConvergence(++actIterCount, "Active",
&VerilatedModel::dumpTriggersAct);
} while (m_model.evalAct());
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop act
} while (m_model.evalInact());
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop inact
} while (m_model.evalNba());
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop nba
} while (m_model.evalObs());
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop obs
} while (m_model.evalReact());
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop react
// The 'Postponed' region runs once, at the end of the time step
m_model.evalPostponed();
m_model.evalEnd();
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // eval
}
// Template instantiations
template void VerilatedEvalLoop::evalImpl<false>();
template void VerilatedEvalLoop::evalImpl<true>();
//===========================================================================
// VerilatedModel:: Methods
+95
View File
@@ -301,6 +301,8 @@ public:
#endif
};
class VlExecutionProfilerBase;
//=========================================================================
/// Base class of a Verilator generated (Verilated) model.
///
@@ -313,6 +315,8 @@ class VerilatedModel VL_NOT_FINAL {
VerilatedContext& m_context; // The VerilatedContext this model is instantiated under
protected:
bool m_didInit = false; // Time 0 initialization has run
explicit VerilatedModel(VerilatedContext& context);
virtual ~VerilatedModel() = default;
@@ -331,8 +335,82 @@ private:
// The following are for use by Verilator internals only
template <typename, typename>
friend class VerilatedTrace;
friend class VerilatedEvalLoop;
// Run-time trace configuration requested by this model
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
// Entry points called by VerilatedEvalLoop
virtual void evalBegin() = 0;
virtual void evalEnd() = 0;
virtual void evalStatic() = 0;
virtual void evalInitial() = 0;
virtual void evalSample() = 0;
virtual bool evalStl(bool firstIteration) = 0;
virtual bool evalIco(bool firstIteration) = 0;
virtual bool evalAct() = 0;
virtual bool evalInact() = 0;
virtual bool evalNba() = 0;
virtual bool evalObs() = 0;
virtual bool evalReact() = 0;
virtual void evalPostponed() = 0;
virtual void dumpTriggersStl() = 0;
virtual void dumpTriggersIco() = 0;
virtual void dumpTriggersAct() = 0;
virtual void dumpTriggersNba() = 0;
virtual void dumpTriggersObs() = 0;
virtual void dumpTriggersReact() = 0;
// Runs 'final' blocks at the end of the simulation
virtual void evalFinal() = 0;
};
//=========================================================================
/// Evaluation loop calling a VerilatedModel's entry points
class VerilatedEvalLoop final {
VL_UNCOPYABLE(VerilatedEvalLoop);
// MEMBERS
VerilatedModel& m_model; // The model this loop evaluates
const uint32_t m_convergeLimit; // --converge-limit from compiler command line
// Where to record --prof-exec sections, or null if not profiling
VlExecutionProfilerBase* m_profilerp = nullptr;
// Whether this is the top level model during profiling
bool m_profTopLevel = false;
public:
// CONSTRUCTORS
VerilatedEvalLoop(VerilatedModel& model, uint32_t convergeLimit)
: m_model{model}
, m_convergeLimit{convergeLimit} {}
// METHODS
// Evaluate a single time step of the SV scheduling model
void eval() {
if (VL_UNLIKELY(m_profilerp)) {
evalImpl<true>();
} else {
evalImpl<false>();
}
}
// Set --prof-exec profiler
void profiler(VlExecutionProfilerBase* profilerp, bool topLevel) {
m_profilerp = profilerp;
m_profTopLevel = topLevel;
}
private:
// Evaluate a time step, recording --prof-exec sections iff 'Profiling'.
template <bool Profiling>
void evalImpl();
// Check the iteration convergence
void checkConvergence(uint32_t iterCount, const char* namep,
void (VerilatedModel::*dumpTriggersp)() = nullptr) {
if (VL_UNLIKELY(iterCount > m_convergeLimit)) didNotConverge(namep, dumpTriggersp);
}
// Dump the region's triggers, if it has any, then report non-convergence and abort
void didNotConverge(const char* namep, void (VerilatedModel::*dumpTriggersp)());
};
//=========================================================================
@@ -357,6 +435,23 @@ public:
virtual ~VerilatedVirtualBase() = default;
};
//===========================================================================
// Internal: Base of the '--prof-exec' execution profiler
//
// Implemented by VlExecutionProfiler, see verilated_profiler.h. Declared here
// so the evaluation loop can drive the profiler without naming it, as it is
// only linked when Verilated with --prof-exec.
class VlExecutionProfilerBase VL_NOT_FINAL : public VerilatedVirtualBase {
public:
// Mark the beginning of a section of execution
virtual void sectionPush(const char* namep) = 0;
// Mark the end of the innermost open section
virtual void sectionPop() = 0;
// Advance the profiling window at the start of a time step
virtual void configure() = 0;
};
//===========================================================================
/// Verilator simulation context
///
+10 -3
View File
@@ -149,7 +149,7 @@ static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
//=============================================================================
// VlExecutionProfiler is for collecting profiling data about model execution
class VlExecutionProfiler final : public VerilatedVirtualBase {
class VlExecutionProfiler final : public VlExecutionProfilerBase {
// CONSTANTS
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
@@ -193,8 +193,15 @@ public:
t_trace.emplace_back();
return t_trace.back();
}
// Configure profiler (called in beginning of 'eval')
void configure();
// Record the beginning/end of a section, for the run-time library
void sectionPush(const char* namep) override {
if (VL_UNLIKELY(m_enabled)) addRecord().sectionPush(namep);
}
void sectionPop() override {
if (VL_UNLIKELY(m_enabled)) addRecord().sectionPop();
}
// Advance the profiling window, called by the run-time evaluation loop
void configure() override;
// Setup profiling on a particular thread;
void setupThread(uint32_t threadId);
// Clear all profiling data
+1
View File
@@ -30,6 +30,7 @@
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
#include <array>
#include <cmath>
#include <cstdint>
#include <functional>
+104
View File
@@ -1537,6 +1537,110 @@ constexpr bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs
// ######################################################################
// Enumeration of the model's evaluation entry points. Fields:
// is iterated, has triggers, takes 'firstIteration' flag, is slow
// clang-format off
#define FOR_EACH_EVAL(macro) \
/* id, iterated, hasTrigs, firstIt, slow */ \
macro(STATIC, false, false, false, true) \
macro(INITIAL, false, false, false, true) \
macro(STL, true, true, true, true) \
macro(SAMPLE, false, false, false, false) \
macro(ICO, true, true, true, false) \
macro(ACT, true, true, false, false) \
macro(INACT, true, false, false, false) \
macro(NBA, true, true, false, false) \
macro(OBS, true, true, false, false) \
macro(REACT, true, true, false, false) \
macro(POSTPONED, false, false, false, false) \
macro(FINAL, false, false, false, true)
// clang-format on
class VEval final {
public:
enum en : uint8_t {
#define VL_EVAL_ID(id, iterated, triggers, first, slow) id,
FOR_EACH_EVAL(VL_EVAL_ID)
#undef VL_EVAL_ID
_ENUM_END
};
enum en m_e;
const char* ascii() const {
static const char* const values[] = {
#define VL_EVAL_NAME(id, iterated, triggers, first, slow) #id,
FOR_EACH_EVAL(VL_EVAL_NAME)
#undef VL_EVAL_NAME
"_ENUM_END" //
};
return values[m_e];
}
bool isIterated() const {
static const bool values[] = {
#define VL_EVAL_IS_ITERATED(id, iterated, triggers, first, slow) iterated,
FOR_EACH_EVAL(VL_EVAL_IS_ITERATED)
#undef VL_EVAL_IS_ITERATED
false //
};
return values[m_e];
}
bool hasTriggers() const {
static const bool values[] = {
#define VL_EVAL_HAS_TRIGGERS(id, iterated, triggers, first, slow) triggers,
FOR_EACH_EVAL(VL_EVAL_HAS_TRIGGERS)
#undef VL_EVAL_HAS_TRIGGERS
false //
};
return values[m_e];
}
bool firstIteration() const {
static const bool values[] = {
#define VL_EVAL_FIRST(id, iterated, triggers, first, slow) first,
FOR_EACH_EVAL(VL_EVAL_FIRST)
#undef VL_EVAL_FIRST
false //
};
return values[m_e];
}
bool slow() const {
static const bool values[] = {
#define VL_EVAL_SLOW(id, iterated, triggers, first, slow) slow,
FOR_EACH_EVAL(VL_EVAL_SLOW)
#undef VL_EVAL_SLOW
false //
};
return values[m_e];
}
// Short name
std::string tag() const { return VString::downcase(ascii()); }
// Name of the generated entry point function
std::string funcName() const { return "_eval_" + tag(); }
// Name of the VerilatedModel virtual method invoking the entry point
std::string evalMethod() const { return "eval" + capitalizedTag(); }
// Name of the function dumping the triggers of this region
std::string dumpTriggersFuncName() const { return "_eval_dump_triggers__" + tag(); }
// Name of the VerilatedModel virtual method dumping this region's triggers
std::string dumpTriggersMethod() const { return "dumpTriggers" + capitalizedTag(); }
// cppcheck-suppress noExplicitConstructor
VEval(en _e)
: m_e{_e} {}
explicit VEval(int _e)
: m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
private:
std::string capitalizedTag() const {
const std::string name = ascii();
return name.substr(0, 1) + VString::downcase(name.substr(1));
}
};
#undef FOR_EACH_EVAL
// ######################################################################
class VFwdType final {
public:
enum en : uint8_t { NONE, ENUM, STRUCT, UNION, CLASS, INTERFACE_CLASS, GENERIC_INTERFACE };
+11 -6
View File
@@ -1441,8 +1441,6 @@ class AstNetlist final : public AstNode {
// @astgen ptr := m_dollarUnitPkgp : Optional[AstPackage] // $unit
// @astgen ptr := m_stdPackagep : Optional[AstPackage] // SystemVerilog std package
// @astgen ptr := m_stdPackageProcessp : Optional[AstClass] // SystemVerilog std process class
// @astgen ptr := m_evalp : Optional[AstCFunc] // The '_eval' function
// @astgen ptr := m_evalNbap : Optional[AstCFunc] // The '_eval__nba' function
// @astgen ptr := m_dpiExportTriggerp : Optional[AstVarScope] // DPI export trigger variable
// @astgen ptr := m_delaySchedulerp : Optional[AstVar] // Delay scheduler variable
// @astgen ptr := m_nbaEventp : Optional[AstVarScope] // NBA event variable
@@ -1460,6 +1458,10 @@ class AstNetlist final : public AstNode {
// AstConst itself, as AstConst is a very common node and only a small fraction carry this
// name.
std::unordered_map<const AstConst*, string> m_constOrigParamNames;
// The model's evaluation entry point functions
std::array<AstCFunc*, VEval::_ENUM_END> m_evalFuncps{};
// The trigger dump function of each region if exists, otherwise nullptr
std::array<AstCFunc*, VEval::_ENUM_END> m_dumpTriggersFuncps{};
public:
AstNetlist();
@@ -1483,10 +1485,10 @@ public:
void astConstOrigParamNameErase(const AstConst* nodep);
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
AstPackage* dollarUnitPkgAddp();
AstCFunc* evalp() const { return m_evalp; }
void evalp(AstCFunc* funcp) { m_evalp = funcp; }
AstCFunc* evalNbap() const { return m_evalNbap; }
void evalNbap(AstCFunc* funcp) { m_evalNbap = funcp; }
AstCFunc* evalFuncp(VEval eval) const { return m_evalFuncps[eval]; }
void evalFuncp(VEval eval, AstCFunc* funcp) { m_evalFuncps[eval] = funcp; }
AstCFunc* dumpTriggersFuncp(VEval eval) const { return m_dumpTriggersFuncps[eval]; }
void dumpTriggersFuncp(VEval eval, AstCFunc* funcp) { m_dumpTriggersFuncps[eval] = funcp; }
AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; }
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
@@ -1522,6 +1524,9 @@ public:
const std::string& name = resolvedTopModuleName();
return prettyName(name.empty() ? v3Global.rootp()->topModulep()->name() : name);
}
// Record statistics for eval functions
void addEvalStats(const std::string& phase);
};
class AstPackageExport final : public AstNode {
// A package export declaration
+25 -2
View File
@@ -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();
+4 -14
View File
@@ -63,7 +63,7 @@ class ClockVisitor final : public VNVisitor {
// NODE STATE
// STATE
AstCFunc* m_sampleCFuncp = nullptr; // The CFunc to populate with sampled value assignments
AstCFunc* const m_sampleCFuncp; // The CFunc to populate with sampled value assignments
// VISITORS
void visit(AstCoverToggle* nodep) override {
@@ -106,11 +106,6 @@ class ClockVisitor final : public VNVisitor {
if (!varp->valuep()) return;
if (!varp->sampled()) return;
// Create the containing function on first encounter
if (!m_sampleCFuncp) {
m_sampleCFuncp = V3Sched::util::makeSubFunction(v3Global.rootp(), "_sample", false);
}
FileLine* const flp = nodep->fileline();
AstNodeExpr* const rhsp = VN_AS(varp->valuep()->unlinkFrBack(), NodeExpr);
AstVarRef* const lhsp = new AstVarRef{flp, nodep, VAccess::WRITE};
@@ -124,15 +119,10 @@ class ClockVisitor final : public VNVisitor {
public:
// CONSTRUCTORS
explicit ClockVisitor(AstNetlist* netlistp) {
explicit ClockVisitor(AstNetlist* netlistp)
: m_sampleCFuncp{netlistp->evalFuncp(VEval::SAMPLE)} {
iterate(netlistp);
// If we need a sample function, call it at the begining of eval
if (m_sampleCFuncp) {
V3Sched::util::splitCheck(m_sampleCFuncp);
AstCCall* const callp = new AstCCall{m_sampleCFuncp->fileline(), m_sampleCFuncp};
callp->dtypeSetVoid();
netlistp->evalp()->stmtsp()->addHereThisAsNext(callp->makeStmt());
}
V3Sched::util::splitCheck(m_sampleCFuncp);
}
~ClockVisitor() override = default;
};
+11 -4
View File
@@ -859,11 +859,18 @@ public:
if (uint64_t cost = V3Control::getProfileData(v3Global.opt.prefix())) {
UINFO(9, "Fetching cost from profile info: " << cost);
return cost;
} else {
cost = V3InstrCount::count(v3Global.rootp()->evalp(), false);
UINFO(9, "Evaluating cost: " << cost);
return cost;
}
// Without profiling data, sum the regions evaluated on each time step
const AstNetlist* const netlistp = v3Global.rootp();
uint64_t cost = 0;
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
if (eval.slow()) continue;
cost += V3InstrCount::count(netlistp->evalFuncp(eval), false);
}
UINFO(9, "Evaluating cost: " << cost);
return cost;
}
};
+77 -30
View File
@@ -31,9 +31,12 @@ class EmitCModel final : public EmitCFunc {
using CFuncVector = std::vector<const AstCFunc*>;
// MEMBERS
// Needed to emit references to functions of the model, e.g. entry points
const EmitCParentModule m_emitCParentModule;
V3UniqueNames m_uniqueNames; // For generating unique file names
// METHODS
CFuncVector findFuncps(std::function<bool(const AstCFunc*)> cb) {
CFuncVector funcps;
for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
@@ -91,11 +94,16 @@ class EmitCModel final : public EmitCFunc {
puts("public ::sc_core::sc_module, ");
}
puts("public VerilatedModel {\n");
// The symbol table references the model's evaluation state
puts("friend class " + EmitCUtil::symClassName() + ";\n");
ofp()->resetPrivate();
ofp()->putsPrivate(true); // private:
puts("// Symbol table holding complete model state (owned by this class)\n");
puts(EmitCUtil::symClassName() + "* const vlSymsp;\n");
puts("// Evaluation loop\n");
puts("VerilatedEvalLoop m_evalLoop;\n");
puts("\n");
ofp()->putsPrivate(false); // public:
@@ -258,7 +266,23 @@ class EmitCModel final : public EmitCFunc {
}
ofp()->putsPrivate(true); // private:
puts("// Internal functions - trace registration\n");
puts("\n// Internal functions - the model's evaluation entry points\n");
puts("void evalBegin() override final;\n");
puts("void evalEnd() override final;\n");
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
// Only the iterated regions report whether they did any work
puts(eval.isIterated() ? "bool "s : "void "s);
puts(eval.evalMethod() + (eval.firstIteration() ? "(bool firstIteration)"s : "()"s));
puts(" override final;\n");
}
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
if (!eval.hasTriggers()) continue;
puts("void " + eval.dumpTriggersMethod() + "() override final;\n");
}
puts("\n// Internal functions - trace registration\n");
puts("void traceBaseModel(VerilatedTraceBaseC* tfp, int levels, int options);\n");
puts("};\n");
@@ -279,11 +303,13 @@ class EmitCModel final : public EmitCFunc {
puts(" , vlSymsp{new " + EmitCUtil::symClassName()
+ "(contextp(), name(), this)}\n");
} else {
puts(+"(VerilatedContext* _vcontextp__, const char* _vcname__)\n");
puts("(VerilatedContext* _vcontextp__, const char* _vcname__)\n");
puts(" : VerilatedModel{*_vcontextp__}\n");
puts(" , vlSymsp{new " + EmitCUtil::symClassName()
+ "(contextp(), _vcname__, this)}\n");
}
puts(" , m_evalLoop{*this, /*convergeLimit:*/ "s
+ cvtToStr(v3Global.opt.convergeLimit()) + "}\n");
// Set up IO references
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
@@ -311,6 +337,12 @@ class EmitCModel final : public EmitCFunc {
puts("{\n");
puts("// Register model with the context\n");
puts("contextp()->addModel(this);\n");
if (v3Global.opt.profExec()) {
putsDecoration(nullptr, "// Profile the evaluation loop's region loops\n");
const bool topLevel = !v3Global.opt.hierChild() && v3Global.opt.libCreate().empty();
puts("m_evalLoop.profiler(vlSymsp->__Vm_executionProfilerp, /*topLevel:*/ "s
+ (topLevel ? "true" : "false") + ");\n");
}
if (v3Global.opt.trace())
puts("contextp()->traceBaseModelCbAdd(\n"
"[this](VerilatedTraceBaseC* tfp, int levels, int options) {"
@@ -382,10 +414,14 @@ class EmitCModel final : public EmitCFunc {
puts("void " + topModNameProtected + "__" + protect("_eval_debug_assertions") + selfDecl
+ ";\n");
puts("#endif // VL_DEBUG\n");
puts("void " + topModNameProtected + "__" + protect("_eval_static") + selfDecl + ";\n");
puts("void " + topModNameProtected + "__" + protect("_eval_initial") + selfDecl + ";\n");
puts("void " + topModNameProtected + "__" + protect("_eval_settle") + selfDecl + ";\n");
puts("void " + topModNameProtected + "__" + protect("_eval") + selfDecl + ";\n");
const AstNetlist* const netlistp = v3Global.rootp();
for (int i = 0; i < VEval::_ENUM_END; ++i) {
emitCFuncDecl(netlistp->evalFuncp(VEval{i}), modp);
}
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const AstCFunc* const funcp = netlistp->dumpTriggersFuncp(VEval{i});
if (funcp) emitCFuncDecl(funcp, modp);
}
if (optSystemC() && v3Global.usesTiming()) {
// ::eval
@@ -399,11 +435,15 @@ class EmitCModel final : public EmitCFunc {
puts("}\n");
}
// ::eval_step
// ::eval_step - the run-time library drives the whole time step
puts("\nvoid " + EmitCUtil::topClassName() + "::eval_step() {\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + EmitCUtil::topClassName()
+ "::eval_step\\n\"); );\n");
puts("m_evalLoop.eval();\n");
puts("}\n");
// ::evalBegin - prepare the model for a time step
puts("\nvoid " + EmitCUtil::topClassName() + "::evalBegin() {\n");
puts("#ifdef VL_DEBUG\n");
putsDecoration(nullptr, "// Debug assertions\n");
puts(topModNameProtected + "__" + protect("_eval_debug_assertions")
@@ -415,32 +455,42 @@ class EmitCModel final : public EmitCFunc {
if (v3Global.hasEvents()) puts("vlSymsp->clearTriggeredEvents();\n");
if (v3Global.hasClasses()) puts("vlSymsp->__Vm_deleter.deleteAll();\n");
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) {\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Initial\\n\"););\n");
puts(topModNameProtected + "__" + protect("_eval_static") + "(&(vlSymsp->TOP));\n");
puts(topModNameProtected + "__" + protect("_eval_initial") + "(&(vlSymsp->TOP));\n");
puts(topModNameProtected + "__" + protect("_eval_settle") + "(&(vlSymsp->TOP));\n");
puts("vlSymsp->__Vm_didInit = true;\n");
puts("}\n");
if (v3Global.opt.profExec() && !v3Global.opt.hierChild()
&& v3Global.opt.libCreate().empty()) {
puts("vlSymsp->__Vm_executionProfilerp->configure();\n");
}
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Eval\\n\"););\n");
puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n");
// ::evalEnd - the time step is complete
puts("\nvoid " + EmitCUtil::topClassName() + "::evalEnd() {\n");
putsDecoration(nullptr, "// Evaluate cleanup\n");
puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
puts("}\n");
// Evaluation entry points
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
AstCFunc* const funcp = v3Global.rootp()->evalFuncp(eval);
puts(eval.isIterated() ? "\nbool " : "\nvoid ");
puts(EmitCUtil::topClassName() + "::" + eval.evalMethod() + "(");
if (eval.firstIteration()) puts("bool firstIteration");
puts(") {\n");
if (eval.isIterated()) puts("return ");
puts(funcNameProtect(funcp, m_modp) + "(&(vlSymsp->TOP)");
if (eval.firstIteration()) puts(", firstIteration");
puts(");\n");
puts("}\n");
}
// The trigger dump of each region
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
if (!eval.hasTriggers()) continue;
puts("\nVL_ATTR_COLD void " + EmitCUtil::topClassName()
+ "::" + eval.dumpTriggersMethod() + "() {\n");
puts(funcNameProtect(v3Global.rootp()->dumpTriggersFuncp(eval), m_modp)
+ "(&(vlSymsp->TOP));\n");
puts("}\n");
}
}
void emitStandardMethods2(AstNodeModule* modp) {
const string topModNameProtected = EmitCUtil::prefixNameProtect(modp);
const string selfDecl = "(" + topModNameProtected + "* vlSelf)";
// ::eval_end_step
if (v3Global.needTraceDumper() && !optSystemC()) {
puts("\n");
@@ -485,14 +535,10 @@ class EmitCModel final : public EmitCFunc {
}
putSectionDelimiter("Invoke final blocks");
// Forward declarations
puts("\n");
putns(modp,
"void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n");
// ::final
puts("\nVL_ATTR_COLD void " + EmitCUtil::topClassName() + "::final() {\n");
puts("contextp()->executingFinal(true);\n");
puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n");
puts("evalFinal();\n");
puts("contextp()->executingFinal(false);\n");
puts("}\n");
@@ -710,5 +756,6 @@ public:
void V3EmitC::emitcModel() {
UINFO(2, __FUNCTION__ << ":");
v3Global.rootp()->addEvalStats("emitc");
{ EmitCModel{v3Global.rootp()->topModulep()}; }
}
+2 -1
View File
@@ -926,7 +926,7 @@ void EmitCSyms::emitSymHdr() {
}
}
if (v3Global.hasClasses()) puts("VlDeleter __Vm_deleter;\n");
puts("bool __Vm_didInit = false;\n");
puts("bool& __Vm_didInit;\n");
if (v3Global.opt.mtasks()) {
puts("\n// MULTI-THREADING\n");
@@ -1481,6 +1481,7 @@ void EmitCSyms::emitSymImp(const AstNetlist* netlistp) {
puts(" : VerilatedSyms{contextp}\n");
puts(" // Setup internal state of the Syms class\n");
puts(" , __Vm_modelp{modelp}\n");
puts(" , __Vm_didInit{modelp->m_didInit}\n");
if (v3Global.opt.mtasks()) {
puts(" , __Vm_threadPoolp{static_cast<VlThreadPool*>(contextp->threadPoolp())}\n");
}
-7
View File
@@ -396,13 +396,6 @@ class InlineCFuncsVisitor final : public VNVisitor {
iterateChildrenConst(nodep);
}
// Nodes that reference functions/calls
void visit(AstNetlist* nodep) override {
UASSERT_OBJ(!nodep->evalp(), nodep, "evalp should not be null at this stage");
UASSERT_OBJ(!nodep->evalNbap(), nodep, "evalNbap should be null at this stage");
iterateChildrenConst(nodep);
}
void visit(AstNodeCCall* nodep) override {
if (m_cfuncVtxp) m_cfuncVtxp->sizeInc();
getInlineCFuncsFunctionVertexp(nodep->funcp())->setKeep("Called elsewhere");
+5 -5
View File
@@ -130,8 +130,8 @@ class LifePostDlyVisitor final : public VNVisitorConst {
LocMap m_writes; // VarScope write locations
std::vector<Location<AstNodeAssign>> m_assigns; // Assignments considered for removal
std::vector<std::unique_ptr<GraphPathChecker>> m_checkers; // Storage for exec graph checkers
const AstCFunc* const m_evalNbap; // The _eval__nba function
bool m_inEvalNba = false; // Traversing under _eval__nba
const AstCFunc* const m_nbaFuncp; // The 'nba' region entry point
bool m_inEvalNba = false; // Traversing under the 'nba' region entry point
// METHODS
void squashAssignposts() {
@@ -187,7 +187,7 @@ class LifePostDlyVisitor final : public VNVisitorConst {
// Trace code in the given function
void trace(AstCFunc* nodep) {
VL_RESTORER(m_inEvalNba);
if (nodep == m_evalNbap) m_inEvalNba = true;
if (nodep == m_nbaFuncp) m_inEvalNba = true;
iterateChildrenConst(nodep);
}
@@ -232,7 +232,7 @@ class LifePostDlyVisitor final : public VNVisitorConst {
// We only try to optimize NBA shadow variables
if (!nodep->varScopep()->optimizeLifePost()) return;
// Mark variables referenced outside _eval__nba
// Mark variables referenced outside the 'nba' region
if (!m_inEvalNba) {
nodep->varScopep()->user1(true);
return;
@@ -303,7 +303,7 @@ class LifePostDlyVisitor final : public VNVisitorConst {
public:
// CONSTRUCTORS
explicit LifePostDlyVisitor(AstNetlist* netlistp)
: m_evalNbap{netlistp->evalNbap()} {
: m_nbaFuncp{netlistp->evalFuncp(VEval::NBA)} {
iterateConst(netlistp);
}
~LifePostDlyVisitor() override {
+1 -7
View File
@@ -144,7 +144,7 @@ AstCFunc* V3Order::order(AstNetlist* netlistp, //
FileLine* const flp = netlistp->fileline();
AstCFunc* const funcp = [&]() {
AstScope* const scopeTopp = netlistp->topScopep()->scopep();
AstCFunc* const resp = new AstCFunc{flp, "_eval_" + tag, scopeTopp, ""};
AstCFunc* const resp = new AstCFunc{flp, "_eval_body__" + tag, scopeTopp, ""};
resp->dontCombine(true);
resp->isStatic(false);
resp->isLoose(true);
@@ -156,13 +156,7 @@ AstCFunc* V3Order::order(AstNetlist* netlistp, //
}();
// Assemble the body
if (v3Global.opt.profExec()) {
funcp->addStmtsp(AstCStmt::profExecSectionPush(flp, "func " + tag));
}
funcp->addStmtsp(stmtsp);
if (v3Global.opt.profExec()) { //
funcp->addStmtsp(AstCStmt::profExecSectionPop(flp, "func " + tag));
}
// Done
return funcp;
+202 -285
View File
@@ -25,11 +25,14 @@
// All clocks (signals referenced in an AstSenTree) generated via a blocking assignment
// (including combinationally generated signals) are computed within the act region.
// - Replicate combinational logic
// - Create input combinational logic loop
// - Create input combinational logic region
// - Create the pre/act/nba triggers
// - Create the 'act' region evaluation function
// - Create the 'nba' region evaluation function
// - Bolt it all together to create the '_eval' function
//
// The loops iterating these regions are not generated. They live in the
// run-time (VerilatedEvalLoop), which invokes the region evaluation
// functions created here on the generated model.
//
// Details of the algorithm are described in the internals documentation docs/internals.rst
//
@@ -111,25 +114,21 @@ std::vector<AstSenTree*> findTriggeredIface(const AstVarScope* vscp,
}
//============================================================================
// Eval loop builder
// Eval region builder
struct EvalLoop final {
// Flag set to true on entry to the first iteration of the loop
AstVarScope* firstIterp;
// The loop itself and statements around it
AstNodeStmt* stmtsp;
};
// Create an eval loop with all the trimmings.
EvalLoop createEvalLoop(
// Create the evaluation function of a scheduling region. The loops iterating
// the regions live in the run-time library (see VerilatedEvalLoop), which
// invokes this function once per iteration of the region's loop via a virtual
// method on the model (see V3EmitCModel). The function returns true if the
// region did any work, in which case the loop iterates again.
void createEvalRegion(
AstNetlist* netlistp, //
const std::string& tag, // Tag for current phase
const string& name, // Name of current phase
bool slow, // Should create slow functions
VEval eval, // The entry point of the current region
// Index of the region's 'first iteration' extra trigger, if it has one, otherwise ignored
uint32_t firstIterTrigger,
const TriggerKit& trigKit, // The trigger kit
AstVarScope* trigp, // The trigger vector - may be nullptr if no triggers or using 'condp'
AstNodeExpr* condp, // Explicit condition that must be true to run 'phaseWorkp'
AstNodeStmt* innerp, // The inner loop, if any
AstNodeStmt* phasePrepp, // Prep statements run before checking triggers
AstNodeStmt* phaseWorkp, // The work to do if anything triggered
// Extra statements to run after the work, even if no triggers fired. This function is
@@ -137,118 +136,81 @@ EvalLoop createEvalLoop(
// and must be unmodified otherwise.
std::function<AstNodeStmt*(AstVarScope*)> phaseExtra = [](AstVarScope*) { return nullptr; } //
) {
UASSERT(!trigp || !condp, "Cannot use both 'trigp' and 'condp' in 'createEvalLoop'");
UASSERT(!trigp || !condp, "Cannot use both 'trigp' and 'condp' in 'createEvalRegion'");
UASSERT(!eval.firstIteration() || trigp,
"Region without triggers cannot need a first iteration flag");
// All work is under a trigger or condition, so if there are none,
// there is nothing to do besides executing the inner loop.
if (!trigp && !condp) return {nullptr, innerp};
// All work is under a trigger or condition, so with neither the region has
// nothing to evaluate, and what we create below reduces to a no-op function.
const std::string tag = eval.tag();
const std::string varPrefix = "__V" + tag;
AstScope* const scopeTopp = netlistp->topScopep()->scopep();
FileLine* const flp = netlistp->fileline();
// We wrap the prep/cond/work in a function for readability
AstCFunc* const phaseFuncp = util::makeTopFunction(netlistp, "_eval_phase__" + tag, slow);
// Populate the trigger dump entry point function
if (trigp) {
UASSERT(eval.hasTriggers(), "Region with a trigger vector must have triggers");
netlistp->dumpTriggersFuncp(eval)->addStmtsp(trigKit.newDumpCall(trigp, tag, false));
}
AstCFunc* const funcp = netlistp->evalFuncp(eval);
// A flag is passed from the run-time eval loop if this is the first iteration of the
// current loop
if (eval.firstIteration()) {
AstVarScope* const firstIterArgp = util::newArgument(funcp, netlistp->findBitDType(),
"firstIteration", VDirection::INPUT);
// Set the region's 'first iteration' trigger straight from the argument
funcp->addStmtsp(trigKit.newExtraTriggerAssignment(firstIterArgp, firstIterTrigger));
// Only 'stl' also needs a module level flag, for design logic that reads
// it directly (see V3Timing). Those reads can be anywhere in the design,
// hence module level. Always created, even if nothing reads it.
// TODO: get rid of this special case
if (eval == VEval::STL) {
AstVarScope* const firstIterp = netlistp->stlFirstIterationp();
firstIterp->varp()->noReset(true);
firstIterp->varp()->isInternal(true);
funcp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, firstIterp, VAccess::WRITE},
new AstVarRef{flp, firstIterArgp, VAccess::READ}});
}
}
{
// Add the preparatory statements
phaseFuncp->addStmtsp(phasePrepp);
funcp->addStmtsp(phasePrepp);
// The execute flag
AstVarScope* const executeFlagp = scopeTopp->createTemp(varPrefix + "Execute", 1);
executeFlagp->varp()->noReset(true);
// If there is work in this phase, execute it if any triggers fired
// If there is work in this region, execute it if any triggers fired
if (phaseWorkp) {
AstNodeExpr* const lhsp = new AstVarRef{flp, executeFlagp, VAccess::WRITE};
// If using explicit condition, that directly determines whether to execute,
// otherwise check if any triggers are fired
AstNodeExpr* const rhsp = condp ? condp : trigKit.newAnySetCall(trigp);
phaseFuncp->addStmtsp(new AstAssign{flp, lhsp, rhsp});
funcp->addStmtsp(new AstAssign{flp, lhsp, rhsp});
// Add the work
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, executeFlagp, VAccess::READ}};
ifp->addThensp(phaseWorkp);
phaseFuncp->addStmtsp(ifp);
funcp->addStmtsp(ifp);
}
// Construct the extra statements
AstNodeStmt* const extraWorkp = phaseExtra(executeFlagp);
if (extraWorkp) phaseFuncp->addStmtsp(extraWorkp);
if (extraWorkp) funcp->addStmtsp(extraWorkp);
// The function returns ture iff it did run work
phaseFuncp->rtnType("bool");
// The function returns true iff it did run work
AstNodeExpr* const retp
= phaseWorkp || extraWorkp
? static_cast<AstNodeExpr*>(new AstVarRef{flp, executeFlagp, VAccess::READ})
: static_cast<AstNodeExpr*>(new AstConst{flp, AstConst::BitFalse{}});
phaseFuncp->addStmtsp(new AstCReturn{flp, retp});
funcp->addStmtsp(new AstCReturn{flp, retp});
}
// The result statements
AstNodeStmt* stmtps = nullptr;
// Prof-exec section push
if (v3Global.opt.profExec()) { //
stmtps = AstCStmt::profExecSectionPush(flp, "loop " + tag);
}
const auto addVar = [&](const std::string& name, int width, uint32_t initVal, bool init) {
const string tempName{"__V" + tag + name};
AstVarScope* const vscp = tempName == "__VstlFirstIteration"
? netlistp->stlFirstIterationp()
: scopeTopp->createTemp(tempName, width);
vscp->varp()->noReset(true);
vscp->varp()->isInternal(true);
if (init) stmtps = AstNode::addNext(stmtps, util::setVar(vscp, initVal));
return vscp;
};
// The iteration counter
AstVarScope* const counterp = addVar("IterCount", 32, 0, true);
// The first iteration flag - cleared in 'phasePrepp' if used
AstVarScope* const firstIterFlagp = addVar("FirstIteration", 1, 1, true);
// Phase function result
AstVarScope* const phaseResultp = addVar("PhaseResult", 1, 0, false);
// The loop
{
AstLoop* const loopp = new AstLoop{flp};
stmtps->addNext(loopp);
// Check the iteration limit (aborts if exceeded). Dump triggers if using triggers.
AstNodeStmt* dumpCallp = trigp ? trigKit.newDumpCall(trigp, tag, false) : nullptr;
loopp->addStmtsp(util::checkIterationLimit(netlistp, name, counterp, dumpCallp));
// Increment the iteration counter
loopp->addStmtsp(util::incrementVar(counterp));
// Execute the inner loop
loopp->addStmtsp(innerp);
// Call the phase function to execute the current work. If we did
// work, then need to loop again, so set the continuation flag.
// If used, the first iteration flag is cleared when consumed, no
// need to reset it
AstCCall* const callp = new AstCCall{flp, phaseFuncp};
callp->dtypeSetBit();
AstAssign* const resultAssignp
= new AstAssign{flp, new AstVarRef{flp, phaseResultp, VAccess::WRITE}, callp};
loopp->addStmtsp(resultAssignp);
// Clear FirstIteration flag
AstAssign* const firstClearp
= new AstAssign{flp, new AstVarRef{flp, firstIterFlagp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse()}};
loopp->addStmtsp(firstClearp);
// Continues until the continuation flag is clear
loopp->addStmtsp(
new AstLoopTest{flp, loopp, new AstVarRef{flp, phaseResultp, VAccess::READ}});
}
// Prof-exec section pop
if (v3Global.opt.profExec()) {
stmtps->addNext(AstCStmt::profExecSectionPop(flp, "loop " + tag));
}
return {firstIterFlagp, stmtps};
}
//============================================================================
@@ -363,7 +325,7 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) {
// Create simply ordered functions
AstCFunc* createStatic(AstNetlist* netlistp, const LogicClasses& logicClasses) {
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval_static", /* slow: */ true);
AstCFunc* const funcp = netlistp->evalFuncp(VEval::STATIC);
const LogicByScope& orig = logicClasses.m_static;
if (orig.size() <= 1) {
@@ -397,21 +359,19 @@ AstCFunc* createStatic(AstNetlist* netlistp, const LogicClasses& logicClasses) {
}
void createInitial(AstNetlist* netlistp, const LogicClasses& logicClasses) {
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval_initial", /* slow: */ true);
AstCFunc* const funcp = netlistp->evalFuncp(VEval::INITIAL);
orderSequentially(funcp, logicClasses.m_initial);
util::splitCheck(funcp);
}
AstCFunc* createPostponed(AstNetlist* netlistp, const LogicClasses& logicClasses) {
if (logicClasses.m_postponed.empty()) return nullptr;
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval_postponed", /* slow: */ false);
void createPostponed(AstNetlist* netlistp, const LogicClasses& logicClasses) {
AstCFunc* const funcp = netlistp->evalFuncp(VEval::POSTPONED);
orderSequentially(funcp, logicClasses.m_postponed);
util::splitCheck(funcp);
return funcp;
}
void createFinal(AstNetlist* netlistp, const LogicClasses& logicClasses) {
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval_final", /* slow: */ true);
AstCFunc* const funcp = netlistp->evalFuncp(VEval::FINAL);
orderSequentially(funcp, logicClasses.m_final);
util::splitCheck(funcp);
}
@@ -429,19 +389,13 @@ void addVirtIfaceTriggerAssignments(AstNetlist* netlistp, AstCFunc* initFuncp,
}
}
// Order the combinational logic to create the settle loop
// Order the combinational logic to create the 'stl' region
void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilder& senExprBulider,
LogicClasses& logicClasses) {
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval_settle", true);
// Clone, because ordering is destructive, but we still need them for "_eval"
// Clone, because ordering is destructive, but we still need them for the other regions
LogicByScope comb = logicClasses.m_comb.clone();
LogicByScope hybrid = logicClasses.m_hybrid.clone();
// Nothing to do if there is no logic.
// While this is rare in real designs, it reduces noise in small tests.
if (comb.empty() && hybrid.empty()) return;
// We have an extra trigger denoting this is the first iteration of the settle loop
TriggerKit::ExtraTriggers extraTriggers;
const uint32_t firstIterationTrigger = extraTriggers.allocate("first iteration");
@@ -468,14 +422,12 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
[=](const AstVarScope*, std::vector<AstSenTree*>& out) { out.push_back(inputChanged); });
util::splitCheck(stlFuncp);
// Create the eval loop
const EvalLoop stlLoop = createEvalLoop( //
netlistp, "stl", "Settle", /* slow: */ true, trigKit,
// Create the region evaluation function
createEvalRegion( //
netlistp, VEval::STL, firstIterationTrigger, trigKit,
// Use trigger
trigKit.vscp(), nullptr,
// Explicit condition
// Inner loop statements
nullptr,
// Prep statements: Compute the current 'stl' triggers
[&trigKit] {
AstNodeStmt* const stmtp = trigKit.newCompBaseCall();
@@ -484,23 +436,14 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
}(),
// Work statements: Invoke the 'stl' function
util::callVoidFunc(stlFuncp));
// Add the first iteration trigger to the trigger computation function
trigKit.addExtraTriggerAssignment(stlLoop.firstIterp, firstIterationTrigger, false);
// Add the eval loop to the top function
funcp->addStmtsp(stlLoop.stmtsp);
}
//============================================================================
// Order the replicated combinational logic to create the 'ico' region
AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
SenExprBuilder& senExprBuilder, LogicByScope& logic,
const VirtIfaceTriggers& virtIfaceTriggers) {
// Nothing to do if no combinational logic is sensitive to top level inputs
if (logic.empty()) return nullptr;
void createIcoRegion(AstNetlist* netlistp, AstCFunc* const initFuncp,
SenExprBuilder& senExprBuilder, LogicByScope& logic,
const VirtIfaceTriggers& virtIfaceTriggers) {
// SystemC only: Any top level inputs feeding a combinational logic must be marked,
// so we can make them sc_sensitive
if (v3Global.opt.systemC()) {
@@ -587,8 +530,9 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
V3Order::TrigToSenMap trigToSen;
invertAndMergeSenTreeMap(trigToSen, trigKit.mapVec());
// The 'first iteration' trigger for top level inputs - lazy constructed only if needed
AstSenTree* firstIterTriggerp = nullptr;
// The 'first iteration' trigger for top level inputs
AstSenTree* const firstIterTriggerp
= trigKit.newExtraTriggerSenTree(trigKit.vscp(), firstIterationTrigger);
// The DPI Export trigger
AstSenTree* const dpiExportTriggered
@@ -609,10 +553,6 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
if (it != inp2changedp.end()) {
out.push_back(it->second);
} else if (varp->isPrimaryInish() || varp->isSigUserRWPublic() || varp->sampled()) {
if (!firstIterTriggerp) {
firstIterTriggerp
= trigKit.newExtraTriggerSenTree(trigKit.vscp(), firstIterationTrigger);
}
out.push_back(firstIterTriggerp);
}
// Add other triggers
@@ -625,13 +565,11 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
});
util::splitCheck(icoFuncp);
// Create the eval loop
const EvalLoop icoLoop = createEvalLoop( //
netlistp, "ico", "Input combinational", /* slow: */ false, trigKit,
// Create the region evaluation function
createEvalRegion( //
netlistp, VEval::ICO, firstIterationTrigger, trigKit,
// Use trigger
trigKit.vscp(), nullptr,
// Inner loop statements
nullptr,
// Prep statements: Compute the current 'ico' triggers
[&trigKit] {
AstNodeStmt* const stmtp = trigKit.newCompBaseCall();
@@ -641,16 +579,9 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
// Work statements: Invoke the 'ico' function
util::callVoidFunc(icoFuncp));
// Add the first iteration trigger to the trigger computation function - if used
if (firstIterTriggerp) {
trigKit.addExtraTriggerAssignment(icoLoop.firstIterp, firstIterationTrigger, false);
}
// Release temporary input change detect SenTrees
for (AstSenTree* const senTreep : icoChangeSenTreeps) senTreep->deleteTree();
icoChangeSenTreeps.clear();
return icoLoop.stmtsp;
}
//============================================================================
@@ -666,16 +597,14 @@ struct EvalKit final {
};
//============================================================================
// Bolt together parts to create the top level _eval function
// Create the evaluation function of each region of a time step
void createEval(AstNetlist* netlistp, //
AstNode* icoLoop, //
const TriggerKit& trigKit, //
const EvalKit& actKit, //
const EvalKit& nbaKit, //
const EvalKit& obsKit, //
const EvalKit& reactKit, //
AstCFunc* postponedFuncp, //
TimingKit& timingKit //
) {
FileLine* const flp = netlistp->fileline();
@@ -687,13 +616,11 @@ void createEval(AstNetlist* netlistp, //
AstCCall* const timingReadyp = timingKit.createReady(netlistp);
AstCCall* const timingResumep = timingKit.createResume(netlistp);
// Create the active eval loop
EvalLoop topLoop = createEvalLoop( //
netlistp, "act", "Active", /* slow: */ false, trigKit,
// Create the 'act' region
createEvalRegion( //
netlistp, VEval::ACT, 0, trigKit,
// Use trigger
actKit.m_vscp, nullptr,
// Inner loop statements
nullptr,
// Prep statements
[&]() {
// Compute the current 'act' triggers - the NBA triggers are the latched value
@@ -730,56 +657,54 @@ void createEval(AstNetlist* netlistp, //
return workp;
}());
// Create if there are any delays, so we can check at runtime if a #0 is unexpected
if (delaySchedVscp) {
topLoop = createEvalLoop( //
netlistp, "inact", "Inactive", /* slow: */ false, trigKit,
// Use explicit condition
nullptr,
[&]() {
// Run if any zero delays are pending
AstNodeExpr* const callp
= new AstCMethodHard{flp, new AstVarRef{flp, delaySchedVscp, VAccess::READ},
VCMethod::SCHED_AWAITING_ZERO_DELAY};
callp->dtypeSetBit();
return callp;
}(),
// Inner loop statements
topLoop.stmtsp,
// Prep statements
nullptr,
// Work statements
[&]() -> AstNodeStmt* {
if (v3Global.usesZeroDelay()) {
// Resume processes watiting for #0 delay
AstCMethodHard* const callp = new AstCMethodHard{
flp, new AstVarRef{flp, delaySchedVscp, VAccess::READWRITE},
VCMethod::SCHED_RESUME_ZERO_DELAY};
callp->dtypeSetVoid();
return callp->makeStmt();
} else {
// Assumption was that the design doesn't use #0 delays.
// Die at run-time if it does.
AstCStmt* const stmtp = new AstCStmt{flp};
const FileLine* const locp = netlistp->topModulep()->fileline();
const std::string& file = VIdProtect::protect(locp->filename());
const std::string& line = std::to_string(locp->lineno());
stmtp->add(
"VL_FATAL_MT(\"" + V3OutFormatter::quoteNameControls(file) + "\", " + line
+ ", \"\", \"ZERODLY: Design Verilated with '--no-sched-zero-delay', "
+ "but #0 delay executed at runtime\");");
return stmtp;
}
}());
}
// Create the 'inact' region
createEvalRegion( //
netlistp, VEval::INACT, 0, trigKit,
// Use explicit condition
nullptr,
[&]() -> AstNodeExpr* {
if (!delaySchedVscp) return nullptr;
// Run if any zero delays are pending
AstNodeExpr* const callp
= new AstCMethodHard{flp, new AstVarRef{flp, delaySchedVscp, VAccess::READ},
VCMethod::SCHED_AWAITING_ZERO_DELAY};
callp->dtypeSetBit();
return callp;
}(),
// Prep statements
nullptr,
// Work statements
[&]() -> AstNodeStmt* {
if (!delaySchedVscp) {
// Nothing to do if there are no delays at all in the design
return nullptr;
} else if (v3Global.usesZeroDelay()) {
// Resume processes watiting for #0 delay
AstCMethodHard* const callp = new AstCMethodHard{
flp, new AstVarRef{flp, delaySchedVscp, VAccess::READWRITE},
VCMethod::SCHED_RESUME_ZERO_DELAY};
callp->dtypeSetVoid();
return callp->makeStmt();
} else {
// Assumption was that the design doesn't use #0 delays.
// Die at run-time if it does.
AstCStmt* const stmtp = new AstCStmt{flp};
const FileLine* const locp = netlistp->topModulep()->fileline();
const std::string& file = VIdProtect::protect(locp->filename());
const std::string& line = std::to_string(locp->lineno());
stmtp->add("VL_FATAL_MT(\"" + V3OutFormatter::quoteNameControls(file) + "\", "
+ line
+ ", \"\", \"ZERODLY: Design Verilated with '--no-sched-zero-delay', "
+ "but #0 delay executed at runtime\");");
return stmtp;
}
}());
// Create the NBA eval loop, which is the default top level loop.
topLoop = createEvalLoop( //
netlistp, "nba", "NBA", /* slow: */ false, trigKit,
// Create the 'nba' region
createEvalRegion( //
netlistp, VEval::NBA, 0, trigKit,
// Use trigger
nbaKit.m_vscp, nullptr,
// Inner loop statements
topLoop.stmtsp,
// Prep statements
nullptr,
// Work statements
@@ -819,68 +744,45 @@ void createEval(AstNetlist* netlistp, //
return ifp;
});
if (!obsKit.empty()) {
// Create the Observed eval loop, which becomes the top level loop.
topLoop = createEvalLoop( //
netlistp, "obs", "Observed", /* slow: */ false, trigKit,
// Use trigger
obsKit.m_vscp, nullptr,
// Inner loop statements
topLoop.stmtsp,
// Prep statements
nullptr,
// Work statements
[&]() {
AstNodeStmt* workp = nullptr;
// Latch the Observed trigger flags under the Reactive trigger flags
if (!reactKit.empty()) {
workp = trigKit.newOrIntoCall(reactKit.m_vscp, obsKit.m_vscp);
}
// Invoke the 'obs' function
workp = AstNode::addNext(workp, util::callVoidFunc(obsKit.m_funcp));
// Clear the 'obs' triggers
workp = AstNode::addNext(workp, trigKit.newClearCall(obsKit.m_vscp));
//
return workp;
}());
}
// Create the 'obs' region
createEvalRegion( //
netlistp, VEval::OBS, 0, trigKit,
// Use trigger
obsKit.m_vscp, nullptr,
// Prep statements
nullptr,
// Work statements
[&]() -> AstNodeStmt* {
if (obsKit.empty()) return nullptr;
AstNodeStmt* workp = nullptr;
// Latch the Observed trigger flags under the Reactive trigger flags
if (!reactKit.empty()) {
workp = trigKit.newOrIntoCall(reactKit.m_vscp, obsKit.m_vscp);
}
// Invoke the 'obs' function
workp = AstNode::addNext(workp, util::callVoidFunc(obsKit.m_funcp));
// Clear the 'obs' triggers
workp = AstNode::addNext(workp, trigKit.newClearCall(obsKit.m_vscp));
//
return workp;
}());
if (!reactKit.empty()) {
// Create the Reactive eval loop, which becomes the top level loop.
topLoop = createEvalLoop( //
netlistp, "react", "Reactive", /* slow: */ false, trigKit,
// Use trigger
reactKit.m_vscp, nullptr,
// Inner loop statements
topLoop.stmtsp,
// Prep statements
nullptr,
// Work statements
[&]() {
// Invoke the 'react' function
AstNodeStmt* workp = util::callVoidFunc(reactKit.m_funcp);
// Clear the 'react' triggers
workp = AstNode::addNext(workp, trigKit.newClearCall(reactKit.m_vscp));
return workp;
}());
}
// Now that we have build the loops, create the main 'eval' function
AstCFunc* const funcp = util::makeTopFunction(netlistp, "_eval", false);
netlistp->evalp(funcp);
if (v3Global.opt.profExec()) funcp->addStmtsp(AstCStmt::profExecSectionPush(flp, "eval"));
// Start with the ico loop, if any
if (icoLoop) funcp->addStmtsp(icoLoop);
// Execute the top level eval loop
funcp->addStmtsp(topLoop.stmtsp);
// Add the Postponed eval call
if (postponedFuncp) funcp->addStmtsp(util::callVoidFunc(postponedFuncp));
if (v3Global.opt.profExec()) funcp->addStmtsp(AstCStmt::profExecSectionPop(flp, "eval"));
// Create the 'react' region
createEvalRegion( //
netlistp, VEval::REACT, 0, trigKit,
// Use trigger
reactKit.m_vscp, nullptr,
// Prep statements
nullptr,
// Work statements
[&]() -> AstNodeStmt* {
if (reactKit.empty()) return nullptr;
// Invoke the 'react' function
AstNodeStmt* workp = util::callVoidFunc(reactKit.m_funcp);
// Clear the 'react' triggers
workp = AstNode::addNext(workp, trigKit.newClearCall(reactKit.m_vscp));
return workp;
}());
}
} // namespace
@@ -938,13 +840,28 @@ void schedule(AstNetlist* netlistp) {
V3Stats::addStat("Scheduling, " + name, size);
};
// Step 0. Prepare external domains for timing and virtual interfaces
// Step 1: Create every entry point called from the run-time eval loop
for (int i = 0; i < VEval::_ENUM_END; ++i) {
const VEval eval{i};
AstCFunc* const funcp = util::makeTopFunction(netlistp, eval.funcName(), eval.slow());
netlistp->evalFuncp(eval, funcp);
// Only the iterated functions report whether they did any work
if (eval.isIterated()) funcp->rtnType("bool");
// Only a region with a trigger vector has anything to dump
if (eval.hasTriggers()) {
AstCFunc* const dumpp
= util::makeTopFunction(netlistp, eval.dumpTriggersFuncName(), true);
netlistp->dumpTriggersFuncp(eval, dumpp);
}
}
// Step 2: Prepare external domains for timing and virtual interfaces
// Create extra triggers for virtual interfaces
const auto& virtIfaceTriggers = makeVirtIfaceTriggers(netlistp);
// Prepare timing-related logic and external domains
TimingKit timingKit = prepareTiming(netlistp);
// Step 1. Gather and classify all logic in the design
// Step 3: Gather and classify all logic in the design
LogicClasses logicClasses = gatherLogicClasses(netlistp);
if (v3Global.opt.stats()) {
@@ -954,7 +871,7 @@ void schedule(AstNetlist* netlistp) {
addSizeStat("size of class: final", logicClasses.m_final);
}
// Step 2. Schedule static, initial and final logic classes in source order
// Step 4: Schedule static, initial and final logic classes in source order
AstCFunc* const staticp = createStatic(netlistp, logicClasses);
if (v3Global.opt.stats()) V3Stats::statsStage("sched-static");
@@ -964,7 +881,7 @@ void schedule(AstNetlist* netlistp) {
createFinal(netlistp, logicClasses);
if (v3Global.opt.stats()) V3Stats::statsStage("sched-final");
// Step 3: Break combinational cycles by introducing hybrid logic
// Step 5: Break combinational cycles by introducing hybrid logic
// Note: breakCycles also removes corresponding logic from logicClasses.m_comb;
logicClasses.m_hybrid = breakCycles(netlistp, logicClasses.m_comb);
if (v3Global.opt.stats()) {
@@ -980,11 +897,11 @@ void schedule(AstNetlist* netlistp) {
AstScope* const scopeTopp = topScopep->scopep();
SenExprBuilder senExprBuilder{scopeTopp};
// Step 4: Create 'settle' region that restores the combinational invariant
// Step 6: Create 'settle' region that restores the combinational invariant
createSettle(netlistp, staticp, senExprBuilder, logicClasses);
if (v3Global.opt.stats()) V3Stats::statsStage("sched-settle");
// Step 5: Partition the clocked and combinational (including hybrid) logic into pre/act/nba.
// Step 7: Partition the clocked and combinational (including hybrid) logic into pre/act/nba.
// All clocks (signals referenced in an AstSenTree) generated via a blocking assignment
// (including combinationally generated signals) are computed within the act region.
LogicRegions logicRegions
@@ -1000,7 +917,7 @@ void schedule(AstNetlist* netlistp) {
V3Stats::statsStage("sched-partition");
}
// Step 6: Replicate combinational logic
// Step 8: Replicate combinational logic
LogicReplicas logicReplicas = replicateLogic(logicRegions);
if (v3Global.opt.stats()) {
addSizeStat("size of replicated logic: Input", logicReplicas.m_ico);
@@ -1011,12 +928,11 @@ void schedule(AstNetlist* netlistp) {
V3Stats::statsStage("sched-replicate");
}
// Step 7: Create input combinational logic loop
AstNode* const icoLoopp = createInputCombLoop(netlistp, staticp, senExprBuilder,
logicReplicas.m_ico, virtIfaceTriggers);
// Step 9: Create the input combinational logic
createIcoRegion(netlistp, staticp, senExprBuilder, logicReplicas.m_ico, virtIfaceTriggers);
if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-ico");
// Step 8: Create the triggers
// Step 10: Create the triggers
AstVarScope* const dpiExportTriggerVscp = netlistp->dpiExportTriggerp();
netlistp->dpiExportTriggerp(nullptr); // Finished with this here
@@ -1056,7 +972,7 @@ void schedule(AstNetlist* netlistp) {
// NBA for now. This can be revised if evidence is available that it would
// be beneficial
// Step 9: Create the 'act' region evaluation function
// Step 11: Create the 'act' region evaluation function
// Remap sensitivities of the input logic to the triggers
remapSensitivities(logicRegions.m_pre, trigKit.mapPre());
@@ -1134,10 +1050,9 @@ void schedule(AstNetlist* netlistp) {
return {trigVscp, funcp};
};
// Step 10: Create the 'nba' region evaluation function
// Step 12: Create the 'nba' region evaluation function
const EvalKit nbaKit = order("nba", {&logicRegions.m_nba, &logicReplicas.m_nba});
util::splitCheck(nbaKit.m_funcp);
netlistp->evalNbap(nbaKit.m_funcp); // Remember for V3LifePost
if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-nba");
// Orders a region's logic and creates the region eval function (only if there is any logic in
@@ -1151,21 +1066,20 @@ void schedule(AstNetlist* netlistp) {
return kit;
};
// Step 11: Create the 'obs' region evaluation function
// Step 13: Create the 'obs' region evaluation function
const EvalKit obsKit = orderIfNonEmpty("obs", {&logicRegions.m_obs, &logicReplicas.m_obs});
// Step 12: Create the 're' region evaluation function
// Step 14: Create the 'react' region evaluation function
const EvalKit reactKit
= orderIfNonEmpty("react", {&logicRegions.m_react, &logicReplicas.m_react});
// Step 13: Create the 'postponed' region evaluation function
auto* const postponedFuncp = createPostponed(netlistp, logicClasses);
// Step 15: Create the 'postponed' region evaluation function
createPostponed(netlistp, logicClasses);
// Step 14: Bolt it all together to create the '_eval' function
createEval(netlistp, icoLoopp, trigKit, actKit, nbaKit, obsKit, reactKit, postponedFuncp,
timingKit);
// Step 16: Populate the eval entry point function of each region of a time step
createEval(netlistp, trigKit, actKit, nbaKit, obsKit, reactKit, timingKit);
// Step 15: Add neccessary evaluation before awaits
// Step 17: Add neccessary evaluation before awaits
if (AstCCall* const readyp = timingKit.createReady(netlistp)) {
staticp->addStmtsp(readyp->makeStmt());
beforeTrigVisitor(netlistp, senExprBuilder, trigKit);
@@ -1202,12 +1116,15 @@ void schedule(AstNetlist* netlistp) {
staticp->addStmtsp(loopp);
}
// Step 16: Clean up
// Step 18: Clean up
netlistp->clearStlFirstIterationp();
// Haven't split static initializer yet
util::splitCheck(staticp);
// Record eval stats
netlistp->addEvalStats("sched");
// Dump
V3Global::dumpCheckGlobalTree("sched", 0, dumpTreeEitherLevel() >= 3);
}
+10 -5
View File
@@ -22,6 +22,7 @@
#include "V3Ast.h"
#include <array>
#include <functional>
#include <unordered_map>
#include <unordered_set>
@@ -354,8 +355,12 @@ public:
// Create an AstSenTree that is sensitive to the given Extra trigger
AstSenTree* newExtraTriggerSenTree(AstVarScope* vscp, uint32_t index) const;
// Set then extra trigger bit at 'index' to the value of 'vscp', then set 'vscp' to 0
void addExtraTriggerAssignment(AstVarScope* vscp, uint32_t index, bool clear = true) const;
// Statement setting the extra trigger bit at 'index' to the value of 'vscp'
AstNodeStmt* newExtraTriggerAssignment(AstVarScope* vscp, uint32_t index) const;
// Set the extra trigger bit at 'index' to the value of 'vscp', then set 'vscp' to 0.
// Prepended to the trigger computation function.
void addExtraTriggerAssignment(AstVarScope* vscp, uint32_t index) const;
// Set trigger bit at 'index' when vscp's value changes from previous evaluation.
// Creates a prev variable: trigger[bit] = (vscp != prev); prev = vscp
@@ -450,15 +455,15 @@ namespace util {
AstCFunc* makeTopFunction(AstNetlist* netlistp, const string& name, bool slow);
// Create a new sub function (not an entry point)
AstCFunc* makeSubFunction(AstNetlist* netlistp, const string& name, bool slow);
// Add an argument of the given type to the given function
AstVarScope* newArgument(AstCFunc* funcp, AstNodeDType* dtypep, const string& name,
VDirection direction);
// Create statement that sets the given 'vscp' to 'val'
AstNodeStmt* setVar(AstVarScope* vscp, uint32_t val);
// Create statement that increments the given 'vscp' by one
AstNodeStmt* incrementVar(AstVarScope* vscp);
// Create statement that calls the given 'void' returning function
AstNodeStmt* callVoidFunc(AstCFunc* funcp);
// Create statement that checks counterp' to see if the eval loop iteration limit is reached
AstNodeStmt* checkIterationLimit(AstNetlist* netlistp, const string& name, AstVarScope* counterp,
AstNodeStmt* dumpCallp);
// Split large function according to --output-split-cfuncs
void splitCheck(AstCFunc* ofuncp);
// Build an AstIf conditional on the given SenTree being triggered
+11 -28
View File
@@ -34,18 +34,7 @@ namespace V3Sched {
namespace {
AstVarScope* newArgument(AstCFunc* funcp, AstNodeDType* dtypep, const std::string& name,
VDirection direction) {
FileLine* const flp = funcp->fileline();
AstScope* const scopep = funcp->scopep();
AstVar* const varp = new AstVar{flp, VVarType::BLOCKTEMP, name, dtypep};
varp->funcLocal(true);
varp->direction(direction);
funcp->addArgsp(varp);
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
scopep->addVarsp(vscp);
return vscp;
}
using util::newArgument;
AstVarScope* newLocal(AstCFunc* funcp, AstNodeDType* dtypep, const std::string& name) {
FileLine* const flp = funcp->fileline();
@@ -404,22 +393,24 @@ AstSenTree* TriggerKit::newExtraTriggerSenTree(AstVarScope* vscp, uint32_t index
return newTriggerSenTree(vscp, {index + m_nSenseWords * WORD_SIZE});
}
void TriggerKit::addExtraTriggerAssignment(AstVarScope* vscp, uint32_t index, bool clear) const {
AstNodeStmt* TriggerKit::newExtraTriggerAssignment(AstVarScope* vscp, uint32_t index) const {
index += m_nSenseWords * WORD_SIZE;
const uint32_t wordIndex = index / WORD_SIZE;
const uint32_t bitIndex = index % WORD_SIZE;
FileLine* const flp = vscp->fileline();
// Set the trigger bit
AstVarRef* const refp = new AstVarRef{flp, m_vscp, VAccess::WRITE};
AstNodeExpr* const wordp = new AstArraySel{flp, refp, static_cast<int>(wordIndex)};
AstNodeExpr* const trigLhsp = new AstSel{flp, wordp, static_cast<int>(bitIndex), 1};
AstNodeExpr* const trigRhsp = new AstVarRef{flp, vscp, VAccess::READ};
AstNode* const setp = new AstAssign{flp, trigLhsp, trigRhsp};
if (clear) {
// Clear the input variable
setp->addNext(new AstAssign{flp, new AstVarRef{flp, vscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse{}}});
}
return new AstAssign{flp, trigLhsp, trigRhsp};
}
void TriggerKit::addExtraTriggerAssignment(AstVarScope* vscp, uint32_t index) const {
FileLine* const flp = vscp->fileline();
// Set the trigger bit, then clear the input variable
AstNode* const setp = newExtraTriggerAssignment(vscp, index);
setp->addNext(new AstAssign{flp, new AstVarRef{flp, vscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse{}}});
if (AstNode* const nodep = m_compVecp->stmtsp()) {
setp->addNext(setp, nodep->unlinkFrBackWithNext());
}
@@ -779,10 +770,6 @@ TriggerKit TriggerKit::create(AstNetlist* netlistp, //
AstScope* const scopep = netlistp->topScopep()->scopep();
{
AstCFunc* const fp = kit.m_compVecp;
// Profiling push
if (v3Global.opt.profExec()) {
fp->addStmtsp(AstCStmt::profExecSectionPush(flp, "trigBase " + name));
}
// Trigger computation
for (AstNodeStmt* const nodep : senResults.m_preUpdates) fp->addStmtsp(nodep);
fp->addStmtsp(trigStmtsp);
@@ -796,10 +783,6 @@ TriggerKit TriggerKit::create(AstNetlist* netlistp, //
ifp->addThensp(util::setVar(initVscp, 1));
ifp->addThensp(initialTrigsp);
}
// Profiling pop
if (v3Global.opt.profExec()) {
fp->addStmtsp(AstCStmt::profExecSectionPop(flp, "trigBase " + name));
}
util::splitCheck(fp);
};
// If there are 'pre' triggers, compute them
+14 -21
View File
@@ -46,6 +46,19 @@ AstCFunc* makeSubFunction(AstNetlist* netlistp, const string& name, bool slow) {
return funcp;
}
AstVarScope* newArgument(AstCFunc* funcp, AstNodeDType* dtypep, const string& name,
VDirection direction) {
FileLine* const flp = funcp->fileline();
AstScope* const scopep = funcp->scopep();
AstVar* const varp = new AstVar{flp, VVarType::BLOCKTEMP, name, dtypep};
varp->funcLocal(true);
varp->direction(direction);
funcp->addArgsp(varp);
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
scopep->addVarsp(vscp);
return vscp;
}
AstCFunc* makeTopFunction(AstNetlist* netlistp, const string& name, bool slow) {
AstCFunc* const funcp = makeSubFunction(netlistp, name, slow);
funcp->entryPoint(true);
@@ -77,27 +90,6 @@ AstNodeStmt* callVoidFunc(AstCFunc* funcp) {
return callp->makeStmt();
}
AstNodeStmt* checkIterationLimit(AstNetlist* netlistp, const string& name, AstVarScope* counterp,
AstNodeStmt* dumpCallp) {
FileLine* const flp = netlistp->fileline();
// If we exceeded the iteration limit, die
const uint32_t limit = v3Global.opt.convergeLimit();
AstVarRef* const counterRefp = new AstVarRef{flp, counterp, VAccess::READ};
AstConst* const constp = new AstConst{flp, AstConst::DTyped{}, counterp->dtypep()};
constp->num().setLong(limit);
AstNodeExpr* const condp = new AstGt{flp, counterRefp, constp};
AstIf* const ifp = new AstIf{flp, condp};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
if (dumpCallp) ifp->addThensp(dumpCallp);
AstCStmt* const stmtp = new AstCStmt{flp};
ifp->addThensp(stmtp);
stmtp->add("VL_FATAL_MT(\"\", 0, \"\", \"DIDNOTCONVERGE: " + name
+ " region did not converge after '--converge-limit' of " + std::to_string(limit)
+ " tries\");");
return ifp;
}
static AstCFunc* splitCheckCreateNewSubFunc(AstCFunc* ofuncp) {
static std::map<AstCFunc*, uint32_t> s_funcNums; // What split number to attach to a function
const uint32_t funcNum = s_funcNums[ofuncp]++;
@@ -256,4 +248,5 @@ AstIf* createIfFromSenTree(AstSenTree* senTreep) {
}
} // namespace util
} // namespace V3Sched
+1 -1
View File
@@ -1220,7 +1220,7 @@ class TraceVisitor final : public VNVisitor {
V3GraphVertex* const funcVtxp = getCFuncVertexp(nodep);
if (!m_finding) { // If public, we need a unique activity code to allow for sets
// directly in this func
if (nodep->funcPublic() || nodep->dpiExportImpl() || nodep == v3Global.rootp()->evalp()
if (nodep->funcPublic() || nodep->dpiExportImpl() || nodep->entryPoint()
|| nodep->isCoroutine()) {
// Cannot treat a coroutine as slow, it may be resumed later
const bool slow = nodep->slow() && !nodep->isCoroutine();
-4
View File
@@ -587,10 +587,6 @@ static void process() {
}
}
// These are no longer needed, remove references before CFunc inlining
v3Global.rootp()->evalp(nullptr);
v3Global.rootp()->evalNbap(nullptr);
if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()) {
if (v3Global.opt.fInlineCFuncs()) {
// Inline small CFuncs to reduce function call overhead
+21 -21
View File
@@ -1,21 +1,21 @@
AST patterns with depth 1
126 (CONST #A):a/a
125 (CONST #A):a/a
54 (VARREF):a/b
36 (CCAST (VARREF):a/b):a/b
34 (AND (CONST #A):a/a _:a/1):a/1
29 (VARREF):a/a
23 (CONST ZERO):a/a
21 (VARREF):(w64)u[1:0]
23 (VARREF):(w64)u[1:0]
21 (CONST ZERO):a/a
21 (VARREF):a/a
20 (CCAST _:a/1):a/1
18 (AND (CONST #A):a/a _:a/a):a/a
19 (AND (CONST #A):a/a _:a/a):a/a
18 (SHIFTR _:a/b (CONST #A):a/a):a/1
17 (VARREF):a/1
15 (SHIFTL _:a/1 (CONST #A):a/a):a/a
14 (NEGATE _:a/1):a/a
12 (AND (CONST #A):a/a _:a/b):a/b
12 (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b
12 (NOT _:a/b):a/b
12 (VARREF):(w64)u[0:0]
12 (VARREF):a/1
11 (OR _:a/a _:a/b):a/c
9 (OR _:a/a _:a/1):a/b
9 (VARREF):(G/str)
@@ -24,34 +24,36 @@ AST patterns with depth 1
8 (CRESET):a/a
8 (NOT _:a/a):a/a
8 (REDXOR _:a/b):a/1
7 (CONST ZERO):a/1
7 (SHIFTL _:a/b (CONST #A):a/a):a/a
6 (AND _:a/b _:a/b):a/b
6 (OR _:a/a _:a/a):a/a
6 (REDXOR _:a/a):b/1
5 (CCAST (VARREF):a/1):a/1
5 (CCAST _:a/a):b/1
5 (OR _:a/a _:a/a):a/a
4 (ADD _:a/a (VARREF):a/a):a/a
4 (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):a/a):b/b
4 (CCAST (CONST #A):a/a):a/a
4 (CCAST (VARREF):a/1):a/1
4 (CCAST _:a/1):b/1
4 (CONST #A):(G/str)
4 (CONST #A):a/1
4 (NEGATE _:a/1):a/b
4 (SHIFTL _:a/a (CONST #A):b/b):a/a
3 (AND (VARREF):a/a (CONST #A):b/b):a/a
3 (CONST ZERO):a/1
3 (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b
3 (CONST #A):a/1
3 (CRESET):(w64)u[0:0]
3 (CRESET):(w64)u[1:0]
3 (CRESET):1/1
3 (NOT _:a/1):a/1
3 (OR (CONST #A):a/a _:a/a):a/a
3 (VARREF):1/1
2 (ADD _:a/a (VARREF):a/a):a/a
2 (CCALL [(VARREF):(w64)u[0:0], (VARREF):(w64)u[0:0]]):a/a
2 (CCALL [(VARREF):(w64)u[0:0]]):a/1
2 (CCALL [(VARREF):(w64)u[1:0], (VARREF):(w64)u[1:0]]):a/a
2 (CCALL [(VARREF):(w64)u[1:0]]):a/1
2 (CCALL []):a/1
2 (CCAST (CONST #A):a/a):a/a
2 (CCAST _:a/1):b/b
2 (CRESET):(G/str)
2 (GT (CONST #A):a/a (VARREF):a/a):a/1
2 (LT (CONST #A):a/a (VARREF):a/a):a/1
2 (NEQ _:a/b _:a/b):a/1
2 (OR _:a/a _:a/a):a/b
2 (REDXOR (VARREF):a/b):a/1
@@ -59,14 +61,10 @@ AST patterns with depth 1
2 (REDXOR _:a/b):c/1
2 (SHIFTR _:a/a (CONST #A):b/b):a/a
1 (ARRAYSEL (VARREF):(w64)u[0:0] (VARREF):a/a):b/b
1 (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b
1 (ARRAYSEL (VARREF):(w64)u[1:0] (VARREF):a/a):b/b
1 (CCAST _:a/1):b/b
1 (CCAST _:a/b):a/b
1 (CCAST _:a/b):c/c
1 (CRESET):1/1
1 (NEQ _:a/b _:a/b):a/c
1 (VARREF):1/1
AST patterns with depth 2
18 (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1
@@ -85,7 +83,6 @@ AST patterns with depth 2
6 (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c
6 (SHIFTL (OR _:a/a _:a/b):a/c (CONST #A):a/a):a/a
5 (AND (CONST #A):a/a (CCAST _:b/b):a/1):a/1
4 (ADD (CCAST (CONST #A):a/a):a/a (VARREF):a/a):a/a
4 (AND (CONST #A):a/a (NEGATE _:a/1):a/b):a/b
4 (AND (CONST #A):a/a (REDXOR _:a/b):a/1):a/1
4 (AND (CONST #A):a/a (REDXOR _:b/b):a/1):a/1
@@ -97,12 +94,15 @@ AST patterns with depth 2
4 (SHIFTL (REDXOR _:a/b):a/1 (CONST #A):a/a):a/a
3 (AND (CONST #A):a/a (NOT _:a/1):a/1):a/1
3 (OR (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):b/b):a/a):a/a
2 (ADD (CCAST (CONST #A):a/a):a/a (VARREF):a/a):a/a
2 (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):b/b):a/a):a/a
2 (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):b/b):a/a):a/a
2 (AND (CONST #A):a/a (OR _:a/a _:a/a):a/b):a/b
2 (CCAST (CCAST (VARREF):a/1):a/1):b/b
2 (CCAST (SHIFTR _:a/a (CONST #A):b/b):a/a):b/1
2 (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1
2 (NOT (CCAST _:a/1):a/1):a/1
2 (OR (AND (CONST #A):a/a _:a/a):a/a (CCAST _:b/1):a/a):a/a
2 (OR (OR _:a/a _:a/a):a/a (OR _:a/a _:a/b):a/c):a/d
2 (OR (SHIFTL _:a/a (CONST #A):b/b):a/a (CCAST _:b/b):a/a):a/a
2 (OR (SHIFTL _:a/a (CONST #A):b/b):a/a (CCAST _:b/b):a/a):a/c
@@ -117,17 +117,16 @@ AST patterns with depth 2
2 (SHIFTL (REDXOR _:a/a):b/1 (CONST #A):b/b):b/b
2 (SHIFTL (REDXOR _:a/b):c/1 (CONST #A):c/c):c/c
2 (SHIFTR (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b (CONST #A):a/a):b/b
1 (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #B):b/b):a/a):a/a
1 (CCAST (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):a/a):b/b):a/1
1 (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b):a/1
1 (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b):a/1
1 (CCAST (CCALL [(VARREF):(w64)u[0:0]]):a/1):a/1
1 (CCAST (CCALL [(VARREF):(w64)u[1:0]]):a/1):a/1
1 (CCAST (CCAST (VARREF):a/1):a/1):b/b
1 (CCAST (CCAST _:a/b):a/b):c/c
1 (CCAST (OR _:a/a _:a/b):a/c):a/c
1 (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/c
1 (NOT (CCAST (VARREF):a/1):a/1):a/1
1 (OR (AND (CONST #A):a/a _:a/a):a/a (CCAST _:b/1):a/a):a/a
1 (OR (SHIFTL _:a/1 (CONST #A):a/a):a/a (NEQ _:a/b _:a/b):a/1):a/c
1 (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (OR _:a/a _:a/1):a/b):a/c
1 (SHIFTL (NEQ _:a/b _:a/b):a/1 (CONST #A):a/a):a/a
@@ -189,6 +188,7 @@ AST patterns with depth 3
1 (NOT (CCAST (CCALL [(VARREF):(w64)u[0:0]]):a/1):a/1):a/1
1 (NOT (CCAST (CCALL [(VARREF):(w64)u[1:0]]):a/1):a/1):a/1
1 (OR (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):b/b):a/a):a/a (CCAST (CCAST (VARREF):b/1):b/1):a/a):a/a
1 (OR (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #B):b/b):a/a):a/a (CCAST (CCAST (VARREF):b/1):b/1):a/a):a/a
1 (OR (SHIFTL (NEQ _:a/b _:a/b):a/1 (CONST #A):a/a):a/a (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1):a/c
1 (OR (SHIFTL (NEQ _:a/b _:a/b):a/c (CONST #A):a/a):a/a (OR (SHIFTL _:a/1 (CONST #B):a/a):a/a (NEQ _:a/b _:a/b):a/1):a/c):a/b
1 (SHIFTL (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1 (CONST #A):a/a):a/a
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"(E)","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"(E)","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"t","addr":"(F)","loc":"d,67:8,67:9","origName":"t","verilogName":"t","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -16,7 +16,7 @@ def check_evals():
got = 0
for filename in test.glob_some(test.obj_dir + "/*.cpp"):
wholefile = test.file_contents(filename)
if re.search(r'__eval_nba__[0-9]+\(.*\)\s*{', wholefile):
if re.search(r'__eval_body__nba__[0-9]+\(.*\)\s*{', wholefile):
got += 1
if got < 2:
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"test","addr":"(E)","loc":"d,21:8,21:12","origName":"test","verilogName":"test","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"t","addr":"(E)","loc":"d,7:8,7:9","origName":"t","verilogName":"t","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"$root","addr":"(F)","loc":"d,7:8,7:9","origName":"$root","verilogName":"$root","level":1,"modPublic":true,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"$root","addr":"(F)","loc":"d,11:8,11:11","origName":"$root","verilogName":"$root","level":1,"modPublic":true,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"$root","addr":"(F)","loc":"d,11:8,11:11","origName":"$root","verilogName":"$root","level":1,"modPublic":true,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"(E)","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"$root","addr":"(F)","loc":"d,7:8,7:21","origName":"$root","verilogName":"$root","level":1,"modPublic":true,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"m","addr":"(E)","loc":"d,7:8,7:9","origName":"m","verilogName":"m","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"top","addr":"(E)","loc":"d,7:8,7:11","origName":"top","verilogName":"top","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"m","addr":"(E)","loc":"d,12:8,12:9","origName":"m","verilogName":"m","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+1 -2
View File
@@ -51,7 +51,6 @@ test.run(cmd=[
])
# Check both lib and sim are present
test.file_grep(gantt_log, r'\|\s+[1-9][0-9]*\s+\|\s+[0-9.]+\s+\|\s+eval')
test.file_grep(gantt_log, r'\|\s+[1-9][0-9]*\s+\|\s+[0-9.]+\s+\|\s+secret:eval')
test.file_grep_count(gantt_log, r'\|\s+[1-9][0-9]*\s+\|\s+[0-9.]+\s+\|\s+eval', 2)
test.passes()
+1 -1
View File
@@ -20,6 +20,6 @@ test.execute()
if test.vlt:
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, calls inlined\s+(\d+)', 7)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions inlined\s+(\d+)', 7)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 7)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 8)
test.passes()
@@ -19,6 +19,6 @@ test.execute()
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, calls inlined\s+(\d+)', 0)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions inlined\s+(\d+)', 0)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 0)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 2)
test.passes()
+1 -1
View File
@@ -17,7 +17,7 @@ test.compile(verilator_flags2=["--stats", "--binary", "--trace", "--inline-cfunc
if test.vlt:
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, calls inlined\s+(\d+)', 8)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions inlined\s+(\d+)', 7)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 9)
test.file_grep(test.stats, r'Optimizations, Inline CFuncs, functions removed\s+(\d+)', 10)
test.execute()
+23 -9
View File
@@ -11,8 +11,6 @@
<map from="PSfqIT" to="__PVT__secret_cyc_r"/>
<map from="PStVCQ" to="__PVT__secret_r"/>
<map from="PSfqS0" to="__PVT__t__DOT__secret_inst"/>
<map from="PSF5NB" to="__VactIterCount"/>
<map from="PSkICD" to="__VactPhaseResult"/>
<map from="PSScAO" to="__VactTriggered"/>
<map from="PSx9Nt" to="__Vconfigure"/>
<map from="PSrjMj" to="__Vdly__secret_cyc"/>
@@ -20,29 +18,45 @@
<map from="PStVA8" to="__Vdpiexp_dpix_a_task_TOP__t__DOT__secret_inst"/>
<map from="PSxbIE" to="__Vdpiimwrap_dpii_a_func_TOP__t__DOT__secret_inst"/>
<map from="PS76My" to="__Vfunc_dpii_a_func__0__Vfuncout"/>
<map from="PSywKw" to="__Vinline_0__eval_nba___Vinline_0__nba_sequent__TOP__0___Vdly__t__DOT__secret_inst2__DOT__secret_cyc"/>
<map from="PSAZvl" to="__VicoDidInit"/>
<map from="PSk0iX" to="__VicoTriggered"/>
<map from="PSAUcz" to="__Vinline_0__eval_body__nba___Vinline_0__nba_sequent__TOP__0___Vdly__t__DOT__secret_inst2__DOT__secret_cyc"/>
<map from="PSo9XV" to="__VnbaExecute"/>
<map from="PSEtOH" to="__VnbaIterCount"/>
<map from="PSeNXP" to="__VnbaPhaseResult"/>
<map from="PSmzsT" to="__VnbaTriggered"/>
<map from="PSJZmm" to="__Vscopep_t__secret_inst"/>
<map from="PSnH92" to="__VstlTriggered"/>
<map from="PS25fg" to="__Vtask_dpix_a_task__1__i"/>
<map from="PSJN3f" to="__Vtrigprevexpr___TOP__clk__0"/>
<map from="PSGb9V" to="__Vtrigprevexpr___TOP__clk__1"/>
<map from="PSyTg5" to="_ctor_var_reset"/>
<map from="PSvIGv" to="_dump_triggers__act"/>
<map from="PS8lsQ" to="_eval"/>
<map from="PSotBv" to="_dump_triggers__ico"/>
<map from="PSX011" to="_dump_triggers__stl"/>
<map from="PSL96q" to="_eval_act"/>
<map from="PSKZ7c" to="_eval_debug_assertions"/>
<map from="PSNbkL" to="_eval_dump_triggers__act"/>
<map from="PSjLH2" to="_eval_dump_triggers__ico"/>
<map from="PSJNIi" to="_eval_dump_triggers__nba"/>
<map from="PSKbzS" to="_eval_dump_triggers__obs"/>
<map from="PSdpbg" to="_eval_dump_triggers__react"/>
<map from="PSFUOo" to="_eval_dump_triggers__stl"/>
<map from="PSEZzj" to="_eval_final"/>
<map from="PSlnyj" to="_eval_ico"/>
<map from="PS6Zut" to="_eval_inact"/>
<map from="PSABAY" to="_eval_initial"/>
<map from="PS0BBP" to="_eval_phase__act"/>
<map from="PSfNDT" to="_eval_phase__nba"/>
<map from="PSBUJ6" to="_eval_settle"/>
<map from="PSjoVa" to="_eval_nba"/>
<map from="PS3ty8" to="_eval_obs"/>
<map from="PSIOZr" to="_eval_postponed"/>
<map from="PSU5m9" to="_eval_react"/>
<map from="PSNS3N" to="_eval_sample"/>
<map from="PS0mmd" to="_eval_static"/>
<map from="PSOo5Y" to="_eval_stl"/>
<map from="PSoFVg" to="_nba_sequent__TOP__t__DOT__secret_inst__0"/>
<map from="PSMRXn" to="_trigger_anySet__act"/>
<map from="PSBKaZ" to="_trigger_clear__act"/>
<map from="PSB9K0" to="_trigger_orInto__act_vec_vec"/>
<map from="PScyq8" to="clk"/>
<map from="PSEUqF" to="firstIteration"/>
<map from="PSawda" to="in"/>
<map from="PSMlYB" to="n"/>
<map from="PSmk5h" to="out"/>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+37 -26
View File
@@ -1,6 +1,7 @@
-V{t#,#}- Verilated::debug is on. Message prefix indicates {<thread>,<sequence_number>}.
-V{t#,#}+ Vt_timing_eval_act___024root___ctor_var_reset
-V{t#,#}+++++TOP Evaluate Vt_timing_eval_act::eval_step
-V{t#,#}+ Eval
-V{t#,#}+ Vt_timing_eval_act___024root___eval_debug_assertions
-V{t#,#}+ Initial
-V{t#,#}+ Vt_timing_eval_act___024root___eval_static
@@ -17,24 +18,24 @@
-V{t#,#}+ Vt_timing_eval_act___024root____VbeforeTrig_h########__0
-V{t#,#} Suspending process waiting for @([event] t.a) at t/t_timing_eval_act.v:33
-V{t#,#}+ Vt_timing_eval_act___024root___eval_initial__TOP__Vtiming__3
-V{t#,#}+ Vt_timing_eval_act___024root___eval_settle
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_stl
-V{t#,#}+ Vt_timing_eval_act___024root___dump_triggers__stl
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__stl
-V{t#,#} 'stl' region trigger index 0 is active: Internal 'stl' trigger - first iteration
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_body__stl
-V{t#,#}+ Vt_timing_eval_act___024root___act_comb__TOP__0
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__stl
-V{t#,#}+ Vt_timing_eval_act___024root___eval_stl
-V{t#,#}+ Vt_timing_eval_act___024root___dump_triggers__stl
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__stl
-V{t#,#} No 'stl' region triggers active
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__stl
-V{t#,#}+ Eval
-V{t#,#}+ Vt_timing_eval_act___024root___eval
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_sample
-V{t#,#}+ Vt_timing_eval_act___024root___eval_ico
-V{t#,#}+ Vt_timing_eval_act___024root___dump_triggers__ico
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__ico
-V{t#,#} 'ico' region trigger index 0 is active: Internal 'ico' trigger - first iteration
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
@@ -43,15 +44,22 @@
-V{t#,#} No 'act' region triggers active
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__nba
-V{t#,#}+ Vt_timing_eval_act___024root___eval_inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_nba
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_obs
-V{t#,#}+ Vt_timing_eval_act___024root___eval_react
-V{t#,#}+ Vt_timing_eval_act___024root___eval_postponed
-V{t#,#}End-of-eval cleanup
-V{t#,#}+++++TOP Evaluate Vt_timing_eval_act::eval_step
-V{t#,#}+ Vt_timing_eval_act___024root___eval_debug_assertions
-V{t#,#}+ Eval
-V{t#,#}+ Vt_timing_eval_act___024root___eval
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_debug_assertions
-V{t#,#}+ Vt_timing_eval_act___024root___eval_sample
-V{t#,#}+ Vt_timing_eval_act___024root___eval_ico
-V{t#,#}+ Vt_timing_eval_act___024root___dump_triggers__ico
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__ico
-V{t#,#} 'ico' region trigger index 0 is active: Internal 'ico' trigger - first iteration
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
@@ -76,9 +84,9 @@
-V{t#,#} Awaiting time 1: Process waiting at t/t_timing_eval_act.v:39
-V{t#,#} Resuming delayed processes
-V{t#,#} Resuming: Process waiting at t/t_timing_eval_act.v:39
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_body__act
-V{t#,#}+ Vt_timing_eval_act___024root___act_comb__TOP__0
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#} Committing processes waiting for @([event] t.a):
@@ -126,9 +134,9 @@
-V{t#,#} Not triggered processes waiting for @([event] t.e):
-V{t#,#} - Process waiting at t/t_timing_eval_act.v:28
-V{t#,#} Resuming processes waiting for @([event] t.e)
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_body__act
-V{t#,#}+ Vt_timing_eval_act___024root___act_comb__TOP__0
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
@@ -152,9 +160,9 @@
-V{t#,#} - Process waiting at t/t_timing_eval_act.v:28
-V{t#,#} Resuming processes waiting for @([event] t.e)
-V{t#,#} Resuming: Process waiting at t/t_timing_eval_act.v:34
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_body__act
-V{t#,#}+ Vt_timing_eval_act___024root___act_comb__TOP__0
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
@@ -163,13 +171,13 @@
-V{t#,#} No 'act' region triggers active
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__nba
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_nba
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_body__nba
-V{t#,#}+ Vt_timing_eval_act___024root___act_comb__TOP__0
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_clear__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_timing_eval_act___024root___timing_ready
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
@@ -178,8 +186,11 @@
-V{t#,#} No 'act' region triggers active
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_phase__nba
-V{t#,#}+ Vt_timing_eval_act___024root___eval_inact
-V{t#,#}+ Vt_timing_eval_act___024root___eval_nba
-V{t#,#}+ Vt_timing_eval_act___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_eval_act___024root___eval_obs
-V{t#,#}+ Vt_timing_eval_act___024root___eval_react
-V{t#,#}+ Vt_timing_eval_act___024root___eval_postponed
-V{t#,#}End-of-eval cleanup
-V{t#,#}+ Vt_timing_eval_act___024root___eval_final
+1 -1
View File
@@ -1,4 +1,4 @@
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","evalp":"UNLINKED","evalNbap":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
{"type":"NETLIST","name":"$root","addr":"(B)","loc":"a,0:0,0:0","timeunit":"1ps","timeprecision":"1ps","typeTablep":"(C)","constPoolp":"(D)","dollarUnitPkgp":"UNLINKED","stdPackagep":"UNLINKED","stdPackageProcessp":"UNLINKED","dpiExportTriggerp":"UNLINKED","delaySchedulerp":"UNLINKED","nbaEventp":"UNLINKED","nbaEventTriggerp":"UNLINKED","topScopep":"UNLINKED","stlFirstIterationp":"UNLINKED",
"modulesp": [
{"type":"MODULE","name":"mh2","addr":"(E)","loc":"d,18:8,18:11","origName":"mh2","verilogName":"mh2","level":1,"timeunit":"1ps","inlinesp": [],
"stmtsp": [
+36 -12
View File
@@ -6,47 +6,71 @@ internalsDump:
scopesDump:
-V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step
-V{t#,#}+ Eval
-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions
-V{t#,#}+ Initial
-V{t#,#}+ Vt_verilated_debug___024root___eval_static
-V{t#,#}+ Vt_verilated_debug___024root___eval_initial
-V{t#,#}+ Vt_verilated_debug___024root___eval_initial__TOP
Data: w96: 000000aa 000000bb 000000cc
-V{t#,#}+ Vt_verilated_debug___024root___eval_settle
-V{t#,#}+ Eval
-V{t#,#}+ Vt_verilated_debug___024root___eval
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_stl
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__stl
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__stl
-V{t#,#} 'stl' region trigger index 0 is active: Internal 'stl' trigger - first iteration
-V{t#,#}+ Vt_verilated_debug___024root___eval_sample
-V{t#,#}+ Vt_verilated_debug___024root___eval_ico
-V{t#,#}+ Vt_verilated_debug___024root___eval_triggers_vec__ico
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__ico
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__ico
-V{t#,#} 'ico' region trigger index 0 is active: @( clk)
-V{t#,#} 'ico' region trigger index 64 is active: Internal 'ico' trigger - first iteration
-V{t#,#}+ Vt_verilated_debug___024root___eval_act
-V{t#,#}+ Vt_verilated_debug___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__act
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#} No 'act' region triggers active
-V{t#,#}+ Vt_verilated_debug___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__nba
-V{t#,#}+ Vt_verilated_debug___024root___eval_inact
-V{t#,#}+ Vt_verilated_debug___024root___eval_nba
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_obs
-V{t#,#}+ Vt_verilated_debug___024root___eval_react
-V{t#,#}+ Vt_verilated_debug___024root___eval_postponed
-V{t#,#}End-of-eval cleanup
-V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step
-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions
-V{t#,#}+ Eval
-V{t#,#}+ Vt_verilated_debug___024root___eval
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions
-V{t#,#}+ Vt_verilated_debug___024root___eval_sample
-V{t#,#}+ Vt_verilated_debug___024root___eval_ico
-V{t#,#}+ Vt_verilated_debug___024root___eval_triggers_vec__ico
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__ico
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__ico
-V{t#,#} 'ico' region trigger index 0 is active: @( clk)
-V{t#,#} 'ico' region trigger index 64 is active: Internal 'ico' trigger - first iteration
-V{t#,#}+ Vt_verilated_debug___024root___eval_act
-V{t#,#}+ Vt_verilated_debug___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__act
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#} 'act' region trigger index 0 is active: @(posedge clk)
-V{t#,#}+ Vt_verilated_debug___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__nba
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_inact
-V{t#,#}+ Vt_verilated_debug___024root___eval_nba
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_body__nba
-V{t#,#}+ Vt_verilated_debug___024root___nba_sequent__TOP__0
*-* All Finished *-*
-V{t#,#}+ Vt_verilated_debug___024root___trigger_clear__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_act
-V{t#,#}+ Vt_verilated_debug___024root___eval_triggers_vec__act
-V{t#,#}+ Vt_verilated_debug___024root___dump_triggers__act
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#} No 'act' region triggers active
-V{t#,#}+ Vt_verilated_debug___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_verilated_debug___024root___eval_phase__nba
-V{t#,#}+ Vt_verilated_debug___024root___eval_inact
-V{t#,#}+ Vt_verilated_debug___024root___eval_nba
-V{t#,#}+ Vt_verilated_debug___024root___trigger_anySet__act
-V{t#,#}+ Vt_verilated_debug___024root___eval_obs
-V{t#,#}+ Vt_verilated_debug___024root___eval_react
-V{t#,#}+ Vt_verilated_debug___024root___eval_postponed
-V{t#,#}End-of-eval cleanup
-V{t#,#}+ Vt_verilated_debug___024root___eval_final