How to compare the data between two uvm_tlm_analysis_fifo in scoreboard?

As I coded the scoreboard as follows :

class scoreboard extends uvm_scoreboard;
 `uvm_component_utils(scoreboard)
 int no_of_compared_txns;
 read_txn sb_rd_txn;
 write_txn sb_wr_txn;
 bit [7:0]ram_model[int];
 uvm_analysis_export #(read_txn)item_collected_export_rd_txn;
 uvm_analysis_export #(write_txn)item_collected_export_wr_txn;
 uvm_tlm_analysis_fifo #(read_txn)rd_fifo;
 uvm_tlm_analysis_fifo #(write_txn)wr_fifo;
 
 //new constructor
 function new (string name, uvm_component parent);
    super.new(name, parent);
	sb_rd_txn=read_txn::type_id::create("sb_rd_txn");
	sb_wr_txn=write_txn::type_id::create("sb_wr_txn");
  endfunction : new
  
  //Building
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    item_collected_export_rd_txn= new("item_collected_export_rd_txn", this);
	item_collected_export_wr_txn= new("item_collected_export_wr_txn", this);
	rd_fifo=new("rd_fifo",this);
	wr_fifo=new("wr_fifo",this);
  endfunction: build_phase
  
  //connect phase 
  function void connect_phase(uvm_phase phase);
     item_collected_export_rd_txn.connect(rd_fifo.analysis_export);
	 item_collected_export_wr_txn.connect(wr_fifo.analysis_export);
   endfunction
  
 task run_phase(uvm_phase phase);
	       forever begin
		       wr_fifo.get(sb_wr_txn);
			   write();
			   rd_fifo.get(sb_rd_txn);
			   compare();
			 end			 
	 endtask
	 
  virtual function void write();
       //if((!sb_wr_txn.csn_0)||(!sb_wr_txn.csn_1)) begin
	   fork
		   if(sb_wr_txn.wen_0)
			   ram_model[sb_wr_txn.addr_0]=sb_wr_txn.datain_0;
		   if(sb_wr_txn.wen_1)
			   ram_model[sb_wr_txn.addr_1]=sb_wr_txn.datain_1;
		join
		//end
	endfunction
	 
  virtual function void compare(); 
              if(sb_rd_txn.ren_0) begin
			   if(ram_model.exists(sb_rd_txn.addr_0))begin
				    if((ram_model [sb_rd_txn.addr_0]==sb_rd_txn.dataout_0)||(ram_model [sb_rd_txn.addr_0]==sb_rd_txn.dataout_1)) begin
					`uvm_info("compare", {"Test: OK!"}, UVM_LOW);
					$display("\n In port_0 & detection correct");
					$display("scoreboard:: addr_0=%0d dataout_0=%0d datain_0=%0d \n",sb_rd_txn.addr_0,sb_rd_txn.dataout_0,ram_model[sb_rd_txn.addr_0]);
					no_of_compared_txns++;
				end
				else begin
				   `uvm_info("compare", {"Test: Fail!"}, UVM_LOW);
				    $display("\n scoreboard:: addr_0=%d,actual data=%d,expected data=%0d",sb_rd_txn.addr_0,sb_rd_txn.dataout_0,ram_model[sb_rd_txn.addr_0]);
					$error(" Data Mismatch\n");
				 end
			    end
		    end
		  if(sb_rd_txn.ren_1) begin
				if(ram_model.exists(sb_rd_txn.addr_1))begin
					  if((ram_model [sb_rd_txn.addr_1]==sb_rd_txn.dataout_1)||(ram_model [sb_rd_txn.addr_1]==sb_rd_txn.dataout_0)) begin
					    `uvm_info("compare", {"Test: OK!"}, UVM_LOW);
					     $display("\n In port_1 & detection correct");
					     $display("scoreboard:: addr_1=%d dataout_1=%d expected data=%0d\n",sb_rd_txn.addr_1,sb_rd_txn.dataout_1,ram_model[sb_rd_txn.addr_1]);
						 no_of_compared_txns++;
				end
				else begin
				   `uvm_info("compare", {"Test: Fail!"}, UVM_LOW);
					$display("\n scoreboard:: addr_1=%d,actual data=%d,expected data=%0d",sb_rd_txn.addr_1,sb_rd_txn.dataout_1,ram_model[sb_rd_txn.addr_1]);
					$error(" Data Mismatch\n");
					end
				end
			end  
	  endfunction

 endclass

But after simulation I find only four data checks have completed. Is my ran_phase task is wrong or I need to change my compare logic. It is the scoreboard of a dual port ram.

In reply to Subhra Bera:

Because you did not Show how many Transactions were processed it is hard to give a good advice.
Did you check you have different addresses addr_0 and addr_1?

In reply to chr_sue:

there are 10 transaction in write _sequence _item:


class ram_write_10_addr_seq extends write_base_sequence;
`uvm_object_utils(ram_write_10_addr_seq)

 function new(string name="ram_write_10_addr_seq");
      super.new(name);
  endfunction
  
 task body();
    for(int i=0;i<10;i++) begin
	    req=write_txn::type_id::create("req");
		
		start_item(req);
		  assert(req.randomize()with{addr_0==i[7:0]; addr_1 == i[7:0]+10;csn_0==0;csn_1==0;wen_0==1;wen_1==1;})
		finish_item(req);
	 end
  endtask

endclass

there are 10 read transaction in read_sequence_item:

class ram_read_10_addr_seq extends read_base_sequence;
`uvm_object_utils(ram_read_10_addr_seq)

 function new(string name="ram_read_10_addr_seq");
     super.new(name);
  endfunction
  
 task body();
    for(int i=0;i<10;i++) begin
	    req=read_txn::type_id::create("req");
		
		start_item(req);
		  assert(req.randomize()with{addr_1==i[7:0]; addr_0 == i[7:0]+10;csn_0==0;csn_1==0;ren_0==1;ren_1==1;})
		finish_item(req);
	 end
  endtask

endclass

In reply to Subhra Bera:
You should display your addresses and data.
Then you see how many data were generated.
BTW, in UVM never, never, never use $display!

In reply to chr_sue:

Sir, I have displayed all the elements that are sampled at write _monitor and read_monitor and there are no problem. From write_monitor and read_monitor I have sent those data by write() method to scoreboard through analysis port. In the scoreboard I use two uvm_tlm_analyis_fifo to store the data which come from two monitors as shown in my scoreboard which I posted at the top of this conversation. But the problem is :
task run_phase(uvm_phase phase);
forever begin
wr_fifo.get(sb_wr_txn);
$display(“req=%p”,sb_wr_txn);
write();
rd_fifo.get(sb_rd_txn);
compare();
end
endtask


  when I use display  method as shown in the above code it displays only 4 address and related data input. where are other elements? I am confused. 
                   Sir, I am a starter in verification field and I am still learning.So please help me. And if you want to check my code then I can send the whole code to you.

In reply to Subhra Bera:

Please visit my webpage: www.christoph-suehnel.de
or use my email christoph@christoph-suehnel.de to send some code.

In reply to Subhra Bera:

Hi Subhra,

  virtual function void write();
       //if((!sb_wr_txn.csn_0)||(!sb_wr_txn.csn_1)) begin
	   fork
		   if(sb_wr_txn.wen_0)
			   ram_model[sb_wr_txn.addr_0]=sb_wr_txn.datain_0;
		   if(sb_wr_txn.wen_1)
			   ram_model[sb_wr_txn.addr_1]=sb_wr_txn.datain_1;
		join
		//end
	endfunction

I believe you want a join_any, not join. Your fork started 2 processes, and they both must complete before the fork will exit. The only transactions that will complete this fork MUST have wen_0 and wen_1 both logic high.

task run_phase(uvm_phase phase);
  forever begin
    wr_fifo.get(sb_wr_txn);
    write();
    rd_fifo.get(sb_rd_txn);
    compare();
  end			 
endtask

This component you described is a “dual port RAM model, with a scoreboard”. However, your run_phase looks like code for a dual-port fifo scoreboard. The writing of the RAM should be independent of the reading/comparing. i.e. They should not be in the same thread.

This might be a lot to digest if you are just beginning, but I recommend also using a single transaction type. address, data, either an enum {RAM_WRITE, RAM_READ) or a logic rd_nwr signal. I’d removed the “dual port” information out of the transaction, and use the 2 “imp” ports to represent the two ports of your RAM This will greatly shrink the size of your code, which is too complicated currently. I can help more if you are interested.

result will look something like:

  // Macros to create the uvm_analysis_imp ports (just an export + write function)
  `uvm_analysis_imp_decl(_port0) 
  `uvm_analysis_imp_decl(_port1)

   // The macros above created these ports
   uvm_analysis_imp_exp #(ram_txn,scoreboard) port0_imp;
   uvm_analysis_imp_act #(ram_txn,scoreboard) port1_imp;

  virtual function void write_port0(ram_txn t, 0);
    if (t.rd_nwr) check_ram(t);             // READ & VERIFY       
    else          ram_model[t.addr]=t.data; // WRITE
  endfunction

  virtual function void write_port1(ram_txn t, 1);
    if (t.rd_nwr) check_ram(t);             // READ & VERIFY       
    else          ram_model[t.addr]=t.data; // WRITE
  endfunction

  function void check_ram(ram_txn t, int port_num);
    if(ram_model[t.addr]==t.data) begin
      `uvm_info("compare", {"Test: OK!"}, UVM_HIGH);
    end else begin 
      `uvm_error(get_type_name(), $sformatf("miscompare on port %0d, addr=", port_num, t.addr))
      `uvm_info(get_type_name(), $sformatf("ACT data=0x%0h",t.data), UVM_MEDIUM)
      `uvm_info(get_type_name(), $sformatf("EXP data=0x%0h",ram_model[t.addr]), UVM_MEDIUM)
    end
  endfunction

That leaves your run_phase empty, so just delete it for now.

You can build on to this model, if your RAM has write access semaphores etc.

I’m assuming you don’t need an associative array for your RAM either… I’d just use a typically array if you know the size.
bit [31:0] RAM[512]; // e.g.

In reply to Subhra Bera:

That might take awhile.
Why don’t you revise your component and then we can analyze the result.

In reply to Subhra Bera:
I would extend the scoreboard from uvm_subscriber and instantiate in this class a uvm_tlm_analysis_fifo.
The Analysis fifo gets ist data from the write side and the Analysis_export of the uvm_subscriber is used to consider the read data. If the first rd_data is available the first wr data from the Analysis fifo will be retrieved.

In reply to chr_sue:
Sir,after removing dependency of the write task from compare task the scoreboard works correctly.

task run_phase(uvm_phase phase);
   fork
	       forever begin
		        wr_fifo.get(sb_wr_txn);
			   `uvm_info(get_type_name(), {"sb_wr_txn ", sb_wr_txn.convert2string}, UVM_MEDIUM)
			    write();
				end
				forever begin
			    rd_fifo.get(sb_rd_txn);
				read_txn_count++;
				$display("read_txn_count=%d",read_txn_count);
				`uvm_info(get_type_name(), {"sb_rd_txn ", sb_rd_txn.convert2string}, UVM_MEDIUM)
			    compare();
			 end	
   join