This commit is contained in:
parent
1f0357ba93
commit
1bf24c7eb4
|
|
@ -185,6 +185,56 @@ class LinkJumpVisitor final : public VNVisitor {
|
||||||
return new AstStmtExpr{
|
return new AstStmtExpr{
|
||||||
fl, new AstMethodCall{fl, queueRefp, "push_back", new AstArg{fl, "", processSelfp}}};
|
fl, new AstMethodCall{fl, queueRefp, "push_back", new AstArg{fl, "", processSelfp}}};
|
||||||
}
|
}
|
||||||
|
void handleDisableOnFork(AstDisable* const nodep, const std::vector<AstBegin*>& forks) {
|
||||||
|
// The support is limited only to disabling a fork from outside that fork.
|
||||||
|
// It utilizes the process::kill()` method. For each `disable` a queue of processes is
|
||||||
|
// declared. At the beginning of each fork that can be disabled, its process handle is
|
||||||
|
// pushed to the queue. `disable` statement is replaced with calling `kill()` method on
|
||||||
|
// each element of the queue.
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
const std::string targetName = nodep->targetp()->name();
|
||||||
|
if (existsBlockAbove(targetName)) {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from within same fork");
|
||||||
|
}
|
||||||
|
if (m_ftaskp) {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from task / function");
|
||||||
|
}
|
||||||
|
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
|
||||||
|
AstClass* const processClassp
|
||||||
|
= VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class);
|
||||||
|
// Declare queue of processes (as a global variable for simplicity)
|
||||||
|
AstVar* const processQueuep = new AstVar{
|
||||||
|
fl, VVarType::VAR, m_queueNames.get(targetName), VFlagChildDType{},
|
||||||
|
new AstQueueDType{fl, VFlagChildDType{},
|
||||||
|
new AstClassRefDType{fl, processClassp, nullptr}, nullptr}};
|
||||||
|
processQueuep->lifetime(VLifetime::STATIC);
|
||||||
|
topPkgp->addStmtsp(processQueuep);
|
||||||
|
|
||||||
|
AstVarRef* const queueWriteRefp
|
||||||
|
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::WRITE};
|
||||||
|
AstStmtExpr* pushCurrentProcessp = getQueuePushProcessSelfp(queueWriteRefp);
|
||||||
|
|
||||||
|
for (AstBegin* const beginp : forks) {
|
||||||
|
if (pushCurrentProcessp->backp()) {
|
||||||
|
pushCurrentProcessp = pushCurrentProcessp->cloneTree(false);
|
||||||
|
}
|
||||||
|
if (beginp->stmtsp()) {
|
||||||
|
// There is no need to add it to empty block
|
||||||
|
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstVarRef* const queueRefp = new AstVarRef{fl, topPkgp, processQueuep, VAccess::READWRITE};
|
||||||
|
AstTaskRef* const killQueueCall
|
||||||
|
= new AstTaskRef{fl, VN_AS(getMemberp(processClassp, "killQueue"), Task),
|
||||||
|
new AstArg{fl, "", queueRefp}};
|
||||||
|
killQueueCall->classOrPackagep(processClassp);
|
||||||
|
nodep->addNextHere(new AstStmtExpr{fl, killQueueCall});
|
||||||
|
}
|
||||||
|
static bool directlyUnderFork(const AstNode* const nodep) {
|
||||||
|
if (nodep->backp()->nextp() == nodep) return directlyUnderFork(nodep->backp());
|
||||||
|
if (VN_IS(nodep->backp(), Fork)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
|
|
@ -369,35 +419,9 @@ class LinkJumpVisitor final : public VNVisitor {
|
||||||
if (VN_IS(targetp, Task)) {
|
if (VN_IS(targetp, Task)) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling task by name");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling task by name");
|
||||||
} else if (AstFork* const forkp = VN_CAST(targetp, Fork)) {
|
} else if (AstFork* const forkp = VN_CAST(targetp, Fork)) {
|
||||||
// The support is limited only to disabling a fork from outside that fork.
|
std::vector<AstBegin*> forks;
|
||||||
// It utilizes the process::kill()` method. For each `disable` a queue of processes is
|
|
||||||
// declared. At the beginning of each fork that can be disabled, its process handle is
|
|
||||||
// pushed to the queue. `disable` statement is replaced with calling `kill()` method on
|
|
||||||
// each element of the queue.
|
|
||||||
if (existsBlockAbove(forkp->name())) {
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from within same fork");
|
|
||||||
}
|
|
||||||
if (m_ftaskp) {
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from task / function");
|
|
||||||
}
|
|
||||||
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
|
|
||||||
AstClass* const processClassp
|
|
||||||
= VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class);
|
|
||||||
// Declare queue of processes (as a global variable for simplicity)
|
|
||||||
AstVar* const processQueuep = new AstVar{
|
|
||||||
fl, VVarType::VAR, m_queueNames.get(forkp->name()), VFlagChildDType{},
|
|
||||||
new AstQueueDType{fl, VFlagChildDType{},
|
|
||||||
new AstClassRefDType{fl, processClassp, nullptr}, nullptr}};
|
|
||||||
processQueuep->lifetime(VLifetime::STATIC);
|
|
||||||
topPkgp->addStmtsp(processQueuep);
|
|
||||||
|
|
||||||
AstVarRef* const queueWriteRefp
|
|
||||||
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::WRITE};
|
|
||||||
AstStmtExpr* const pushCurrentProcessp = getQueuePushProcessSelfp(queueWriteRefp);
|
|
||||||
|
|
||||||
for (AstNode* forkItemp = forkp->stmtsp(); forkItemp; forkItemp = forkItemp->nextp()) {
|
for (AstNode* forkItemp = forkp->stmtsp(); forkItemp; forkItemp = forkItemp->nextp()) {
|
||||||
// Add push_back statement at the beginning of each fork.
|
// Further handling of disable stmt requires all forks to be begin blocks
|
||||||
// Wrap into begin block if needed
|
|
||||||
AstBegin* beginp = VN_CAST(forkItemp, Begin);
|
AstBegin* beginp = VN_CAST(forkItemp, Begin);
|
||||||
if (!beginp) {
|
if (!beginp) {
|
||||||
beginp = new AstBegin{fl, "", nullptr};
|
beginp = new AstBegin{fl, "", nullptr};
|
||||||
|
|
@ -406,34 +430,28 @@ class LinkJumpVisitor final : public VNVisitor {
|
||||||
// In order to continue the iteration
|
// In order to continue the iteration
|
||||||
forkItemp = beginp;
|
forkItemp = beginp;
|
||||||
}
|
}
|
||||||
if (pushCurrentProcessp->backp()) {
|
forks.push_back(beginp);
|
||||||
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp->cloneTree(false));
|
|
||||||
} else {
|
|
||||||
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
handleDisableOnFork(nodep, forks);
|
||||||
AstVarRef* const queueRefp
|
|
||||||
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::READWRITE};
|
|
||||||
AstTaskRef* const killQueueCall
|
|
||||||
= new AstTaskRef{fl, VN_AS(getMemberp(processClassp, "killQueue"), Task),
|
|
||||||
new AstArg{fl, "", queueRefp}};
|
|
||||||
killQueueCall->classOrPackagep(processClassp);
|
|
||||||
nodep->addNextHere(new AstStmtExpr{fl, killQueueCall});
|
|
||||||
} else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) {
|
} else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) {
|
||||||
const std::string targetName = beginp->name();
|
if (directlyUnderFork(beginp)) {
|
||||||
if (existsBlockAbove(targetName)) {
|
std::vector<AstBegin*> forks{beginp};
|
||||||
if (beginp->user3()) {
|
handleDisableOnFork(nodep, forks);
|
||||||
nodep->v3warn(E_UNSUPPORTED,
|
|
||||||
"Unsupported: disabling block that contains a fork");
|
|
||||||
} else {
|
|
||||||
// Jump to the end of the named block
|
|
||||||
AstJumpLabel* const labelp = findAddLabel(beginp, false);
|
|
||||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"
|
const std::string targetName = beginp->name();
|
||||||
<< targetName << "'");
|
if (existsBlockAbove(targetName)) {
|
||||||
|
if (beginp->user3()) {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED,
|
||||||
|
"Unsupported: disabling block that contains a fork");
|
||||||
|
} else {
|
||||||
|
// Jump to the end of the named block
|
||||||
|
AstJumpLabel* const labelp = findAddLabel(beginp, false);
|
||||||
|
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"
|
||||||
|
<< targetName << "'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nodep->v3fatalSrc("Disable linked with node of unhandled type "
|
nodep->v3fatalSrc("Disable linked with node of unhandled type "
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(timing_loop=True, verilator_flags2=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
begin : blk
|
||||||
|
int x = 0;
|
||||||
|
fork : fork_blk
|
||||||
|
begin
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
x = 1;
|
||||||
|
#2;
|
||||||
|
x = 2;
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
#1;
|
||||||
|
disable fork_blk;
|
||||||
|
#2;
|
||||||
|
if (x != 1) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(timing_loop=True, verilator_flags2=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
begin : blk
|
||||||
|
int x = 0;
|
||||||
|
fork : fork_blk
|
||||||
|
begin
|
||||||
|
#4;
|
||||||
|
x = 3;
|
||||||
|
end
|
||||||
|
begin : begin_blk
|
||||||
|
x = 1;
|
||||||
|
#2;
|
||||||
|
x = 2;
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
#1;
|
||||||
|
disable fork_blk.begin_blk;
|
||||||
|
#2;
|
||||||
|
if (x != 1) $stop;
|
||||||
|
#2;
|
||||||
|
if (x != 3) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(timing_loop=True, verilator_flags2=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
begin : blk
|
||||||
|
int x = 0;
|
||||||
|
fork
|
||||||
|
begin
|
||||||
|
#1;
|
||||||
|
disable begin_blk;
|
||||||
|
end
|
||||||
|
begin : begin_blk
|
||||||
|
x = 1;
|
||||||
|
#2;
|
||||||
|
x = 2;
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
#3;
|
||||||
|
if (x != 1) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue