fixed nba

This commit is contained in:
Ethan Sifferman 2026-02-02 12:35:50 -08:00
parent 268f5c3367
commit ffceba108b
3 changed files with 118 additions and 26 deletions

View File

@ -177,6 +177,8 @@ class DelayedVisitor final : public VNVisitor {
} m_flagSharedKit;
struct { // Stuff needed for Scheme::FlagUnique
AstAlwaysPost* postp; // The post block for commiting results
AstVarScope* commitFlagp; // The commit flag variable
AstVarScope* commitValp; // The commit value variable
} m_flagUniqueKit;
struct { // Stuff needed for Scheme::ValueQueueWhole/Scheme::ValueQueuePartial
AstVarScope* vscp; // The commit queue variable
@ -791,42 +793,70 @@ class DelayedVisitor final : public VNVisitor {
AstActive* const activep = new AstActive{flp, "nba-flag-unique", vscpInfo.senTreep()};
activep->senTreeStorep(vscpInfo.senTreep());
scopep->addBlocksp(activep);
// Add 'Post' scheduled process to be populated later
// Add 'Post' scheduled process
AstAlwaysPost* const postp = new AstAlwaysPost{flp};
activep->addStmtsp(postp);
vscpInfo.flagUniqueKit().postp = postp;
// Create a flag variable to track whether NBA occurred
const std::string flagName = "__VdlySet__" + vscp->varp()->shortName();
AstVarScope* const commitFlagp = createTemp(flp, scopep, flagName, 1);
commitFlagp->varp()->setIgnorePostWrite();
vscpInfo.flagUniqueKit().commitFlagp = commitFlagp;
// Create a value variable to track the final value after a NBA
const std::string valName = "__VdlyVal__" + vscp->varp()->shortName();
AstVarScope* const commitValp = createTemp(flp, scopep, valName, vscp->dtypep());
vscpInfo.flagUniqueKit().commitValp = commitValp;
// NBA 'Post' block: if (__VdlySet) { __VdlySet = 0; var = __VdlyVal; }
// This runs after all NBAs in the time step, applying the last captured value
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, commitFlagp, VAccess::READ}};
postp->addStmtsp(ifp);
ifp->addThensp(new AstAssign{flp, new AstVarRef{flp, commitFlagp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse{}}});
ifp->addThensp(new AstAssign{flp, new AstVarRef{flp, vscp, VAccess::WRITE},
new AstVarRef{flp, commitValp, VAccess::READ}});
}
void convertSchemeFlagUnique(AstAssignDly* nodep, AstVarScope* vscp, VarScopeInfo& vscpInfo) {
UASSERT_OBJ(vscpInfo.m_scheme == Scheme::FlagUnique, vscp, "Inconsistent NBA scheme");
FileLine* const flp = vscp->fileline();
AstScope* const scopep = VN_AS(nodep->user2p(), Scope);
FileLine* const flp = nodep->fileline();
// Base name suffix for signals constructed below
const std::string baseName = uniqueTmpName(scopep, vscp, vscpInfo);
AstVarScope* const commitFlagp = vscpInfo.flagUniqueKit().commitFlagp;
AstVarScope* const commitValp = vscpInfo.flagUniqueKit().commitValp;
// Unlink and capture the RHS value
AstNodeExpr* const capturedRhsp
= captureVal(scopep, nodep, nodep->rhsp()->unlinkFrBack(), "__VdlyVal" + baseName);
// Whole-variable update: use shared flag/value so last NBA wins
if (VN_IS(nodep->lhsp(), VarRef)) {
// Capture the RHS value to be applied at 'Post' time
nodep->addHereThisAsNext(new AstAssign{flp,
new AstVarRef{flp, commitValp, VAccess::WRITE},
nodep->rhsp()->unlinkFrBack()});
// Set the flag to indicate this NBA needs to be applied
nodep->addHereThisAsNext(new AstAssign{flp,
new AstVarRef{flp, commitFlagp, VAccess::WRITE},
new AstConst{flp, AstConst::BitTrue{}}});
} else {
// Partial update: different bits/indices may be written, so each needs its own flag
AstScope* const scopep = VN_AS(nodep->user2p(), Scope);
const std::string baseName = uniqueTmpName(scopep, vscp, vscpInfo);
AstNodeExpr* const capturedRhsp
= captureVal(scopep, nodep, nodep->rhsp()->unlinkFrBack(), "__VdlyVal" + baseName);
AstNodeExpr* const capturedLhsp
= captureLhs(scopep, nodep, nodep->lhsp()->unlinkFrBack(), baseName);
AstVarScope* const uniqueFlagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
uniqueFlagVscp->varp()->setIgnorePostWrite();
// Unlink and capture the LHS reference
AstNodeExpr* const capturedLhsp
= captureLhs(scopep, nodep, nodep->lhsp()->unlinkFrBack(), baseName);
// Set the flag to indicate this partial NBA needs to be applied
nodep->addHereThisAsNext(
new AstAssign{flp, new AstVarRef{flp, uniqueFlagVscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitTrue{}}});
// Create new flag
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
flagVscp->varp()->setIgnorePostWrite();
// Set the flag at the original NBA
nodep->addHereThisAsNext( //
new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitTrue{}}});
// Add the 'Post' scheduled commit
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, flagVscp, VAccess::READ}};
vscpInfo.flagUniqueKit().postp->addStmtsp(ifp);
// Immediately clear the flag
ifp->addThensp(new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse{}}});
// Commit the value
ifp->addThensp(new AstAssign{flp, capturedLhsp, capturedRhsp});
// NBA 'Post' block: if (__VdlySet) { __VdlySet = 0; var[idx] = __VdlyVal; }
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, uniqueFlagVscp, VAccess::READ}};
vscpInfo.flagUniqueKit().postp->addStmtsp(ifp);
ifp->addThensp(new AstAssign{flp, new AstVarRef{flp, uniqueFlagVscp, VAccess::WRITE},
new AstConst{flp, AstConst::BitFalse{}}});
ifp->addThensp(new AstAssign{flp, capturedLhsp, capturedRhsp});
}
// Delete original NBA
pushDeletep(nodep->unlinkFrBack());

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of either the GNU Lesser General Public License Version 3
# or the Perl Artistic License Version 2.0.
# SPDX-FileCopyrightText: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.compile(verilator_flags2=["--binary", "--assert"])
test.execute()
test.passes()

View File

@ -0,0 +1,44 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Ethan Sifferman
// SPDX-License-Identifier: CC0-1.0
module t;
int delay = 0; always #1 delay = int'($time) / 4;
task automatic do_delay;
if (delay > 0) #(delay);
endtask
// `a` should match `b`
logic a = 0;
always begin
a <= 1;
do_delay();
a <= 0;
#1;
end
logic b = 0;
always begin
b <= 1;
do_delay();
b <= 0;
#1;
b <= 1; // this line should do nothing
end
always #1 assert (a == b);
initial begin
$dumpfile("dump.vcd");
$dumpvars;
#20;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule