PDA

View Full Version : Analysis Fifo shows depth of 1 when using my own transactor type



laszloarato
06-20-2008, 07:31 AM
Hi

I am trying to compare two simple data-streams, one before and one after the DUT. To make it simpler, the DUT does nothing but delays each data value by 4 cycles.

Using an "int" value, everything works fine. But when I change it instead to my own transactor class "int_transact", then the analysis fifo(s) act as if it has a depth of 1, and the comparison in the scoreboard fails.

I have attached two examples, one working (with type "int") and one not working (with my class "int_transact"). As you can see with a simple diff, everything else is the same.

So what am I doing wrong ... am I missing something in my transactor class ?

Thanks a lot

Laszlo Arato

P.S.: Funny that .sv files are not accepted in a forum about SystemVerilog ...

kurts
06-20-2008, 01:04 PM
Hi Laszlo,

I see two things wrong with this example. The one thing that is causing the problem you see is that you need to clone your transactions before sending them out from your monitor. This worked for the plain int because it is not an object, and when you put it into the fifo, a copy is made.

When you work with objects, you need to think about handles, and memory allocation. When you write an object handle into a fifo, a copy of the handle is made, not the memory it is pointing to. So, the scoreboard gets the handle that is still pointing to the original object that was allocated in the monitor constructor.

As the monitor runs, it overwrites this memory when you assign into to int field, so it also overwrites the memory in the object the scoreboard sees.

In short, you only ever create one transaction object, and pass around handles to that object. What you need to do is copy the object before you send it out of the monitor.

Here is an updated monitor that should work (changes in bold):


class my_monitor extends ovm_threaded_component;

// Declare port and connections to the DUT
ovm_analysis_port #(int_transact) out_analysis_port;
virtual interf_int in_if;

int_transact int_out, int_out_2_sb;

//--------------------------------------------------------------------------

function new(string name, ovm_named_component parent);
super.new(name, parent);
out_analysis_port = new("out_analysis_port", this);
int_out = new;
endfunction : new

//--------------------------------------------------------------------------

task run();
forever @(posedge in_if.clk) begin
int_out.i = in_if.i;
$cast(int_out_2_sb, int_out.clone());
if (in_if.i > 0) out_analysis_port.write(int_out_2_sb);
end
endtask : run
endclass : my_monitor


The second thing I see is that you declare ovm_analysis_ports in your scoreboard. These should be ovm_analysis_exports. What you are doing is exporting (making available) the functionality that is supplied by internal fifos. I'm a bit surprised that the code runs without warnings, as you are doing a port-to-port connection in your environment, and it should be a port-to-export connection.

Best Regards,
-Kurt

laszloarato
06-23-2008, 06:16 AM
Hi Kurt

thank you very much for pointing out that I am not actually passing any objects to the ports and fifos, but merely handles.

One elegant way I found to avoid cloning the object is to actually create a "new" object every time I go through the monitor cycle, and then pass this object on to the port and fifo.

(This "trick" is actually from a Mentor example, but it was given without any explanations or code remarks, so the hidden meaning got lost ... ).

Again, thanks for the quick response

Laszlo

kurts
06-23-2008, 11:32 AM
Hi Laszlo,

My choice of using clone() rather than new() comes from an OOP design pattern called the "Prototype Pattern".

The Prototype Pattern is good when the cost of creating something (i.e. calling the constructor new()) is higher than the cost of copying something (i.e. calling clone()). You create just once, then stamp out copies from that point on.

In many situations, the cost of calling new() is negligent, so it really does not matter. Also, the OVM default implementation of clone actually does call the constructor form of new(), so the point is moot unless you override your own clone() function. I just do it this way out of habit.

Regards,
-Kurt