Skip to content

Commit

Permalink
Fix dynamic NBAs with automatic vars
Browse files Browse the repository at this point in the history
Signed-off-by: Krzysztof Bieganski <[email protected]>
  • Loading branch information
kbieganski committed Nov 15, 2023
1 parent dc10118 commit 7cb7fc5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 8 deletions.
19 changes: 14 additions & 5 deletions src/V3Fork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,8 @@ class DynScopeVisitor final : public VNVisitor {
}

static bool hasAsyncFork(AstNode* nodep) {
bool afork = false;
nodep->foreach([&](AstFork* forkp) {
if (!forkp->joinType().join()) afork = true;
});
return afork;
return nodep->exists([](AstFork* forkp) { return !forkp->joinType().join(); })
|| nodep->exists([](AstAssignDly*) { return true; });
}

void bindNodeToDynScope(AstNode* nodep, ForkDynScopeFrame* frame) {
Expand Down Expand Up @@ -415,6 +412,18 @@ class DynScopeVisitor final : public VNVisitor {
}
visit(static_cast<AstNodeStmt*>(nodep));
}
void visit(AstAssignDly* nodep) override {
if (m_procp && !VN_IS(nodep->backp(), Fork) && nodep->lhsp()->exists([](AstVarRef* refp) {
return refp->varp()->isFuncLocal();
})) {
auto* forkp = new AstFork{nodep->fileline(), "", nullptr};
forkp->joinType(VJoinType::JOIN_NONE);
nodep->replaceWith(forkp);
forkp->addStmtsp(nodep);
} else {
iterateChildren(nodep);
}
}
void visit(AstNode* nodep) override {
if (nodep->isTimingControl()) m_afterTimingControl = true;
iterateChildren(nodep);
Expand Down
3 changes: 2 additions & 1 deletion src/V3SchedTiming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ void transformForks(AstNetlist* const netlistp) {
funcp->foreach([&](AstNodeVarRef* refp) {
AstVar* const varp = refp->varp();
AstBasicDType* const dtypep = varp->dtypep()->basicp();
bool passByValue = false;
// If not a fork..join, copy. All write refs should've been handled by V3Fork
bool passByValue = !m_forkp->joinType().join();
if (!varp->isFuncLocal()) {
if (VString::startsWith(varp->name(), "__Vintra")) {
// Pass it by value to the new function, as otherwise there are issues with
Expand Down
8 changes: 6 additions & 2 deletions src/V3Timing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,8 +1029,12 @@ class TimingControlVisitor final : public VNVisitor {
// Special case for NBA
if (inAssignDly) {
// Put it in a fork so it doesn't block
auto* const forkp = new AstFork{flp, "", nullptr};
forkp->joinType(VJoinType::JOIN_NONE);
// Could already be the only thing directly under a fork, reuse that if possible
AstFork* forkp = !nodep->nextp() ? VN_CAST(nodep->firstAbovep(), Fork) : nullptr;
if (!forkp) {
forkp = new AstFork{flp, "", nullptr};
forkp->joinType(VJoinType::JOIN_NONE);
}
if (!m_underProcedure) {
// If it's in a function, it won't be handled by V3Delayed
// Put it behind an additional named event that gets triggered in the NBA region
Expand Down
21 changes: 21 additions & 0 deletions test_regress/t/t_assigndly_dynamic.v
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,26 @@ class nba_waiter;
endtask
endclass

class Foo;
task bar(logic a, logic b);
int x;
int y;
// bar's local vars and intravals could be overwritten by other locals
if (a) x <= `DELAY 'hDEAD;
if (b) y <= `DELAY 'hBEEF;
#2
if (x != 'hDEAD) $stop;
endtask

task qux();
int x[] = new[1];
x[0] <= `DELAY 'hBEEF; // Segfault check
endtask
endclass

module t;
nba_waiter waiter = new;
Foo foo = new;
event e;
int cnt = 0;

Expand All @@ -42,6 +60,9 @@ module t;
waiter.wait_for_nba_region;
if (cnt != 4) $stop;
if ($time != `TIME_AFTER_SECOND_WAIT) $stop;
foo.bar(1, 1);
foo.qux();
#2
$write("*-* All Finished *-*\n");
$finish;
end
Expand Down

0 comments on commit 7cb7fc5

Please sign in to comment.