Task argument in task: "ref" behaves differently than "inout" in update of single bit of a vector

  • Issue is that if formal argument is inout, the update of a single bit of a vector ZERO out the other bits, instead of updating just that ONE single bit.
  • However, if formal argument is ref, the update of a single bit of a vector updates that ONE bit only, and does not zero out the other bits.
    WHY?

// with 
 bit[1:2] done; 
 task automatic c_p(int unit, inout bit go,  bit[1:2] done);
// in unit==1 and 
  done[unit]=1'b1;
// we see that done[1]=1 is updated. 
 17 @go= 1, done[1]=1, done[2]=0              <<<<<< done[1] updated by task c_p 

// In 2nd conccurrent occurence of same task c_p 
// in unit==1 and 
  done[unit]=1'b1;
// we see that done[2]=1 is updated
// BUT THE VALUE OF done[1] gets reset to 0
24 ******** in c_p           2 done[1]=0, done[2]=1  <<<<< done[2] updated in task 
#                   24 @go= 1, done[1]=0, done[2]=1  <<<< Why is done[1]==0 
                                                     <<<<< since it was updated to 1 before
#                   24 in done[2]

However, with the "ref", each bit of done is properly updated. 
task automatic c_p(int unit, ref  bit go,  bit[1:2] done);
 24 @go= 1, done[1]=1, done[2]=1                     <<<<<<<<<<<<<< OK HERE 

Code
Edit code - EDA Playground //inout
Edit code - EDA Playground // ref


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;   
    
    task automatic c_master(); 
        bit[1:2] done; 
        bit go; 
        fork
            c_p(1, go, done); // process 1
            c_p(2, go, done); 
        join_none 
        repeat (2) begin : the_repeat                    
            wait(go); 
            wait(done[1] || done[2]);
            $display("%t @go= %d, done[1]=%d, done[2]=%d", $realtime, go, done[1], done[2]);        
            // $display("%t @gdone= %d, done[1]=%d, done[2]=%d", $realtime, go, done[1], done[2]);
            if(done[1]) $display("%t in done[1]", $realtime);
            if(done[2]) $display("%t in done[2]", $realtime);
            go=0; 
        end  : the_repeat   
    endtask 
    
    task automatic c_p(int unit, inout bit go,  bit[1:2] done);
        realtime t; 
        t=unit*7ns;
        #t;
        $display("%t unit= %d", $realtime, unit); 
        go=1'b1;
        done[unit]=1'b1; 
        $display("%t ******** in c_p %d done[1]=%d, done[2]=%d", $realtime, unit, done[1], done[2]);
    endtask
    
    
    // Fork main 
    initial begin  
        #10 fork c_master(); join_none
    end
    
    initial begin 
        bit va, vb;
        repeat(200) @(posedge clk); 
        $finish; 
    end  
endmodule  

Ben SystemVerilog.us

In reply to ben@SystemVerilog.us:

Because with the inout, you have three independent copies of the variable done, all initialized to 0. The first c_p that returns updates top.done, but the other c_p will not see that update, and when it returns, the other bit still has its initial value 0.

In reply to dave_59:

but the other c_p will not see that update, and when it returns, the other bit still has its initial value 0.

But why is the update of the whole vector instead of that ONE bit.
In c_p we have done[2] only, and not done[1:2]. Shouldn’t c_p, in this return, return just that ONE bit. With the inout, you see a return of the whole vector.
So what you are saying is that with the ref the updates are immediate, and seeing buy all copies.
It’s a subtlety because you would think that pointing to 1 bit of a vector leaves the other vectors untouched.
Thanks for your response.
Ben

In reply to ben@SystemVerilog.us:

Yes, When you use ref, there is only one shared variable.