mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 12:17:35 +00:00
Make incorrect soft ordering constraint into a hard constraint. (#5520)
An ordering constraint between NBA commit blocks ('Post' logic) and the written variable were previously added as soft constraints (cutable edges). However these are required for correctness, so if it ever is cut we will have incorrect simulation results. Change these into hard constraints instead. This necessitates adding a flag on AstVar to ignore special variables constructed during V3Delayed that might otherwise appear as degenerate logic loops. E.g.: if (VdlySet) { VdlySet = 0; // <- This write to VdlySet can and must be ignored LHS = VdlyVal; } No functional change, but you might get an error if this constraint was ever violated. (Theoretically it should never be, as these variables were inserted in a way that does not require violating these constraints ...)
This commit is contained in:
parent
5acced1e33
commit
041f6603c3
@ -1847,6 +1847,7 @@ class AstVar final : public AstNode {
|
|||||||
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
|
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
|
||||||
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
|
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
|
||||||
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
|
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
|
||||||
|
bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
m_ansi = false;
|
m_ansi = false;
|
||||||
@ -1891,6 +1892,7 @@ class AstVar final : public AstNode {
|
|||||||
m_isForcedByCode = false;
|
m_isForcedByCode = false;
|
||||||
m_isWrittenByDpi = false;
|
m_isWrittenByDpi = false;
|
||||||
m_isWrittenBySuspendable = false;
|
m_isWrittenBySuspendable = false;
|
||||||
|
m_ignorePostWrite = false;
|
||||||
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
|
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2046,6 +2048,8 @@ public:
|
|||||||
void setWrittenByDpi() { m_isWrittenByDpi = true; }
|
void setWrittenByDpi() { m_isWrittenByDpi = true; }
|
||||||
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }
|
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }
|
||||||
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
|
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
|
||||||
|
bool ignorePostWrite() const { return m_ignorePostWrite; }
|
||||||
|
void setIgnorePostWrite() { m_ignorePostWrite = true; }
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void name(const string& name) override { m_name = name; }
|
void name(const string& name) override { m_name = name; }
|
||||||
|
@ -510,6 +510,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
// Create new flag
|
// Create new flag
|
||||||
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
|
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
|
||||||
|
flagVscp->varp()->setIgnorePostWrite();
|
||||||
// Set the flag at the original NBA
|
// Set the flag at the original NBA
|
||||||
nodep->addHereThisAsNext( //
|
nodep->addHereThisAsNext( //
|
||||||
new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE},
|
new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE},
|
||||||
@ -543,6 +544,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName();
|
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName();
|
||||||
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);
|
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);
|
||||||
queueVscp->varp()->noReset(true);
|
queueVscp->varp()->noReset(true);
|
||||||
|
queueVscp->varp()->setIgnorePostWrite();
|
||||||
vscpInfo.valueQueueKit().vscp = queueVscp;
|
vscpInfo.valueQueueKit().vscp = queueVscp;
|
||||||
// Create the AstActive for the Post logic
|
// Create the AstActive for the Post logic
|
||||||
AstActive* const activep
|
AstActive* const activep
|
||||||
@ -556,7 +558,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
AstCMethodHard* const callp
|
AstCMethodHard* const callp
|
||||||
= new AstCMethodHard{flp, new AstVarRef{flp, queueVscp, VAccess::READWRITE}, "commit"};
|
= new AstCMethodHard{flp, new AstVarRef{flp, queueVscp, VAccess::READWRITE}, "commit"};
|
||||||
callp->dtypeSetVoid();
|
callp->dtypeSetVoid();
|
||||||
callp->addPinsp(new AstVarRef{flp, vscp, VAccess::READWRITE});
|
callp->addPinsp(new AstVarRef{flp, vscp, VAccess::WRITE});
|
||||||
postp->addStmtsp(callp->makeStmt());
|
postp->addStmtsp(callp->makeStmt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,24 +215,20 @@ class OrderGraphBuilder final : public VNVisitor {
|
|||||||
// Update VarUsage
|
// Update VarUsage
|
||||||
varscp->user2(varscp->user2() | VU_GEN);
|
varscp->user2(varscp->user2() | VU_GEN);
|
||||||
// Add edges for produced variables
|
// Add edges for produced variables
|
||||||
if (!m_inClocked || m_inPost) {
|
if (m_inPost) {
|
||||||
// Combinational logic
|
if (!varscp->varp()->ignorePostWrite()) {
|
||||||
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
|
// Add edge from producing LogicVertex -> produced VarStdVertex
|
||||||
// Add edge from producing LogicVertex -> produced VarStdVertex
|
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
|
||||||
if (m_inPost) {
|
|
||||||
m_graphp->addSoftEdge(m_logicVxp, varVxp, WEIGHT_COMBO);
|
|
||||||
} else {
|
|
||||||
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
|
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
|
||||||
}
|
}
|
||||||
|
OrderVarVertex* const postVxp = getVarVertex(varscp, VarVertexType::POST);
|
||||||
|
// Add edge from produced VarPostVertex -> to producing LogicVertex
|
||||||
|
m_graphp->addHardEdge(postVxp, m_logicVxp, WEIGHT_POST);
|
||||||
|
} else if (!m_inClocked) { // Combinational logic
|
||||||
|
// Add edge from producing LogicVertex -> produced VarStdVertex
|
||||||
|
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
|
||||||
|
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
|
||||||
// Add edge from produced VarPostVertex -> to producing LogicVertex
|
// Add edge from produced VarPostVertex -> to producing LogicVertex
|
||||||
|
|
||||||
// For m_inPost:
|
|
||||||
// Add edge consumed_var_POST->logic_vertex
|
|
||||||
// This prevents a consumer of the "early" value to be scheduled
|
|
||||||
// after we've changed to the next-cycle value
|
|
||||||
// ALWAYS do it:
|
|
||||||
// There maybe a wire a=b; between the two blocks
|
|
||||||
OrderVarVertex* const postVxp = getVarVertex(varscp, VarVertexType::POST);
|
OrderVarVertex* const postVxp = getVarVertex(varscp, VarVertexType::POST);
|
||||||
m_graphp->addHardEdge(postVxp, m_logicVxp, WEIGHT_POST);
|
m_graphp->addHardEdge(postVxp, m_logicVxp, WEIGHT_POST);
|
||||||
} else if (m_inPre) { // AstAssignPre
|
} else if (m_inPre) { // AstAssignPre
|
||||||
|
Loading…
Reference in New Issue
Block a user