TLM FIFO Query

For the following Code ::


class write_txn ;
 rand int unsigned b ;
endclass

class apb_gen extends uvm_component ;

  `uvm_component_utils(apb_gen)

 uvm_blocking_put_port #( write_txn ) put_port ;

 function new ( string name , uvm_component parent ) ;
      super.new(name,parent) ; // Else Error !!
   put_port = new("put_port",this);
 endfunction

 task run_phase ( uvm_phase phase ) ;
      write_txn t ;
      `uvm_info(get_name()," run_phase Started",UVM_NONE)  
	 t = new();
     
    for ( int i = 0 ; i < 4 ; i ++ ) 
	begin
          void'(t.randomize() ) ;
         `uvm_info(get_name()," Waiting for put ",UVM_NONE)  
          put_port.put(t) ;
         `uvm_info(get_name()," put done ",UVM_NONE) 
        end
 endtask
 
class apb_drv extends uvm_component ;

  `uvm_component_utils(apb_drv)

 uvm_blocking_get_port #( write_txn ) get_port ;

 function new ( string name , uvm_component parent ) ;
      super.new(name,parent) ; // Else Error !!
   get_port = new("get_port",this);
 endfunction

 task run_phase ( uvm_phase phase ) ;
      write_txn t ;
      `uvm_info(get_name()," run_phase Started",UVM_NONE) 
       phase.raise_objection(this);
         #2 ;
       for ( int i = 0 ; i < 4 ; i ++ ) 
	begin
         `uvm_info(get_name()," Waiting for get() ",UVM_NONE)  
          get_port.get(t) ;
          $display("TIME:%0t Got %0p",$time,t);
	end
       phase.drop_objection(this);
 endtask 

// In class apb_agent 
 apb_gen                   apb_genh ;
 apb_drv                   apb_drvh ;
 uvm_tlm_fifo #(write_txn) fifoh;

 function new ( string name , uvm_component parent ) ;
     super.new(name,parent) ; // Else Error !!
         fifoh = new("fifoh",this); // NOTE :: Size is Default 1 !!
      apb_genh = new("apb_genh",this); 
      apb_drvh = new("apb_drvh",this); 
 endfunction

function void connect_phase ( uvm_phase phase ) ;
   apb_genh.put_port.connect(fifoh.put_export);
   apb_drvh.get_port.connect(fifoh.get_export);
 endfunction

inital 
run_test("apb_agent") ; 

I see the Output as follows ::


UVM_INFO @ 0: reporter [RNTST] Running test apb_agent...
UVM_INFO @ 0: uvm_test_top.apb_drvh [apb_drvh]  run_phase Started
UVM_INFO @ 0: uvm_test_top.apb_genh [apb_genh]  run_phase Started // [Q1] 
UVM_INFO @ 0: uvm_test_top.apb_genh [apb_genh]  Waiting for put 
UVM_INFO @ 0: uvm_test_top.apb_genh [apb_genh]  put done 
UVM_INFO @ 0: uvm_test_top.apb_genh [apb_genh]  Waiting for put 
UVM_INFO @ 2: uvm_test_top.apb_drvh [apb_drvh]  Waiting for get() 
TIME:2 Got '{b:'h6875b355}
UVM_INFO  @ 2: uvm_test_top.apb_drvh [apb_drvh]  Waiting for get() 
TIME:2 Got '{b:'h6875b355} // [Q2]
UVM_INFO  @ 2: uvm_test_top.apb_drvh [apb_drvh]  Waiting for get() 
UVM_INFO  @ 2: uvm_test_top.apb_genh [apb_genh]  put done 
UVM_INFO  @ 2: uvm_test_top.apb_genh [apb_genh]  Waiting for put 
UVM_INFO  @ 2: uvm_test_top.apb_genh [apb_genh]  put done 
UVM_INFO  @ 2: uvm_test_top.apb_genh [apb_genh]  Waiting for put 
UVM_INFO  @ 2: uvm_test_top.apb_genh [apb_genh]  put done 
TIME:2 Got '{b:'h64617ef6} // [Q3]
UVM_INFO  @ 2: uvm_test_top.apb_drvh [apb_drvh]  Waiting for get() 
TIME:2 Got '{b:'h64617ef6}

I expect all get() Output to be different but I don’t observe the same .
My Questions are as follows ::

[Q1] I understand that " run_phase of apb_drvh " is displayed before apb_genh but why does " Waiting for put " && " put done " get displayed after " [apb_genh] run_phase Started "
( i.e run_phase Starts for apb_genh ) since nothing blocks in apb_drvh till that point ??

[Q2] Why do both 2nd get() give Same output as 1st get ?? .

 Sequence of execution should be as follows :: 
 First put() is done then 2nd put() blocks . get() Unblocks for i == 0 ( Should give what we put() ) then blocks again ( for i == 1 ) .
 put() unblocks ( for i == 1 ) followed by put() again blocking ( for i == 2 ) . 
 get() Unblocks for i == 1 ( Should give what we put() 2nd time ) and then again blocks ( for i == 2 ) .  

[Q3] Why is 3rd get() different than 2nd ??

In reply to ABD_91:

[Q1] I understand that " run_phase of apb_drvh " is displayed before apb_genh but why does " Waiting for put " && " put done " get displayed after " [apb_genh] run_phase Started "
( i.e run_phase Starts for apb_genh ) since nothing blocks in apb_drvh till that point ??

Execution of the Run phase of all components happen in parallel. so “run_phase of apb_drvh” and “run_phase of apb_genh” can happen any order as both execute at same time.

Execution of the run phase code happen in the sequence. “run_phase Started” statement is prior to the " Waiting for put " && " put done ". so it first display “run_phase Started” statement.

[Q2] Why do both 2nd get() give Same output as 1st get ?? .

→ you have created only one handle of write_txn, on each randomization call it is modifying and after that it put on the fifo.

  1. put → X
  2. get ← X / put → Y
  3. display of get/put (Value Y is overriding the value X before it is displayed, so put/get display Y)

Create separate handle for each put transaction



    for ( int i = 0 ; i < 4 ; i ++ ) 
	begin
	 t = new();  //moved inside the transaction creation loop
          void'(t.randomize() ) ;
         `uvm_info(get_name()," Waiting for put ",UVM_NONE)  
          put_port.put(t) ;
         `uvm_info(get_name()," put done ",UVM_NONE) 
        end

[Q3] Why is 3rd get() different than 2nd ??
→ Look like there is race condition between put and display of get.

In reply to Rahulkumar:

I get your point but the ( Mailbox ) issue arises when we have all puts done without blocking and then the get() starts . Here we don’t have that

Since Mailbox guarantees atomic FIFO ordering and we never have 2 successive put() or get() I don’t think we should have the issue .

For i == 0 get will always be successful before 2nd put() is done . 2nd put() returns only after get() blocks for i == 1 .

So essentially first get() can never be same as 2nd put() .