4 process and execution

There are 4 processes. Among them in the 1st 3 processes, all 3 must get triggered at the same time and run in parallel. The 4th process should start after any one process in the 2nd and 3rd gets over and the 1st process should also get over. When the 4th process starts executing, the pending process that did not get over must still continue their execution. Note : If the 1st process get over quickly then you must wait for anyone process in the 2nd and 3rd process to get over before starting with the 4th process.
Please give me a solution with using any event, semaphore, wait statements, etc. Use only fork join flavors and fork join concepts like disable fork and wait fork.

In reply to Ravi007:
I am presuming that your “process” is a task.
Below is an example. Change the conditions as needed.


import uvm_pkg::*; `include "uvm_macros.svh"
module top;
    bit clk, a, b;
    event e1, e2, e3, e4; 
    default clocking @(posedge clk); endclocking
        initial forever #10 clk=!clk;   
        /* There are 4 processes. Among them in the 1st 3 processes, 
        all 3 must get triggered at the same time and run in parallel. 
        The 4th process should start after any one process in the 2nd and 3rd gets over 
        and the 1st process should also get over. 
        When the 4th process starts executing, the pending process 
        that did not get over must still continue their execution. Note : 
        If the 1st process get over quickly then you must wait for anyone 
        process in the 2nd and 3rd process to get over before starting with the 4th process. */
        
        task automatic c_master(); 
            bit[1:3] done; 
            fork
                c_p(1, done); // process p1
                c_p(2, done); // p2
                c_p(3, done); // p3
            join_none 
            wait(done); // any one 
            if(done[1]) wait((done[2] || done[3]) ); 
            else wait((done[2] || done[3]) && done[1]);
            fork
                c_p4(4); // the 4, done is optional 
            join_none 
        endtask 
        
        // task automatic c_p(int unit, inout bit[1:3] done); *** BAD ***
        task automatic c_p(int unit, ref bit[1:3] done);
            bit[4:0] delay; 
            if (!randomize(delay)) `uvm_error("MYERR", "This is a randomize error")
            repeat(delay+1) @(posedge clk); 
            if(unit==1) -> e1; else if(unit==2) -> e2; else if(unit==3) -> e3;
            $display("%t unit= %d", $realtime, unit); 
            done[unit]=1'b1;
        endtask
        
        task automatic c_p4(int unit);
            repeat(4) @(posedge clk); 
            $display("%t c_p4= %d", $realtime, unit); 
            -> e4; 
        endtask
        
        // Start the main task here 
        initial begin  
            #10 fork c_master(); join_none
        end

        
        initial begin 
            bit va, vb;
            repeat(200) @(posedge clk); 
            $finish; 
        end  
    endmodule   
#                  190 unit=           1
#                  230 unit=           3
#                  230 unit=           2
#                  310 c_p4=           4

 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


  1. SVA Alternative for Complex Assertions
    Verification Horizons - March 2018 Issue | Verification Academy
  2. SVA: Package for dynamic and range delays and repeats | Verification Academy
  3. SVA in a UVM Class-based Environment
    SVA in a UVM Class-based Environment | Verification Horizons | Verification Academy

In reply to ben@SystemVerilog.us:
I modified the delays, but am puzzled as to why the model got stuck on the wait
specifically


...
 wait(done); // any one 
            if(done[1]) wait((done[2] || done[3]) ); 
            else wait((done[2] || done[3]) && done[1]);
            $display("%t DONE", $realtime);
..
// simulation 
                  10 unit=           2
                  10 unit=           3
                  30 unit=           1
Simulation complete via $finish(1) at time 3990 NS + 0
 
SInce done[1]==0 at t=10, the 
else wait((done[2] || done[3]) && done[1]); should take effect. 
But 2, and 3 and 1 are done, then why did it not get out of the wait? 
Expected the  $display("%t DONE", $realtime);

??
BTW, this is tool independent, works the same on various tools
from 1800 wait_statement ::= // from A.6.5
wait ( expression ) statement_or_null
wait((done[2] || done[3]) && done[1]) Should be legal.  
???

Ben

In reply to ben@SystemVerilog.us:
Updated model with more debug, but the same issue

 
With those results
#                   10 unit=           2
#                   10 unit=           3
#                   12 in else of done[1], wait((done[2] || done[3]) && done[1]
#                   30 unit=           1
// units 1, 2, and 3 are done, yet this wait never gets finished. Why not? 
wait((done[2] || done[3]) && done[1]);

//--------------------------------------------------
            wait(done); // any one 
            #2; // though this may help, it did not 
            if(done[1]) begin 
                $display("%t in done[1], wait((done[2] || done[3])", $realtime);
                wait((done[2] || done[3]) ); 
            end
            else begin 
                $display("%t in else of done[1], wait((done[2] || done[3]) && done[1]", $realtime);
                wait((done[2] || done[3]) && done[1]); // <----*** HUNG HERE, WHY? 
            end
            $display("%t ALL DONE", $realtime);

BTY, this change did not work
join_none
#2;
wait(done); // any one

Test code


import uvm_pkg::*; `include "uvm_macros.svh"
module top;
    bit clk, a, b;
    event e1, e2, e3, e4; 
    default clocking @(posedge clk); endclocking
        initial forever #10 clk=!clk;   
        /* There are 4 processes. Among them in the 1st 3 processes, 
        all 3 must get triggered at the same time and run in parallel. 
        The 4th process should start after any one process in the 2nd and 3rd gets over 
        and the 1st process should also get over. 
        When the 4th process starts executing, the pending process 
        that did not get over must still continue their execution. Note : 
        If the 1st process get over quickly then you must wait for anyone 
        process in the 2nd and 3rd process to get over before starting with the 4th process. */
        
        task automatic c_master(); 
            bit[1:3] done; 
            fork
                c_p(1, done); // process 1
                c_p(2, done); 
                c_p(3, done); 
            join_none 
            wait(done); // any one 
            #2; 
            if(done[1]) begin 
                $display("%t in done[1], wait((done[2] || done[3])", $realtime);
                wait((done[2] || done[3]) ); 
            end
            else begin 
                $display("%t in else of done[1], wait((done[2] || done[3]) && done[1]", $realtime);
                wait((done[2] || done[3]) && done[1]);
            end
            $display("%t ALL DONE", $realtime);
            fork
                c_p4(4); // the 4, done is optional 
            join_none 
        endtask 
        
        task automatic c_p(int unit, inout bit[1:3] done);
            bit[3:0] delay; 
            if (!randomize(delay)) `uvm_error("MYERR", "This is a randomize error")
            // repeat(delay * unit) @(posedge clk); 
          if(unit==1) repeat(unit) @(posedge clk); 
          //else repeat(delay * unit) @(posedge clk);
          if(unit==1) -> e1; else if(unit==2) -> e2; else if(unit==3) -> e3;
            $display("%t unit= %d", $realtime, unit); 
            done[unit]=1'b1;
        endtask
        
        task automatic c_p4(int unit);
            repeat(4) @(posedge clk); 
            $display("%t c_p4= %d", $realtime, unit); 
            -> e4; 
        endtask
        
        // Fork main 
        initial begin  
            #10 fork c_master(); join_none
        end

        
        initial begin 
            bit va, vb;
            repeat(200) @(posedge clk); 
            $finish; 
        end  
    endmodule  
  // simulation 
#                   10 unit=           2
#                   10 unit=           3
#                   12 in else of done[1], wait((done[2] || done[3]) && done[1]
#                   30 unit=           1
# ** Note: $finish    
    
    
    
    
 

In reply to ben@SystemVerilog.us:

Experimenting a bit more, it works, but I still have the question on my preceding post.
Basically, I added time delay in tasks unit 1, 2 and 3. In the preceding post, only task unit 1 had a delay, the others has zero delay and immediately returned a done when forked.


#                   30 unit=           1
#                   32 in done[1], wait((done[2] || done[3])
#                   90 unit=           2
#                   90 ALL DONE
#                  130 unit=           3
#                  170 c_p4=           4


import uvm_pkg::*; `include "uvm_macros.svh"
module top;
    bit clk, a, b;
    event e1, e2, e3, e4; 
    default clocking @(posedge clk); endclocking
        initial forever #10 clk=!clk;   
        /* There are 4 processes. Among them in the 1st 3 processes, 
        all 3 must get triggered at the same time and run in parallel. 
        The 4th process should start after any one process in the 2nd and 3rd gets over 
        and the 1st process should also get over. 
        When the 4th process starts executing, the pending process 
        that did not get over must still continue their execution. Note : 
        If the 1st process get over quickly then you must wait for anyone 
        process in the 2nd and 3rd process to get over before starting with the 4th process. */
        
        task automatic c_master(); 
            bit[1:3] done; 
            fork
                c_p(1, done); // process 1
                c_p(2, done); 
                c_p(3, done); 
            join_none 
            wait(done); // any one 
            #2; 
            if(done[1]) begin 
                $display("%t in done[1], wait((done[2] || done[3])", $realtime);
                wait((done[2] || done[3]) ); 
            end
            else begin 
                $display("%t in else of done[1], wait((done[2] || done[3]) && done[1]", $realtime);
                wait((done[2] || done[3]) && done[1]);
            end
            $display("%t ALL DONE", $realtime);
            fork
                c_p4(4); // the 4, done is optional 
            join_none 
        endtask 
        
        task automatic c_p(int unit, inout bit[1:3] done);
            bit[3:0] delay; 
            if (!randomize(delay)) `uvm_error("MYERR", "This is a randomize error")
            // repeat(delay * unit) @(posedge clk); 
          if(unit==1) repeat(unit) @(posedge clk); 
          else repeat(2 * unit) @(posedge clk);
          if(unit==1) -> e1; else if(unit==2) -> e2; else if(unit==3) -> e3;
            $display("%t unit= %d", $realtime, unit); 
            done[unit]=1'b1;
        endtask
        
        task automatic c_p4(int unit);
            repeat(4) @(posedge clk); 
            $display("%t c_p4= %d", $realtime, unit); 
            -> e4; 
        endtask
        
        // Fork main 
        initial begin  
            #10 fork c_master(); join_none
        end

        
        initial begin 
            bit va, vb;
            repeat(200) @(posedge clk); 
            $finish; 
        end  
    endmodule  
    
    
    
    
    


In reply to ben@SystemVerilog.us:

OK, my error was the use of the **inout** instead of **ref** in 
**task automatic c_p(int unit, ref bit[1:3] done);** // That works 

With the ref of done, when done[unit] is updated the whole news 3 bit are reflected for use another task that wants to update the done[unit].
Still puzzled why with the inout a done[2]=1’b1 updates all 3 bits of done and not the just one bit. with task automatic c_p(int unit, ref bit[1:3] done);


// OK results 
# KERNEL:                   14 unit=           2
# KERNEL:                   14 ******** done[1]=0, done[2]=1, done[3]=0
# KERNEL:                   14 in else of done[1], wait((done[2] || done[3]) && done[1]
# KERNEL:                   14 done[1]=0, done[2]=1, done[3]=0
# KERNEL:                   15 unit=           3
# KERNEL:                   15 ******** done[1]=0, done[2]=1, done[3]=1
# KERNEL:                   30 unit=           1
# KERNEL:                   30 ******** done[1]=1, done[2]=1, done[3]=1
# KERNEL:                   30 done[1]=1, done[2]=1, done[3]=1
# KERNEL:                   30 ALL DONE
# KERNEL:                  110 c_p4=           4

with the inout task automatic c_p(int unit, inout bit[1:3] done);


# KERNEL:                   14 unit=           2
# KERNEL:                   14 ******** done[1]=0, done[2]=1, done[3]=0
# KERNEL:                   14 in else of done[1], wait((done[2] || done[3]) && done[1]
# KERNEL:                   14 done[1]=0, done[2]=1, done[3]=0
# KERNEL:                   15 unit=           3
# KERNEL:                   15 ******** done[1]=0, done[2]=0, done[3]=1
# KERNEL:                   30 unit=           1
# KERNEL:                   30 ******** done[1]=1, done[2]=0, done[3]=0
# RUNTIME: Info: RUNTIME_0068 testbench.sv (77): $finish called. 

This worked for me:

event Event_a;
class fork_test extends uvm_sequence_item;

task parallel_forks();
    fork
        A(); //process 1
        fork
           B(); //process 2
           C(); //process 3
         join_any
     join
     D(); //process 4
endtask

task A();
wait (Event_a.triggered);
$display("Started A: %t", $realtime);
#70;
endtask

task B();
wait (Event_a.triggered);
$display("Started B: %t", $realtime);
#40;
endtask

task C();
wait (Event_a.triggered);
$display("Started C: %t", $realtime);
#150;
endtask

task D();
$display("Started D: %t", $realtime);
endtask

function new(string name);
   super.new(name);
endfunction 
      
endclass


Module top;
initial begin
parallel_forks();
#20;
->Event_a;
end
endmodule

Run time:

Started A: 20
Started B: 20
Started C: 20
Started D: 90

Although I am using event to trigger all 3 processes together(A,B and C), you don’t have to. By default they all start together.