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:
Geza Lore
2022-05-15 16:03:32 +01:00
committed by GitHub
parent 39b7c47e7b
commit 599d23697d
157 changed files with 6386 additions and 4395 deletions
-77
View File
@@ -731,80 +731,3 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
}
return "";
}
void EmitCFunc::doubleOrDetect(AstChangeDet* changep, bool& gotOne) {
// cppcheck-suppress variableScope
static int s_addDoubleOr = 10; // Determined experimentally as best
if (!changep->rhsp()) {
if (!gotOne) {
gotOne = true;
} else {
puts(" | ");
}
iterateAndNextNull(changep->lhsp());
} else {
AstNode* const lhsp = changep->lhsp();
AstNode* const rhsp = changep->rhsp();
UASSERT_OBJ(VN_IS(lhsp, VarRef) || VN_IS(lhsp, ArraySel), changep, "Not ref?");
UASSERT_OBJ(VN_IS(rhsp, VarRef) || VN_IS(rhsp, ArraySel), changep, "Not ref?");
for (int word = 0; word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1);
++word) {
if (!gotOne) {
gotOne = true;
s_addDoubleOr = 10;
puts("(");
} else if (--s_addDoubleOr == 0) {
puts("|| (");
s_addDoubleOr = 10;
} else {
puts(" | (");
}
iterateAndNextNull(changep->lhsp());
if (changep->lhsp()->isWide()) puts("[" + cvtToStr(word) + "]");
if (changep->lhsp()->isDouble()) {
puts(" != ");
} else {
puts(" ^ ");
}
iterateAndNextNull(changep->rhsp());
if (changep->lhsp()->isWide()) puts("[" + cvtToStr(word) + "]");
puts(")");
}
}
}
void EmitCFunc::emitChangeDet() {
putsDecoration("// Change detection\n");
puts("QData __req = false; // Logically a bool\n"); // But not because it results in
// faster code
bool gotOne = false;
for (AstChangeDet* const changep : m_blkChangeDetVec) {
if (changep->lhsp()) {
if (!gotOne) { // Not a clocked block
puts("__req |= (");
} else {
puts("\n");
}
doubleOrDetect(changep, gotOne);
}
}
if (gotOne) puts(");\n");
if (gotOne && !v3Global.opt.protectIds()) {
// puts("VL_DEBUG_IF( if (__req) cout<<\"- CLOCKREQ );");
for (AstChangeDet* nodep : m_blkChangeDetVec) {
if (nodep->lhsp()) {
puts("VL_DEBUG_IF( if(__req && (");
bool gotOneIgnore = false;
doubleOrDetect(nodep, gotOneIgnore);
string varname;
if (VN_IS(nodep->lhsp(), VarRef)) {
varname = ": " + VN_AS(nodep->lhsp(), VarRef)->varp()->prettyName();
}
puts(")) VL_DBG_MSGF(\" CHANGE: ");
puts(protect(nodep->fileline()->filename()));
puts(":" + cvtToStr(nodep->fileline()->lineno()));
puts(varname + "\\n\"); );\n");
}
}
}
}