Disable keyword is not working when we launch threads with fork - join_none in a loop

Hi Dave,
I was trying to solve a problem related to fork - join_none on
posted on the forum. The problem statement was to spawn ‘N’ threads parallely, and wait only till one of these processes are complete. Once it completes, kill the remaining threads.
I came up with the following solution :

module testbench;
  
  semaphore sm;
  initial begin
    
    sm = new();
    for (int i = 0; i< 10; i ++) begin
      fork : f1
        automatic int j = i;
        begin : forked_block
          something(j);
        end
      join_none
      
    end
    #1;
    sm.get(1);
    disable f1.forked_block;
   //disable fork
    $display($time, " : Killed the rest of the processes");
      
  end
  
  task automatic something(int k);
    bit [7:0] delay;
    delay = $urandom();
    $display($time," : Waiting for delay = %d", delay);
    #(delay);
    $display($time, " : Done waiting for delay = %d", delay);    
    sm.put(1);
  endtask
  
endmodule

I get this compile error when I try to run it :

Loading module testbench
** Error (suppressible): testbench.sv(349): (vopt-7063) Failed to find ‘f1’ in hierarchical name ‘f1.forked_block’.
Region: testbench
Optimization failed

If I use disable fork, the code works as intended, but I was curious if we could do the similar thing using named blocks for this case.
I have deliberately added #1 delay to ensure that the threads spawned have started running before we are actually using disable.
Even if I remove “f1” label in fork, and use only the “forked_block” label in begin…end block, I see the same problem of hierarchical name not found.

Could you please help me understand what could the problem here?

The problem is when declaring a for-loop iterator variable like for(int i=0;..., SystemVerilog creates an unnamed block whose scope contains the iterator variable, and the names of everything else declared inside that loop. You cannot have hierarchical references to names inside an unnamed block from outside it.

You move the declaration of i outside the loop, or use a statement label, like

 initial begin
    
    sm = new();
    name: for (int i = 0; i< 10; i ++)
      fork : f1
        automatic int j = i;
        begin : forked_block
          something(j);
        end
      join_none
      #1;
    sm.get(1);
    disable name.f1.forked_block;
   //disable fork
    $display($time, " : Killed the rest of the processes");
      
  end

I would discourage the use of disable named_blocks. If you were to put the named block into a task and have multiple concurrent invocations of that task, this is no way to discern which invocation of the task you want the disable named block to apply to.

1 Like