How to get a sequence's property data in a sequence from a driver?

I’m trying to get a read data from a driver in a sequence.
In my sequence, I ran with `uvm_do_on_with a my sequence.
And I found a read_data value from driver is working well.
But I got faced the problem when I get read_data value from my sequence.

class my_seq_item extends uvm_sequence_item;
`uvm_object_utils(my_seq_item);
rand logic [31:0] my_address;
rand logic        read;
     logic [31:0] my_read_data ;
...
endclass
virtual task my_read(
	bit [31:0] read_data
	...);
	
	req = sequence_item::type_id::create("req");
	
        `uvm_do_on_with ( req, my_sequencer, {
	address == my_address;
	read 	 == 1;
	 })
	 
	 read_data = req.my_read_data; // req.my_read_data Couldn't get the data from here. Why?
        `uvm_info(get_type_name(), $sformatf("READ DATA:%h", req.my_read_data ), UVM_LOW); 

endtask

In my Driver


class my_driver extend uvm_driver #(my_sequence_item);
...
task run_phase(uvm_phase phase);
fork
  do_transfer;
join
...

task automatic do_transfer;
my_sequence_item req;

forever begin
 ...
end
 ...

req.my_read_data <= if.rdata; // Here I can check the read value well.
..
end
endclass

Could you let me know how I get req.my_read_data value from my sequence? Why is req.my_read_data value always 'hxxxxxxxx ?
How to get a sequence’s property data in a sequence from a driver ?

In reply to UVM_LOVE:

You have not shown enough code in your driver to know exactly what the problem is.

But one thing that might be wrong is you have declared req locally inside do_transfer. There is usually no need to do this as it is already declared in uvm_driver. It’s possible you are referencing two different req variables.

In reply to dave_59:

Thank you dave_59 Sir, I have updated it and I commented req(//ahb_seq_item req;) in local as your recommend But still I can’t get the value after commented it.


class my_driver extends uvm_driver #(my_seq_item);
  `uvm_component_utils(my_driver)
  
    virtual my_interface my_if;
  
  /// Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction: new
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db #(virtual my_interface)::get(this, "", "vif", my_if))
      `uvm_fatal(get_type_name(), "Virtual Interface not set in my_driver")
    
    
  endfunction

  /// Semaphore Declaration
  semaphore pipeline_lock = new(1);
  
  /// Run Phase Task
  task run_phase (uvm_phase phase);
  
  @(posedge my_if.RESETn);
  @(posedge my_if.HCLK);
  
  fork
    my_transfer;
    my_transfer;
  join
  
  endtask: run_phase
  
  /// my_transfer task
  task automatic my_transfer;
  
  //my_seq_item req; //<===It does not work.
  
  forever begin
    pipeline_lock.get();
    seq_item_port.get(req);
    accept_tr(req, $time);
    void'(begin_tr(req, "pipelined_driver"));
    my_if.HADDR <= req.HADDR;
    my_if.HWRITE <= req.HWRITE;
    my_if.HBURST <= req.HBURST;
    @(posedge my_if.HCLK);
      $display("1.HREADY:%d", my_if.HREADY);
    while(!my_if.HREADY == 1) begin
      $display("2.HREADY:%d", my_if.HREADY);
    @(posedge my_if.HCLK);
  end
  pipeline_lock.put();
  if (req.HWRITE == 0) begin
    @(posedge my_if.HCLK);
  while(my_if.HREADY != 1) begin
    @(posedge my_if.HCLK);
  end
    req.my_read_data = my_if.rdata; // I can check that req.my_read_data only here. Can't pass to sequence and test.
    req.HRESP = my_if.HRESP;
  end
  else begin
    my_if.HWDATA <= req.HWDATA;
    @(posedge my_if.HCLK);
      while(my_if.HREADY != 1) begin
    @(posedge my_if.HCLK);
    end
    req.HRESP = my_if.HRESP;
  end
  // Return the Request as Response
    seq_item_port.put(req);
    end_tr(req);
  end
  endtask: my_transfer
  
endclass: my_driver


In reply to UVM_LOVE:

You are mixing up two different driver/sequence API’s.

Your driver is using get()/put(), which requires the driver to clone the request into a response transaction as well as using get_response() in your sequence.

Your driver could also call get_next_item() instead of get(), and call item_done() insteadof put().

In reply to dave_59:

But data phase need to be locked by semaphore because the item_done() must be called after get_next_item(). But get() call can request another request item even if the put() method is not called.

and I found an answer from Alternative of `uvm_do_with macro....... | Verification Academy
Here you introduced an alternative of `uvm_do_with macro.

my_transaction tx;
task body;
    tx = my_transaction::type_id::create("tx");
    start_item(tx);
    tx.array = {8'h11, 8'h22, 8'h33, 8'h44 };
    tx.array.rand_mode(0);    // need these next 2 lines if there 
    assert( tx.randomize() ); //    are other fields to randomize
    finish_item(tx);
  end
endtask: body

So I’d like to execute a driver by

start_item(req) ~ finish(req);

in a sequence like this

 
      start_item(req);   
      req.HADDR = addr;
      req.HWDATA = data;    
      finish_item(req);  

instead of

 virtual task do_write( 
    bit [31:0] addr,     
    bit [31:0] data);    
                         
    req = my_seq_item::type_id::create("req");
                         
  `uvm_do_on_with(req, my_seqr, {
    HADDR   == addr;     
    HWDATA  == data;     
    })                   
  endtask

Problem is that there is no way to execute a sequence with sequencer in alternative way. So I have to use `uvm_do_on_with(req, my_seqr,…

Is there any other good approach?

In reply to UVM_LOVE:

You can do start_item(req, my_seqr) instead of using the `uvm_do_on_with macro.

But that is not your problem.

Your driver is using get(), which means the sequence immediately returns from either finish_item(), or `uvm_do_on_with() before the driver has made the assignment to req.my_read_data.

You still have not shown enough code to know what your sequences are doing, but that might be too much to show in this forum. Perhaps you need another thread in your sequence to call get_response().