Queue content corrupted

Hi,
I have an issue with a piece of code that I am reusing:
In scoreboard, after finishing the comparison of current object, there is a function free_memory called to delete all dynamic fields of the expected and received objects.


packet_obj packet_queue_owr[$];  // define a queue
ovm_analysis_imp_sent_obj_pkt #(packet_obj, scoreboard) driver_obj2sb_port;   //declare a scoreboard port for driver obj
ovm_analysis_imp_rcvd_pkt #(packet_obj, scoreboard) receiver_obj2sb_port; //declare a scoreboard port for receiver obj
extern function new(string name, ovm_component parent);
extern function void write_sent_obj_pkt(input packet_obj pkt ); //This function is used to put sent packet in Queue
extern function void write_rcvd_pkt(input packet_obj pkt);  //This function is used to compare received and sent packets
extern function void free_obj_memory(packet_obj pkt_obj_source, packet_obj pkt_obj_received);
//...
function void scoreboard::free_obj_memory(packet_obj pkt_obj_source, packet_obj pkt_obj_received);
   pkt_obj_source.free_memory();
   pkt_obj_received.free_memory();
endfunction : free_obj_memory 

function void scoreboard::write_sent_obj_pkt(input packet_obj pkt );
    packet_queue_owr.push_back(pkt);
endfunction : write_sent_obj_pkt

function void scoreboard::write_rcvd_pkt(input packet_obj pkt);
    packet_obj expected_obj;
    expected_obj = packet_queue_owr.pop_front();
//comparison
free_obj_memory(expected_obj, pkt);

and inside transaction_obj class, free_memory is defined as:


function void packet_obj::free_memory();
    this.dynamic_field1.delete();
    this.dynamic_field2.delete();
    //...
    this.dynamic_fieldN.delete();  
endfunction : free_memory

I am testing a case where one input object is sent to the design but is written twice in the scoreboard (Queue packet_queue_owr).
These two objects are then sent by the design as two seperate objects.
While the reception of the first one is ok, the comparison of the second object fails.
The problem is that expected object is corrupted: all its dynamic fields are empty (size = 0).

I did a print of packet_queue_owr[0] before and after free_obj_memory 's call and I found that the source of the problem is here.
Why the content of the Queue packet_queue_owr is modified after calling the function free_obj_memory ?

Thank you.

In reply to imed_mabrouk:

My guess is that you are sending the same handle to two different locations instead of cloning the object into two separate objects. Since you are using the same handle in two separate locations, deleting the data in one object is reflected in the second location.

Of course, any additional code which shows the two objects being sent would help further isolate your issue.

In reply to cgales:

Thanks cgales for your reply.
Here is how these packets are written from the driver into the queue packet_queue_owr through the analysis port

// connection with scoreboard to send driven packets
    ovm_analysis_port #(packet_obj) driver_obj2sb_port;
//...
task driver_obj::run();
    //drive packet
    //...
    //write packet twice
    repeat(2) driver_obj2sb_port.write(pkt_obj);
    //...
    // go to the next packet   
    seq_item_port.item_done();
endtask : run

Based on what you said (about using the same handle in different locations) and what I found on the forum, I added the following function write_obj to create, copy and write packets into the analysis port:

//============Function Write to scoreboard================//
function void driver_obj::write_obj(packet_obj pkt_orig);
     packet_obj pkt_new;                       //...Object declared 
     pkt_new=new();                            //...New Object created 
     pkt_new.copy(pkt_orig);                   //....Copied object
     driver_obj2sb_port.write(pkt_new);        //Object written
endfunction : write_obj

task driver_obj::run();
    //
    repeat(2) write_obj(pkt_obj);
endtask : run

This solved my problem.
What do you think? Is this a good practice to use all the time? even if I have to write the packet only once ?

In reply to imed_mabrouk:

You should have a clone() function built into every object. This is a standard OVM function and makes it easier to use. Refer to the Verification Academy for reference on how to write this function.

I will always clone() an object prior to sending it to any other component. This will ensure that anything done by the receiving component doesn’t affect my local copy.