Fork/join_all with automatic using for loop

Hi Dave,

In one of the thread i have asked a question and you had responded to ask in new thread since that thread is quite long.

I have a question in mind, how does this below piece of code suitable for clock-based and event based simulations.

for(int i = 0; i < 5; i++) begin
  automatic int j;
  j = i;
  fork
    thread(j);
  join_none
end

I am particularly looking for to understand clock-based simulation on above explained code by you.

It helps to understand for implementing some checks for other requirements.

Your inputs are much appreciated.

Sreeni.

In reply to nivas:

Hi Dave,
In one of the thread i have asked a question and you had responded to ask in new thread since that thread is quite long.
I have a question in mind, how does this below piece of code suitable for clock-based and event based simulations.

for(int i = 0; i < 5; i++) begin
automatic int j;
j = i;
fork
thread(j);
join_none
end

I am particularly looking for to understand clock-based simulation on above explained code by you.
It helps to understand for implementing some checks for other requirements.
Your inputs are much appreciated.
Sreeni.

Reason to having this question is from this below code.

for(int i = 0; i < 5; i++) begin
  automatic int j;
  j = i;
  fork
    if(blk_en[j]) begin
      l_hw_timer0_on = 1;
      l_hw_timer4_on = 0;
      if(l_hw_timer0_on) begin
         l_hw_timer0 ++ ;
        if(l_hw_timer0==10) begin
           l_cntr0[j] = l_cntr0[j] + 1;
        end
        if(l_cntr0[j]==5) begin //some threshold value
           l_hw_timer0 = 0;
           l_hw_timer4_on = 1; 
        end
        //display statement having [j] 
      end //timer0
      //timer4 starts as show on above for some requirement 
    end
  join_none
end
``` verilog

Here timer increment is on clock based.

Needs some information whether this spawns all the values of j.

In reply to nivas:

I thought I understood what you meant by clock-based simulation until I saw your second post. I think of clock-based (sometimes also called cycle-based) simulation of SystemVerilog is an optimization of the scheduling algorithm by making assumptions about the coding style, or through simplifications/disregarding other features like #delays. Can you please explain what you mean using more descriptive words?

The point of the original example was demonstrating the fact that arguments the task ‘thread()’ won’t get passed until after for-loop has finished all its iterations. The reply in my previous post explains a way to get unique value arguments for each iteration.

It’s not clear to me what behavior you’re looking for in your last post. It would certainly help to show where the declarations of all variables in your code are located. (i.e. which are global, and which are local to the forked processes.

In reply to dave_59:

I have put comments on some of the lines

for(int i = 0; i < 5; i++) begin
  automatic int j;
  j = i;
  fork
    if(blk_en[j]) begin               ----> this is global, snooped from interface
      l_hw_timer0_on = 1;             -->timers are local which are dependent on each other
      l_hw_timer4_on = 0;
      if(l_hw_timer0_on) begin
         l_hw_timer0 ++ ;     --> this timer give interval between the events triggered
        if(l_hw_timer0==10) begin
           l_cntr0[j] = l_cntr0[j] + 1; -->local counter 
        end
        if(l_cntr0[j]==5) begin //some threshold value --> counter equals rtl value
           l_hw_timer0 = 0;
           l_hw_timer4_on = 1; 
        end
        //display statement having [j] 
      end //timer0
      //timer4 starts as show on above for some requirement 
    end
  join_none
end

This kind piece of code is sitting in state machine under a state in forever block
Please let me know your inputs.

In reply to nivas:
Bit length code to show you actual implementation.
Purpose is to check the event intervals are meeting with defined values, this is one of the state.
please let me know does this takes for all for loop values.

 fork
  forever begin
    @(posedge i_dut.sample_clk);

    STATE1: begin
     for(int l_c_num=0; l_c_num <=3; ++l_c_num) begin : for_loop
       fork
         automatic int l_n_num = l_c_num;
         begin
           if(m_b_blk0_en[l_n_num] ==1 && m_b_blk4_en[l_n_num]==1) begin 
              l_blk0_timer_on = 1;
              l_blk4_timer_on = 0;
              l_b_blk_en[l_n_num] = 1;
              l_s_blk_name[l_n_num] = $sformatf("\"block%0d\"",l_n_num);
              if(l_blk0_timer_on==1) begin
                 l_blk0_timer ++;
                 l_blk4_timer = 0;
                if(l_blk0_timer == m_n_base_tr) begin   //RTL value m_n_base_tr
                   //increment blk0_cntr on every base_timer clocks cycles
                   //blk0 and blk4 are local variable counters
                   l_n_blk0_cntr[l_n_num] = l_n_blk0_cntr[l_n_num] + 1;
                   //sum every count blk0_timer
                   l_event_interval[l_n_num] = l_event_interval[l_n_num] + l_blk0_timer;
                   //reset blk0_timer on every base_timer reach
                   l_blk0_timer = 0; 
                end  
                //condition to check cntr value equals thr value
                if(l_n_num==0) begin
                  if(l_b_blk_en[l_n_num]==1) begin
                    //RTL values   
                    if(m_b_blk0_thr[0] > m_b_blk0_thr[1] + m_b_blk0_thr[2] + m_b_blk0_thr[3])  begin
                      if(l_n_blk0_cntr[l_n_num]==m_b_blk0_thr[l_n_num]) begin
                        //blk0_cntr becomes 0 after blk0_cntr=blk0_thr 
                        l_n_blk0_cntr[l_n_num] = 0; 
                        //check RTL blk0_cntr is equals to local blk0_cntr
                        if(l_n_blk0_cntr[l_n_num]==m_b_blk0_cntr[l_n_num])
                           l_b_blk0_cntr_expired[l_n_num] = 1; 
                      end    
                    end  
                  end  
                end  
                else if(l_n_num==1) begin 
                  if(l_b_blk_en[l_n_num]==1) begin
                    if(m_b_blk0_thr[1] > m_b_blk0_thr[0] + m_b_blk0_thr[2] + m_b_blk0_thr[3])  begin
                      if(l_n_blk0_cntr[l_n_num]==m_b_blk0_thr[l_n_num]) begin
                        //blk0_cntr becomes 0 after blk0_cntr=blk0_thr 
                        l_n_blk0_cntr[l_n_num] = 0; 
                        //check RTL blk0_cntr is equals to local blk0_cntr
                        if(l_n_blk0_cntr[l_n_num]==m_b_blk0_cntr[l_n_num])
                           l_b_blk0_cntr_expired[l_n_num] = 1; 
                      end  
                    end  
                  end  
                //check for events after blk0_cntr expired
                if(l_b_blk0_cntr_expired[l_n_num]==1) begin
                  //condition to check eventtart event on rank blk0(master)  
                  if(m_event_start) begin //RTL signal snoop 
                     l_event_start[l_n_num] ++;
                     //set flag once eventtart event is issued
                     l_b_mpc_event_start_done[l_n_num] = 1;
                     //event_start min intervals check ////l_event_min_interval is a constant value
                     if(l_event_interval[l_n_num]>l_event_min_interval[l_n_num]) begin
                        ///check PASS 
                     end 
                     else begin
                        ///Check FAIL  
                     end    
                     //reset blk0_timer & enable blk4_timer_on
                     l_blk0_timer = 0;
                     l_blk4_timer_on = 1;
                     l_blk0_timer_on = 0;
                  end //event_start
                end //blk0_cntr_expired
              end //blk0_timer  
           end //blk_en
         end 
       join_none
     end : for_loop
     wait fork;
``` verilog