verilator/test_regress/t/t_disable_fork_join.v

172 lines
4.2 KiB
Systemverilog

// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
// Disabling a named fork..join / fork..join_any block from one of its own
// branches must terminate the sibling branches, including any that are
// suspended on a delay. This is the join/join_any analogue of the
// fork..join_none cases in t_disable_inside (#6591): the bug was that a sibling
// spawned later in source order registered its process for kill only after the
// disabling branch had already issued the kill, so the sibling survived and its
// $stop fired one time unit later.
// verilog_format: off
`define stop $stop
`define checkt(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0t exp=%0t (%t !== %t)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
module t;
// fork..join: the disabling branch comes first, the delayed sibling second.
initial begin
fork : fork_blk2
begin
`checkt($time, 0);
disable fork_blk2;
$stop;
end
begin
`checkt($time, 0);
#1 $stop;
end
join
end
// fork..join: the delayed sibling comes first, the disabling branch second.
initial begin
fork : fork_blk3
begin
`checkt($time, 0);
#1 $stop;
end
begin
`checkt($time, 0);
disable fork_blk3;
$stop;
end
join
end
// fork..join: the delayed sibling also contains an unreachable disable, which
// makes LinkJump wrap its registration in a JumpBlock. It must still register
// before the synthetic fork-start delay so the earlier disable kills it.
initial begin
fork : fork_blk_wrap
begin
`checkt($time, 0);
disable fork_blk_wrap;
$stop;
end
begin
`checkt($time, 0);
#1;
if ($c("false")) disable fork_blk_wrap;
$stop;
end
join
end
// fork..join_any: the disabling branch comes first, the delayed sibling second.
initial begin
fork : fork_blk2a
begin
`checkt($time, 0);
disable fork_blk2a;
$stop;
end
begin
`checkt($time, 0);
#1 $stop;
end
join_any
end
// fork..join_any: the delayed sibling comes first, the disabling branch second.
initial begin
fork : fork_blk3a
begin
`checkt($time, 0);
#1 $stop;
end
begin
`checkt($time, 0);
disable fork_blk3a;
$stop;
end
join_any
end
// fork..join_any: the delayed sibling's own unreachable disable again forces a
// JumpBlock wrapper around its registration.
initial begin
fork : fork_blk_wrap_any
begin
`checkt($time, 0);
disable fork_blk_wrap_any;
$stop;
end
begin
`checkt($time, 0);
#1;
if ($c("false")) disable fork_blk_wrap_any;
$stop;
end
join_any
end
// fork..join that can be disabled, but takes the path where disable is not
// reached: both branches must run to completion with their timing intact.
initial begin
fork : fork_blk4
begin
`checkt($time, 0);
if ($c("false")) begin
disable fork_blk4;
$stop;
end
#1;
`checkt($time, 1);
end
begin
`checkt($time, 0);
#1;
`checkt($time, 1);
end
join
end
// Deeply nested fork..join: the named fork is several levels deep inside other
// forks and one of its own branches disables it. The delayed sibling at that
// deep level must still be killed, so the fix has to work when the disable-able
// fork is itself nested inside other (suspending) forks.
initial begin
fork
begin
fork
begin
fork : fork_deep
begin
`checkt($time, 0);
disable fork_deep;
$stop;
end
begin
`checkt($time, 0);
#1 $stop;
end
join
end
join
end
join
end
initial begin
#10;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule