mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
IEEE compliant scheduler (#3384)
This is a major re-design of the way code is scheduled in Verilator, with the goal of properly supporting the Active and NBA regions of the SystemVerilog scheduling model, as defined in IEEE 1800-2017 chapter 4. With this change, all internally generated clocks should simulate correctly, and there should be no more need for the `clock_enable` and `clocker` attributes for correctness in the absence of Verilator generated library models (`--lib-create`). Details of the new scheduling model and algorithm are provided in docs/internals.rst. Implements #3278
This commit is contained in:
+28
-8
@@ -131,8 +131,8 @@ struct LifePostLocation {
|
||||
class LifePostDlyVisitor final : public VNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared on entire tree
|
||||
// AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var
|
||||
// AstVarScope::user1() -> bool: referenced outside _eval__nba
|
||||
// AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var
|
||||
const VNUser4InUse m_inuser4;
|
||||
|
||||
// STATE
|
||||
@@ -155,6 +155,9 @@ private:
|
||||
const V3Graph* m_mtasksGraphp = nullptr; // Mtask tracking graph
|
||||
std::unique_ptr<GraphPathChecker> m_checker;
|
||||
|
||||
const AstCFunc* const m_evalNbap; // The _eval__nba function
|
||||
bool m_inEvalNba = false; // Traversing under _eval__nba
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
@@ -185,8 +188,11 @@ private:
|
||||
return true;
|
||||
}
|
||||
void squashAssignposts() {
|
||||
for (auto& itr : m_assignposts) {
|
||||
const LifePostLocation* const app = &itr.second;
|
||||
for (auto& pair : m_assignposts) {
|
||||
// If referenced external to _eval__nba, don't optimize
|
||||
if (pair.first->user1()) continue;
|
||||
|
||||
const LifePostLocation* const app = &pair.second;
|
||||
const AstVarRef* const lhsp = VN_AS(app->nodep->lhsp(), VarRef); // original var
|
||||
const AstVarRef* const rhsp = VN_AS(app->nodep->rhsp(), VarRef); // dly var
|
||||
AstVarScope* const dlyVarp = rhsp->varScopep();
|
||||
@@ -274,6 +280,12 @@ private:
|
||||
LifePostElimVisitor{nodep};
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
// Mark variables referenced outside _eval__nba
|
||||
if (!m_inEvalNba) {
|
||||
nodep->varScopep()->user1(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consumption/generation of a variable,
|
||||
const AstVarScope* const vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
@@ -288,6 +300,7 @@ private:
|
||||
// The pre-assignment into the dly var should not count as its
|
||||
// first write; we only want to consider reads and writes that
|
||||
// would still happen if the dly var were eliminated.
|
||||
if (!m_inEvalNba) iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignPost* nodep) override {
|
||||
// Don't record ASSIGNPOST in the read/write maps, record them in a
|
||||
@@ -315,9 +328,11 @@ private:
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) override {
|
||||
// Treat the ExecGraph like a call to each mtask body
|
||||
UASSERT_OBJ(!m_mtasksGraphp, nodep, "Cannot handle more than one AstExecGraph");
|
||||
m_mtasksGraphp = nodep->depGraphp();
|
||||
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp(); mtaskVxp;
|
||||
if (m_inEvalNba) {
|
||||
UASSERT_OBJ(!m_mtasksGraphp, nodep, "Cannot handle more than one AstExecGraph");
|
||||
m_mtasksGraphp = nodep->depGraphp();
|
||||
}
|
||||
for (V3GraphVertex* mtaskVxp = nodep->depGraphp()->verticesBeginp(); mtaskVxp;
|
||||
mtaskVxp = mtaskVxp->verticesNextp()) {
|
||||
const ExecMTask* const mtaskp = dynamic_cast<ExecMTask*>(mtaskVxp);
|
||||
m_execMTaskp = mtaskp;
|
||||
@@ -328,6 +343,8 @@ private:
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
if (!m_tracingCall && !nodep->entryPoint()) return;
|
||||
VL_RESTORER(m_inEvalNba);
|
||||
if (nodep == m_evalNbap) m_inEvalNba = true;
|
||||
m_tracingCall = false;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
@@ -337,7 +354,10 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit LifePostDlyVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
explicit LifePostDlyVisitor(AstNetlist* netlistp)
|
||||
: m_evalNbap{netlistp->evalNbap()} {
|
||||
iterate(netlistp);
|
||||
}
|
||||
virtual ~LifePostDlyVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Lifetime postassign deletions", m_statAssnDel);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user