Shifting with non-blocking assignment in the task

Hi all! I have a task in the SV interface that simply shifts input data, here is the code:

   task write(logic [0:9] data_tx);
      
      $display("DATA_TX_CALL: 0b%10b" , data_tx);
            
      repeat(10) begin
	 @(cb);
	 $display("DATA_TX: 0b%10b" , data_tx);
	 cb.txp		<=  data_tx[0];
	 cb.txn		<= ~data_tx[0];
	 data_tx = { data_tx[1:9] , 1'b0}; // Doesn't work with NBA	 
      end
      
   endtask // write

The code works when I use the blocking assignment in data_tx shifting, but I have a problem when NBA is used. Here is the log from task execution with NBA:

DATA_TX_CALL: 0b0101011000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

As I understand the code is legal and data_tx should be updated in NBA region each time @(cb) event occurs. Have no clue why data_tx always equals to zero.
Why this shift is corrupted? Could someone please explain?

In reply to egorman44:

You need to show this code with more context. Is this task a method of a class? If that’s true, then data_tx is an automatic variable. You should’ve gotten a compiler error trying to make an NBA to an automatic variable.

In reply to dave_59:

Hi Dave, thank you for response. The function is inside SV interface:

interface eth_if(input logic clk);
...
   task write(logic [0:9] data_tx);
      
      $display("DATA_TX_CALL: 0b%10b" , data_tx);

      repeat(10) begin
      	 @(cb);
      	 $display("DATA_TX: 0b%10b" , data_tx);
      	 cb.txp		<=  data_tx[0];
      	 cb.txn		<= ~data_tx[0];
      	 data_tx <= { data_tx[1:9] , 1'b0};
      end
      
   endtask // write
   ...
endinterface


I read a file with stimulus line by line and call write() task inside SVUNIT test.

module eth_monitor_unit_test;
...
     `SVTEST(check_comma)
       
       string line;

   int 	      stim_file_h;
   string     file_name = {stimulus_dir , "/ten_bits_0.txt"};  
   logic [0:9] line_bin;
   
   
   stim_file_h = open_file(file_name);
   
   while(!$feof(stim_file_h)) begin
      $fgets(line,stim_file_h);
      line_bin = line.atobin();  
      $display("\nLINE_SENT: 0b%10b" , line_bin);      
      eth_if_mst.write(line_bin);
   end	 
   
   `SVTEST_END
...
endmodule

In reply to egorman44:
The following complete example works for me

interface eth_if(input logic clk);
  bit txp,txn;
  clocking cb @(posedge clk);
    output txp,txn;
  endclocking
    
  task write(logic [0:9] data_tx);
    $display("DATA_TX_CALL: 0b%10b" , data_tx);
    repeat(10) begin
      	 @(cb);
      	 $display("DATA_TX: 0b%10b" , data_tx);
      	 cb.txp		<=  data_tx[0];      // These are clocking block drives
      	 cb.txn		<= ~data_tx[0];      //
      	 data_tx <= { data_tx[1:9] , 1'b0;   // no need for NBA here
    end
   endtask : write
endinterface
module top;
  bit clk;
  initial repeat (100) #10 clk++;
  eth_if eth_mst(clk);
  initial eth_mst.write('b10110101);
endmodule

BTW, there’s no reason to use an NBA with the code you have shown.

In reply to dave_59:

Hi Dave.
NBA intend was to make sure that shifting occurs in NBA region and the first draft of the code had a shifting before clocking block drivesrepeat statement:

repeat(10) begin
      	 @(cb);
      	 $display("DATA_TX: 0b%10b" , data_tx);
      	 data_tx <= { data_tx[1:9] , 1'b0};
      	 cb.txp		<=  data_tx[0];
      	 cb.txn		<= ~data_tx[0]; 
end

And when it didn’t work I tried to fix it somehow. So I don’t think that I did any criminal here, I meant NBA usage. Please, correct me if I’m wrong.
I tried your code and it works fine with a single write(), but it failed when I tried more than one write() task. Here is the code and the log:

interface eth_if(input logic clk);
  bit txp,txn;
  clocking cb @(posedge clk);
    output txp,txn;
  endclocking
 
  task write(logic [0:9] data_tx);
    $display("DATA_TX_CALL: 0b%10b" , data_tx);
    repeat(10) begin
      	 @(cb);
      	 $display("DATA_TX: 0b%10b" , data_tx);
      	 cb.txp		<=  data_tx[0];
      	 cb.txn		<= ~data_tx[0];
      	 data_tx <= { data_tx[1:9] , 1'b0};	 
    end
   endtask : write
endinterface // eth_if

module nba_check;
  bit clk;
  initial repeat (100) #10 clk++;
  eth_if eth_mst(clk);
  initial begin
    eth_mst.write('b10110101);
    eth_mst.write('b10110101);
    eth_mst.write('b10110101);
  end
endmodule

DATA_TX_CALL: 0b0010110101

DATA_TX: 0b0010110101

DATA_TX: 0b0101101010

DATA_TX: 0b1011010100

DATA_TX: 0b0110101000

DATA_TX: 0b1101010000

DATA_TX: 0b1010100000

DATA_TX: 0b0101000000

DATA_TX: 0b1010000000

DATA_TX: 0b0100000000

DATA_TX: 0b1000000000

DATA_TX_CALL: 0b0010110101

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX_CALL: 0b0010110101

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

DATA_TX: 0b0000000000

In reply to egorman44:

Your problem is data_tx is a static variable and you have a pending NBA assignment scheduled to it when you exit and immediately re-enter the task write(). The argument value that was copied in gets overwritten by the NBA.

In reply to dave_59:

Thank you so much, Dave! I got it.