PDA

View Full Version : questions around hierarchy example



sharan_basappa
05-16-2008, 08:44 AM
The avm cookbook mentions that a port cannot be connected to port. So is the case with export to export. The examples provided shows a port connected to port and export connected to export, as follows:

function new(string name, ovm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
g = new("gen", this);
c = new("conv", this);
f = new("fifo", this);
g.put_port.connect(f.blocking_put_export); // A
c.get_port.connect(f.blocking_get_export); // B
c.put_port.connect(put_port); // C
endfunction


function new(string name, ovm_component parent);
super.new(name, parent);
put_export = new("put_export", this);
f = new("fifo", this);
b = new("bfm", this);
put_export.connect(f.blocking_put_export); // E
b.get_port.connect(f.blocking_get_export); // F
endfunction

Am I missing something?

Regards

tfitz
05-16-2008, 09:00 AM
Port-to-port and Export-to-export connections are used to pass port/export references through the hierarchy. On p. 88 of The Verification Cookbook (3rd edition), you'll see this table that explains it all.

Port-to-export connections look like:


comp1.port.connect(comp2.export);

Port-to-port connections look like:


subcomponent.port.connect(port);

Export-to-export connections look like:


export.connect(subcomponent.export);


In AVM and OVM, the connections are automatically handled hierarchically, so we always start with the export (which contains the implementation) and then pass the up (through parent exports), over (to sibling ports) and down (to child ports) to the appropriate port.

Hope this helps,
-Tom

sharan_basappa
05-19-2008, 05:55 AM
Thanks, Tom. This helps.

When I was learning Systemc, I found the concept of port/interface/channel pretty intuitive. An interface is a method; port is a class; channel is the media that generally had containers and actual interface methods implemented. A call to interface (using port) eventually resolve to call in channel. Is there a similar analogy in AVM? Is there a simpler document that de-mystifies the concept of port, interface and channel.

Regards

sharan_basappa
05-19-2008, 07:46 AM
Having gone through the hierarchy example, I have few questions that remain unanswered. Can someone have a look.

1) I am a bit confused as to when to use a port and when to use an export.
For example, the transmit port of producer has a port. The receive of consumer has an export. Can the receive of consumer have a port since a export can very well connect to a port?
I tried this and ended up with runtime (?) errors.

2) Are the channels shown in this example mandatory?
For example, can one of the channel (say in produecer) can be done away with?

Regards

dave_59
05-19-2008, 09:02 AM
Yes, the AVM cookbook describes the same TLM concepts that are in the OVM. The only real difference is that the OVM has more flexible binding rules in that you can connect a "blocking" port to an export that provides both a "blocking" and "nonblocking" interface. In the AVM, a blocking port had to be connected to a blocking export.

Dave

sharan_basappa
05-20-2008, 04:45 AM
From AVM cookbook, page 81:
"get_port is a port, and as such, it initiates transfers. The type of
the interface is tlm_blocking_get_port"

To me, it looks like tlm_blocking_get_port should be tlm_blocking_get_if.

Regards

jsleroy
05-20-2008, 05:54 AM
Hello,

About your first question, I think that your runtime error is normal.

Look at the AVM cookbook, section 5.21 "Ports and Exports" (page 98) :


The elements of a transaction‐level connection are a port, which is the requires side of the connection; an export, which is the provides side of the connection; and a means to associate the two. Ports and exports are objects that are instantiated inside a component. The connect() method on the port allows it to be connected to a compatible export.

Also take a look at the figure 5-1.

sharan_basappa
05-20-2008, 08:48 AM
I have modified the hierarchy example. The only change is that put_export in consumer is modified to put_port and changes required due to this.
When I run this example, I get error that I am trying to connect ports of different type, as follows:
OVM_ERROR @ 0: e.top.consumer.put_port [connect] cannot connect provider of tlm_blocking_put interface to a requirer of tlm_blocking_get interface
OVM_ERROR @ 0: e.top.producer.put_port [connect] cannot connect provider of tlm_blocking_get interface to a requirer of tlm_blocking_put interface

Below is the complete code. Any clue where I am going wrong?


package user_pkg;

import ovm_pkg::*;
`include "ovm_templates.svh"

//----------------------------------------------------------------------
// CLASS transaction
//----------------------------------------------------------------------
class transaction extends ovm_transaction;

rand int data;
rand int addr;

function void copy( input transaction t );
data = t.data;
addr = t.addr;
endfunction

function bit comp( input transaction a , input transaction b );
return ((a.data == b.data) && (a.addr == b.addr));
endfunction

function ovm_object clone();
transaction t; t = new();
t.copy(this);
return t;
endfunction

function string convert2string();
string s;
$sformat(s, "[ addr = %x, data = %x ]", addr, data);
return s;
endfunction

endclass

//----------------------------------------------------------------------
// COMPONENT gen
//----------------------------------------------------------------------
class gen extends ovm_threaded_component;

ovm_blocking_put_port #(transaction) put_port;

function new(string name, ovm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
endfunction

task run;
transaction t;
string msg;

for(int i=0; i < 20; i++) begin
t = new();
assert(t.randomize());
$sformat(msg, "sending : %s", t.convert2string());
ovm_report_info("gen", msg);
put_port.put(t);
end
endtask

endclass

//----------------------------------------------------------------------
// COMPONENT conv
//----------------------------------------------------------------------
class conv extends ovm_threaded_component;

ovm_blocking_put_port #(transaction) put_port;
ovm_blocking_get_port #(transaction) get_port;

function new(string name, ovm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
get_port = new("get_port", this);
endfunction

task run;
transaction t;

forever begin
get_port.get(t);
put_port.put(t);
end
endtask

endclass

//----------------------------------------------------------------------
// COMPONENT bfm
//----------------------------------------------------------------------
class bfm extends ovm_threaded_component;

ovm_blocking_get_port #(transaction) get_port;

function new(string name, ovm_component parent);
super.new(name, parent);
get_port = new("get_port", this);
endfunction

task run;
transaction t;
string msg;

forever begin
get_port.get(t);
$sformat(msg, "receiving: %s", t.convert2string());
ovm_report_info("bfm", msg);
end
endtask

endclass

//----------------------------------------------------------------------
// COMPONENT producer
//----------------------------------------------------------------------
// begin codeblock producer
class producer extends ovm_component;

ovm_blocking_put_port #(transaction) put_port;

gen g;
conv c;
tlm_fifo #(transaction) f;

function new(string name, ovm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
g = new("gen", this);
c = new("conv", this);
f = new("fifo", this);
g.put_port.connect(f.blocking_put_export); // A
c.get_port.connect(f.blocking_get_export); // B
c.put_port.connect(put_port); // C
endfunction

endclass
// end codeblock producer

//----------------------------------------------------------------------
// COMPONENT consumer
//----------------------------------------------------------------------
// begin codeblock consumer
class consumer extends ovm_component;

ovm_blocking_get_port #(transaction) put_port;

bfm b;
tlm_fifo #(transaction) f;

function new(string name, ovm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
f = new("fifo", this);
b = new("bfm", this);
put_port.connect(f.blocking_put_export); // E
b.get_port.connect(f.blocking_get_export); // F
endfunction

endclass
// end codeblock consumer

//----------------------------------------------------------------------
// COMPONENT top
//----------------------------------------------------------------------
// begin codeblock top
class top extends ovm_component;

producer p;
consumer c;

function new(string name, ovm_component parent);
super.new(name, parent);
p = new("producer", this);
c = new("consumer", this);
p.put_port.connect(c.put_port); // D
endfunction

endclass
// end codeblock top


//----------------------------------------------------------------------
// ENVIRONMENT env
//----------------------------------------------------------------------
// begin codeblock env
class env extends ovm_env;
top t;

function new(string name = "env");
super.new(name);
t = new("top", this);
endfunction

task run;
#1000;
endtask

endclass
// end codeblock env

endpackage


//----------------------------------------------------------------------
// MODULE top
//----------------------------------------------------------------------
// begin codeblock topmod
module top;

import user_pkg::*;
env e;

initial begin
e = new("e");
e.do_test();
end

endmodule

kurts
05-20-2008, 12:46 PM
The problem is with your consumer port. It needs to be an export.

Change the port on the consumer to this:

ovm_blocking_put_export #(transaction) put_port;

and it will work. Note that you should probably also change the name of the object to something like "put_xp" to avoid confusion.

This needs to be an export because you are effectively "exporting", or "providing" the functionality of your consumer's fifo to external components. Namely, you are providing the fifo's functionality to the conv component inside the producer.

Your conv component code requires the put functionality. It passes this requirement up through the producer via the producer's port. Your consumer provides the functionality with its fifo, so it must export that provided functionality via an export.

-Kurt

sharan_basappa
05-21-2008, 05:28 AM
The problem is with your consumer port. It needs to be an export.

Change the port on the consumer to this:

ovm_blocking_put_export #(transaction) put_port;

and it will work. Note that you should probably also change the name of the object to something like "put_xp" to avoid confusion.

This needs to be an export because you are effectively "exporting", or "providing" the functionality of your consumer's fifo to external components. Namely, you are providing the fifo's functionality to the conv component inside the producer.

Your conv component code requires the put functionality. It passes this requirement up through the producer via the producer's port. Your consumer provides the functionality with its fifo, so it must export that provided functionality via an export.

-Kurt

Thanks, Kurt. The original example was exactly the way you described. I modified it with an intention to convert *export to *port.

I had closer look at the code and I find that there was a typo in the consumer code block. I corrected that and the new errors look more logical. These are the errors I see now:

OVM_ERROR @ 0: e.top.consumer.put_port [Connection Error] connect ( port -> export ) : e.top.consumer should be a sibling of e.top.consumer.fifo
OVM_ERROR @ 0: e.top.consumer.put_port [Connection Error] Cannot connect e.top.consumer.put_port to e.top.consumer.fifo.blocking_put_export
OVM_ERROR @ 0: e.top.producer.put_port [Connection Error] connect ( child port -> port ) : e.top.producer should be a child of e.top.consumer
OVM_ERROR @ 0: e.top.producer.put_port [Connection Error] Cannot connect e.top.producer.put_port to e.top.consumer.put_port