How does forever behaves in fork block

Hi,

If I have two forever blocks in fork block.How does it behaves.

Example::

fork
begin
    forever
    begin
    //logic
    end
end
begin
    forever
    begin
    //logic
    end
end
join

Please someone clarify me abt this.

Thanks.

Hi Sandy1664,

Please use code tags when posting code in the future.

A fork/join splits the current thread into multiple parallel child threads, one for each statement in the block. The parent thread suspends until all child threads complete or terminate. Your fork/join block contains two statements, so there will be two child threads spawned. Each statement happens to be a begin/end block, which will int turn execute each statement inside it sequentially. Your begin/end blocks contains one statement - a forever loop, which repeatedly executes its statement (another begin/end block) over and over indefinitely.

So your fork/join block will suspend the parent thread indefinitely until both forever loops are terminated either by a break or some other process terminating statement.

In reply to dave_59:

Hi Dave,

Thanks for the explanation.Have a look at the code

fork
forever
begin:label_1
wait(flag1==1);
$display(“flag1 asserted”);
#(duration);
flag2 = 1;
end
forever
begin
@(flag1);
if(flag1==0)
disable label_1;
end
join

multiple processes of label_1 will get created at same time or create one after the other after flag2 becomes 1.

Best Regards,
Sandy.

In reply to sandy1664:

Sorry, I’m not going to look at your code until you add code tags.

In reply to dave_59:

What do you mean by adding code tags Dave ?

In reply to roopanandakumaran:

https://verificationacademy.com/forums/ovm/please-format-your-code-code-and/code-tags

In reply to dave_59:

Hi Dave,

Thanks for the explanation.Have a look at the code

fork 
  forever
    begin:label_1
      wait(flag1==1); 
      $display("flag1 asserted");
      #(duration);
      flag2 = 1;
    end
  forever
    begin
      @(flag1);
      if(flag1==0)
        disable label_1;
    end
join

multiple processes of label_1 will get created at same time or create one after the other after flag2 becomes 1.

Best Regards,
Sandy.

October 28, 2014 at 9:33 am
sandy1664
sandy1664

In reply to sandy1664:

There are two processes created by the fork/join block - the two forever statements. label_1 is a statement label that is a part of the forever statement; label_1 is not a separate process. The disable statement just terminates the statement with the label_1. Terminating a statement means it jumps to the end of the statement. And since this statement is inside a forever statement, it repeats the statement forever.

You can wrap the two forever statements in begin/end blocks without changing the functionality.

fork 
  begin : process_1
    forever
    begin:label_1
      wait(flag1==1); 
      $display("flag1 asserted");
      #(duration);
      flag2 = 1;
    end
 end : process_1
 begin : process_2
  forever
    begin
      @(flag1);
      if(flag1==0)
        disable label_1;
    end
  end : process_2
join

But now the statement label process_1 encompasses an entire process, so disabling that statement will terminate the process.

P.S. You need to be careful using the disable label; statement. Statement labels are static identifiers and if the label is inside a task and there are multiple invocations of the task, disabling the label will disable all invocations of that label inside all tasks. SystemVerilog provides a variety of other mechanisms to terminate process that are more specific to the current process. (disable fork, process::kill)


In reply to dave_59:

Hi Dave,
I am also using the same code type above . I am facing a problem in my problem flag1 == 1 coming two times but print is coming only once. I need display whenever the signal flag1 ==1 .

Regards,
Jyothsna.

In reply to Jyothsna:

Can’t help you without knowing the timing of ‘flag1’ and the value of ‘duration’. Also, a better way of modeling what they wanted is

 forever begin
    fork
       begin
         wait(flag1==1); 
         $display("flag1 asserted");
         #(duration);
         flag2 = 1;
       end
       @negedge flag1;
    join_any
    disable fork;
  end

In reply to dave_59:
With the above syntax i tried it could stucked at run_phase itself. so i tried with the below syntax.

task run_phase
                begin
                   fork
                     begin
                         test1();
                     end
                     begin
                         test2();
                     end
                     join
                  end
                  endtask : run_phase
                  task test1();
                     begin
                        forever @(posedge clk);
                         begin
                            fork
                               begin
                                 @(posedge intf.c1);
                                  uvm_info("p1",uvm_low)
                                end
                                begin
                                 @(posedge intf.c2);
                                  uvm_info("p2",uvm_low)
                                end 
                                 join_none
                            end
                        end
                     endtask 
                     task test2();
                     begin
                        forever @(posedge clk1);
                         begin
                            fork
                               begin
                                 @(posedge intf.c6);
                                  uvm_info("p6",uvm_low)
                                end
                                begin
                                 @(posedge intf.c7);
                                  uvm_info("p7",uvm_low)
                                end 
                                 join_none
                            end
                        end
                     endtask

I need to check c1,c2,c6,c7 until case to be done so i kept fork in raise, drop objections.
The clk,clk1 are of high speed. When the c1,c2,c6,c7 are hit first time at the same time stamp p1,p2,p6,p7 prints are coming continuously.

In reply to Jyothsna:
It would help readability to remove all of the unnecessary begin/end keywords. Also, I assume the semicolons after the @(posedge clk) are typos. Otherwise your code would hang and there would be no output. Here is your code with that corrected:

task run_phase;
  fork
     test1();
     test2();
  join
endtask : run_phase
task test1();
   forever @(posedge clk)
     fork
	begin
           @(posedge intf.c1);
           `uvm_info("p1",uvm_low)
	end
	begin
           @(posedge intf.c2);
           `uvm_info("p2",uvm_low)
	end 
     join_none
endtask 
task test2();
   forever @(posedge clk1)
     fork
	begin
           @(posedge intf.c6);
           `uvm_info("p6",uvm_low)
	end
	begin
           @(posedge intf.c7);
           `uvm_info("p7",uvm_low)
	end 
     join_none
endtask

Now it is easy to see that for each iteration of the forever loop, you are creating a set 4 processes associated with p1, p2, p6 and p7. And every posedge clk you are creating another 4 processes, but the previous process are still active since you used join_none. So by the time you get your c1,c2, c6, or c7 event, there are many processes waiting for that event.

I don’t know what you are trying to achieve, so it is difficult to recommend an alternative.

In reply to dave_59:

Hi Dave,

I have a similar question here. My requirement is like below. We have 4 DMA engines and each of them are separately. They need to do something forever in my test. Here is my code but I am not sure if it’s correct.



task my_thread();

    fork
        begin
            for (int i = 0; i < 4; i++) begin
                automatic int ii = i;
                fork
                    forever begin
                        cycle = $urandom_range(10,1000);
                        wait_cycle(cycle);
                        do something here...
                    end
                join_none
            end
            wait fork;
        end
    join

endtask : my_thread

[\systemverilog]


and I wonder how can I disable the whole thread if we reach to the end of simulation.

In reply to dave_59:

In reply to sandy1664:
There are two processes created by the fork/join block - the two forever statements. label_1 is a statement label that is a part of the forever statement; label_1 is not a separate process. The disable statement just terminates the statement with the label_1. Terminating a statement means it jumps to the end of the statement. And since this statement is inside a forever statement, it repeats the statement forever.
You can wrap the two forever statements in begin/end blocks without changing the functionality.

fork 
begin : process_1
forever
begin:label_1
wait(flag1==1); 
$display("flag1 asserted");
#(duration);
flag2 = 1;
end
end : process_1
begin : process_2
forever
begin
@(flag1);
if(flag1==0)
disable label_1;
end
end : process_2
join

But now the statement label process_1 encompasses an entire process, so disabling that statement will terminate the process.
P.S. You need to be careful using the disable label; statement. Statement labels are static identifiers and if the label is inside a task and there are multiple invocations of the task, disabling the label will disable all invocations of that label inside all tasks. SystemVerilog provides a variety of other mechanisms to terminate process that are more specific to the current process. (disable fork, process::kill)

Dave, Thanks for the explanation.
A following up question regarding disable fork vs disable label of fork for all descendants. Will “disable label of fork” disable all descendants processes?
For example;

 
        task threads();
          fork : PROC_1
            #10; 
          join : PROC_1
        endtask

       initial begin
         fork : PROC_2
           threads();
           #5;
         join_any
         // disable fork; will disable PROC_1. 
         disable PROC_2   Will the PROC_1 get disabled ? It seems the result is not 
                            same from 3 different simulator.