parent
748e48f881
commit
5831cc8d46
|
|
@ -262,6 +262,9 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
if (it != m_beginDisableBegins.end()) return it->second;
|
||||
|
||||
AstBegin* const beginBodyp = new AstBegin{fl, "", nullptr, false};
|
||||
// Disable-by-name rewrites kill this detached block-body process, so mark it as process
|
||||
// backed to ensure fork/join kill-accounting hooks are always emitted.
|
||||
beginBodyp->setNeedProcess();
|
||||
if (beginp->stmtsp()) beginBodyp->addStmtsp(beginp->stmtsp()->unlinkFrBackWithNext());
|
||||
|
||||
AstFork* const forkp = new AstFork{fl, VJoinType::JOIN};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
Fast clock (200ns half-period): o_counter=7
|
||||
Slow clock (5400ns half-period): o_counter=3
|
||||
*-* All Finished *-*
|
||||
|
|
@ -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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary", "-Wno-ZERODLY"])
|
||||
|
||||
test.execute(expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// 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
|
||||
|
||||
// Clock-period detector exercising a named-block `disable` of a block whose
|
||||
// body contains a nested fork..join. Disabling such a block from a sibling
|
||||
// process must release the enclosing fork..join so the surrounding `always`
|
||||
// block keeps iterating.
|
||||
|
||||
module disable_fork (
|
||||
input logic i_clk,
|
||||
output logic [2:0] o_counter
|
||||
);
|
||||
time delay1 = 500ns; // min period
|
||||
time delay2 = 3333ns; // max period
|
||||
|
||||
logic clk_re = 1'b0; // rising edge of the clock
|
||||
logic [2:0] counter = 3'b000;
|
||||
|
||||
always begin
|
||||
fork
|
||||
begin : check1
|
||||
#delay1;
|
||||
#1 disable check2;
|
||||
fork
|
||||
begin : check3
|
||||
#(delay2 - delay1);
|
||||
clk_re <= 1'b0;
|
||||
#1 disable check4;
|
||||
if (counter < 3'b111) counter <= counter + 3'b001;
|
||||
end
|
||||
begin : check4
|
||||
@(posedge i_clk);
|
||||
clk_re <= 1'b1;
|
||||
counter <= 3'b000;
|
||||
#1 disable check3;
|
||||
end
|
||||
join
|
||||
end
|
||||
begin : check2
|
||||
@(posedge i_clk);
|
||||
clk_re <= 1'b0;
|
||||
#1 disable check1;
|
||||
if (counter < 3'b111) counter <= counter + 3'b001;
|
||||
end
|
||||
join
|
||||
end
|
||||
|
||||
assign o_counter = counter;
|
||||
endmodule
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
logic clk;
|
||||
logic [2:0] counter;
|
||||
|
||||
task clk_cycle(input time half_period);
|
||||
clk = 1'b1;
|
||||
#half_period;
|
||||
clk = 1'b0;
|
||||
#half_period;
|
||||
endtask : clk_cycle
|
||||
|
||||
initial begin
|
||||
// Fast clock (period below delay1): every edge arrives before the
|
||||
// min-period timeout, so the counter saturates at its max.
|
||||
repeat (100) clk_cycle(200ns);
|
||||
$display("Fast clock (200ns half-period): o_counter=%0d", counter);
|
||||
`checkh(counter, 3'h7);
|
||||
// Slow clock (period above delay2): the nested fork path runs, which
|
||||
// only works if disabling check1 releases the inner fork..join.
|
||||
repeat (100) clk_cycle(5400ns);
|
||||
$display("Slow clock (5400ns half-period): o_counter=%0d", counter);
|
||||
`checkh(counter, 3'h3);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
disable_fork a_inst(.i_clk(clk), .o_counter(counter));
|
||||
endmodule
|
||||
Loading…
Reference in New Issue