Search code examples
system-veriloguvm

UVM error when using multiple sequencers using for loop construct


I have a sort of following code in the body of my UVM virtual seq:

begin:
  for(int x=0; x<8; x++) begin
    
    fork begin
      automatic int x_idx = x;
        for(int i=0; i<100; i++) begin
          if(!my_sequence[x_idx].randomize() with {...}
          my_sequence[x_idx].start(p_sequencer.my_sequencer[x_idx];
        end
    end join_none
  end
end

Code information:

  1. I have 8 sequencers each receiving its own sequence. Hence the first "for loop" with 8 iterations.
  2. After going through some tutorials I understood that using fork-join I can run the 8 sequences to the 8 sequencers in parallel.

But when I run the code I get error on the "if(!my_sequence..." line of code. Error being:

The object is being used before it was constructed/allocated.

I also tested the code by getting rid of the outer for loop and instead using index numbers as follows:

    fork begin
      automatic int x_idx = x;
        for(int i=0; i<100; i++) begin
          if(!my_sequence[0].randomize() with {...}
          my_sequence[0].start(p_sequencer.my_sequencer[0];
        end
    end join_none

    fork begin
      automatic int x_idx = x;
        for(int i=0; i<100; i++) begin
          if(!my_sequence[0].randomize() with {...}
          my_sequence[1].start(p_sequencer.my_sequencer[1];
        end
    end join_none
    ...

This seems to work. But I want to write better code with for loop.

Another info: While debugging using DVE I saw the x_idx value to be 8. Not sure why it is showing as 8 and also not sure if that's the reason for the bug.


Solution

  • Your problem is you placed the x_idx declaration inside the begin/end block that is inside the fork/join_none. You don't want the initialization to happen when the parallel threads start executing; you want it to happen as each iteration of the for loop executes. You should write it as

    begin
      for(int x=0; x<8; x++)
        fork
          int x_idx = x;
          for(int i=0; i<100; i++) begin
             if(!my_sequence[x_idx].randomize() with {...}
             my_sequence[x_idx].start(p_sequencer.my_sequencer[x_idx];
          end
       join_none
    end
    

    Also, there's no need to use the automatic keyword inside a class—all variables declared inside a class method have an implicit automatic lifetime.

    Note that declarations inside fork/join's initialize upon hitting the fork block, not when the statements inside the fork begin their threads. The declarations are not separate threads. You could also write as:

    begin
      for(int x=0; x<8; x++) begin
        int x_idx = x;
        fork
          for(int i=0; i<100; i++) begin
             if(!my_sequence[x_idx].randomize() with {...}
             my_sequence[x_idx].start(p_sequencer.my_sequencer[x_idx];
          end
       join_none
      end
    end
    

    In both cases, there is a new instance of x_idx for every loop iteration, but the statements inside the fork/join_none don't begin executing until after all iterations complete.