Last Updated: May 22, 2015 (fixed a typo)
This post will explain how analysis port and analysis export work.
In Agent, we connected the analysis port (jb_ap
) of the jelly-bean monitor (jb_mon
) to the analysis port (jb_ap
) of the jelly-bean agent (jb_agent
) as follows:
jb_mon.jb_ap.connect( jb_ap ); // in the jelly_bean_agent |
Then, in Environment, we connected the analysis port (jb_ap
) of the jelly-bean agent to the analysis export (analysis_export
) of the jelly-bean-functional-coverage subscriber (jb_fc_sub
):
jb_agent.jb_ap.connect( jb_fc_sub.analysis_export ); // in the jelly_bean_env |
You might want to look at the verification component diagram in Overview to check these connections.
Finally, in the run_phase()
of the jelly-bean monitor, the monitor called the write()
function of its analysis port, every time it created a jelly-bean transaction (jb_tx
):
jb_ap.write( jb_tx ); // in the jelly_bean_monitor |
We will look at how the above code works in detail in this post. The class diagram related to the analysis port is shown below. UVM standard library classes are shown in pink, while the UVM classes specialized with the jelly_bean_transaction
type are shown in yellow.
Analysis Port
The jb_ap
of the jelly-bean monitor is an object of the uvm_analysis_port
class specialized with the jelly_bean_transaction
type. The following pseudo code shows how the class is specialized.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class uvm_analysis_port #( type T = jelly_bean_transaction ) extends uvm_port_base #( uvm_tlm_if_base #(T,T) ); function new( string name, uvm_component parent ); super.new( name, parent, UVM_PORT, 0, UVM_UNBOUNDED_CONNECTIONS ); m_if_mask = `UVM_TLM_ANALYSIS_MASK; // = 1 < < 8 endfunction // new virtual function string get_type_name(); return "uvm_analysis_port"; endfunction // get_type_name function void write( input jelly_bean_transaction t ); uvm_tlm_if_base #( jelly_bean_transaction, jelly_bean_transaction ) tif; for ( int i = 0; i < this.size(); i++ ) begin tif = this.get_if( i ); if ( tif == null ) uvm_report_fatal( "NTCONN", { "No uvm_tlm interface is connected to ", get_full_name(), " for executing write()" }, UVM_NONE ); tif.write( t ); end endfunction // write endclass // uvm_analysis_port |
As you have seen above, the write()
function of the uvm_analysis_port
delegates its job to tif
, which is an object of uvm_tlm_if_base
class. The uvm_tlm_if_base
class is the base class of uvm_port_base
class, which in turn is the base class of uvm_analysis_imp
class (line 22).
Analysis Export
The analysis_export
of the jelly-bean-functional-coverage subscriber (jb_fc_sub
) is an object of the uvm_analysis_imp
class specialized with the jelly_bean_transaction
type. The following pseudo code shows how the class is specialized.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class uvm_analysis_imp #( type T = jelly_bean_transaction, type IMP = uvm_subscriber #( jelly_bean_transaction ) ) extends uvm_port_base #( uvm_tlm_if_base #( jelly_bean_transaction, jelly_bean_transaction ) ); // `UVM_IMP_COMMON( `UVM_TLM_ANALYSIS_MASK, "uvm_analysis_imp", // | uvm_subscriber #( jelly_bean_transaction, // | jelly_bean_transaction ) ) // V local uvm_subscriber #( jelly_bean_transaction, jelly_bean_transaction ) m_imp; function new( string name, uvm_subscriber #( jelly_bean_transaction, jelly_bean_transaction ) imp ); super.new( name, imp, UVM_IMPLEMENTATION, 1, 1 ); m_imp = imp; m_if_mask = `UVM_TLM_ANALYSIS_MASK; // = 1 < < 8 endfunction // new // +--> `UVM_TLM_GET_TYPE_NAME( "uvm_analysis_imp" ) virtual function string get_type_name(); return "uvm_analysis_imp"; endfunction // get_type_name // end of macro expansion function void write( input jelly_bean_transaction t ); m_imp.write( t ); endfunction // write endclass // uvm_analysis_imp |
The write()
function of the uvm_analysis_imp
class delegates its job to m_imp
. The m_imp
is the jelly-bean-functional-coverage subscriber (jb_fc_sub
) we passed as a parameter to the uvm_analysis_imp
class. This means the write()
function of the uvm_analysis_imp
simply calls the write()
function of the jb_fc_sub
.
Connection
Now let’s put the things together. The following sequence diagram shows the steps involved in the connection.
jb_mon.jb_ap.connect( jb_ap ); // in the jelly_bean_agent |
When the connect()
function is called in the jelly_bean_agent
, the jb_ap
of the jb_mon
stores the jb_ap
of the jb_agent
in an array called m_provided_by
(step 1).
jb_agent.jb_ap.connect( jb_fc_sub.analysis_export ); // in the jelly_bean_env |
Similarly, when the connect()
function is called in the jelly_bean_env
, the jb_ap
of the jb_agent
stores the analysis_export
of the jb_fc
in its m_provided_by
array (step 2).
Just before entering the end_of_elaboration_phase()
of the jb_mon
, resolve_bindings()
function is called. This function traverses the port connection. If the port type is UVM_IMPLEMENTATION
, the port is supposed to provide “implementation”. The function stores the “implementation” to an array called m_imp_list
(steps 3 to 7).
jb_ap.write( jb_tx ); // in the jelly_bean_monitor |
The write()
function iterates over the implementations stored in the m_imp_list
array and calls the write()
function of each implementation (step 8).
That’s about the analysis port. I hope this post helped you to understand how the analysis port works.
Hi Keisuke,
It would be great if you can talk on analysis_fifo also in this tutorial.
Also basically I have an requirement to verify the signals for two interfaces in the scoreboard.
Can you please add some info this with an easy going example showing how we pump in the transaction into this fifo and how do we retrieve etc..
Thank You in Advance..!
-Surya
Please see this new post about the analysis FIFO.
Amazing..!
Thank You Keisuke ๐
It would be helpful if you can talk about TLM in a seperate post
Thank you for the request. Please see these newly created articles; TLM 1 and TLM 1 Example. I will post an article about TLM 2 later.
Hi Keisuke,
Thanks for this really great post to lead me in the UVM world.
I usually browse your post when I have some questions about UVM and I can found the answers from it.
Today I just found there is a typo in this post by chance, which I copied as follows. I think it must be the jb_ap instead of jb_ab.
Similarly, when the connect() function is called in the jelly_bean_env, the jb_ab of the jb_agent stores the analysis_export of the jb_fc in its m_provided_by array (step 2).
Best Regards,
Rui
Thank you for pointing this out. I have fixed the typo.
do you have an example of a many-to-one analysis_port? what should the connect_phase() method look like?
You should be able to connect multiple analysis ports to one analysis export like this:
Hi Keisuke,
If I put more than one analysis_export in an extended uvm_subscriber, how do I implement the related write function of each uvm_analysis_imp? I mean how to distinguish the write function of each port?
Thanks,
Rui
The
`uvm_analysis_imp_decl
macro allows you to use more than onewrite
function in theuvm_subscriber
(or in any components that implement thewrite
function). Suppose you want to add anotheruvm_analysis_imp
calledexpected_candy
to thejelly_bean_sb_subscriber
:The macro will take the macro argument (
_expected_candy
) and create a new class calleduvm_analysis_imp_expected_candy
. You also need to define thewrite_expected_candy
function in the subscriber. For example:The class relation looks like this:
The way you explain is awesome. A big thank you to you.
Hello Keisuke,
in the code line21, ” virtual function void write_expected_candy” , here can use “virtual task write_expected_candy” , is there any risk ?
thank u so much
The
write()
ofuvm_analysis_imp_expected_candy
is afunction
and calls thewrite_expected_candy()
ofjelly_bean_sb_subscriber
. It is probably okay to define thewrite_expected_candy()
as atask
as long as it has no delay or synchronization in it, but then why do you want to make it atask
in the first place?Mr.Keisuke Shimizu,
This website is really awesome !!! I really appreciate your interest and work with my full heart..!!
The concepts are like ice cake to eat….
Thank you for your comments.
Dear Keisuke Shimizu,
If I have a bigger environment (bench) owns several small environment …
class bench extends uvm_env
…
jelly_bean_env jb_env
// and create it in the build phase
…
endclass
the connect will like that…
jb_env.jb_agent.jb_ap.connect( bench_fc_sub.analysis_export ); // in the big_environment(bench)
Right?
It looks fine.
Hi,
I am a beginner.
I understand there are ports/exports, analysis ports/exports, analysis fifos, tlm ports.
Will be great if you can list out the difference between above and when to use what.
Thanks in advance!
It depends on what API (functions and tasks) you want to use. For example, if you just want to use
put()
, thenuvm_blocking_put_port
should be OK. But if you want to usetry_put()
too, then useuvm_put_port
. Please see TLM 1 for more information.HI Keisuke, Nice blog.
I have a doubt. In the last segment you mentioned argument of the connect() should be the provider.
But in env you have used agnt.ap.connect(fc_sub.analysis_export). I was under assumption here agent analysis port is the provider.
Let me know your thoughts.
Since
jb_fc_sub.analysis_export
provides thewrite
function,jb_fc_sub.analysis_export
is the provider, not the other way around.Hi Keisuke,
Thanks for the great material. I had a question regarding monitor’s analysis port connection to agent’s port.
Why can’t the connection be done this way?
jb_ap.connect(jb_mon.jb_ap)
Is it because it violates this relationship requirement of .connect method “If this port is an UVM_PORT type, the provider can be a parent port, or a sibling export or implementation port.”
OR
Because argument of .connect should be provider but here agent’s port might eventually get connected to a provider?
Thanks,
Pooja
Donโt confuse the functionality of the
connect()
by its name. It does not “connect” the two analysis ports by a wire. The purpose of the function is to specify who (eventually) provides the implementation of the function of the analysis port. Pretend the function is calledis_provided_by
. Then you would see jb_mon.jp_ap.is_provided_by( jb_ap )
makes sense, butjb_ap.is_provided_by( jb_mon.jb_ap )
doesnโt.