// 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
