SystemVerilog: unexpected behavior while dealing with fork/join_none

Hi everyone,

In the following code, my_mbx is an unbounded mailbox that can be populated from multiple sources at the same simulation time:


virtual task mbx_monitor();

    mbx_data_object mbx_data;

    forever begin

        my_mbx.get(mbx_data);

        if (mbx_data.decrement_counter) begin
 
            fork wait_and_decrement_counter(mbx_data.id); join_none

        end // if (mbx_data.decrement_counter)

    end // forever

endtask : mbx_monitor

virtual task wait_and_decrement_counter(int id);
    
    `uvm_info(get_name(), $sformatf("Decrementing counter due to item #%0d", id), verbosity)

    #50;

    counter--;

endtask : wait_and_decrement_counter


At time X, mailbox include two objects:
- object #0: decrement_counter == 1, id == 0
- object #1: decrement_counter == 0, id == 1

My expectation is that object #0 should call the wait_and_decrement_counter task while object 1 should not, i.e. I should see the following print:

UVM_INFO  |@ X ps | uvm_test_top | Decrementing counter due to item #0

Actually I am seeing this one:

UVM_INFO  |@ X ps | uvm_test_top | Decrementing counter due to item #1

After some GUI debug, it seems that I have an issue with passing the object.id as an argument to the wait_and_decrement_counter task.

Here the thread:
- Getting item 0 from mailbox
- Since item0.decrement_counter == 1, I’m getting into the if condition, calling the forked task
- Getting item 1 from mailbox
- Since item1.decrement_counter == 0, I’m not getting into the if condition
- Getting into the wait_and_decrement_counter task, seeing item1.id as passed argument

The trivial solution will be to add a #1 delay after the task call (i.e. into the if condition), but I would prefer to not add any delay there, can someone advise ?

Thanks in advance,
Ruben

Hi,Ruben

I think the fork join none will create a thread to carry the wait_and_decrement_counter if the mbx_data.decrement_counter = 1;
but it factly will carry this wait_and_decrement_counter task after the main thread counter a function or task,so the first wait_and_decrement_counter task will carried after the second my_mbx.get(mbx_data) function, so the mbx_data will be updated , i suggest you add a `uvm_info after the “none” key word

by the way, i want to know how long can get a full access account?
i am a student.
thanks so much

In reply to rubendah:

The forked task doesn’t execute until the parent task blocks. By the time that this happens, mbx_data has changed and this is what is passed to the task. You want to use an automatic variable:


virtual task mbx_monitor();
 
    mbx_data_object mbx_data;
 
    forever begin
        my_mbx.get(mbx_data);
        if (mbx_data.decrement_counter) begin
          automatic int id = mbx_data.id;
          fork
            wait_and_decrement_counter(id);
          join_none 
        end // if (mbx_data.decrement_counter) 
    end // forever
endtask : mbx_monitor
 
virtual task wait_and_decrement_counter(int id);
    `uvm_info(get_name(), $sformatf("Decrementing counter due to item #%0d", id), verbosity)
    #50;
    counter--;
endtask : wait_and_decrement_counter

In reply to mike_wang:

Hi Mike,

I guess I got full access since I’ve registered myself with my work mail address.

In reply to cgales:

Indeed, it solved my issue, thanks !

In reply to rubendah:
thanks so much