This is write-up about the internals of UVM 1800.2 analysis_port rabbit hole.
Starting with uvm_analysis_port.svh
, where the doc has small snippet of uvm_analysis_port object.
//------------------------------------------------------------------------------
// Class -- NODOCS -- uvm_analysis_port
//
// Broadcasts a value to all subscribers implementing a <uvm_analysis_imp>.
//
//| class mon extends uvm_component;
//| uvm_analysis_port#(trans) ap;
//|
//| function new(string name = "sb", uvm_component parent = null);
//| super.new(name, parent);
//| ap = new("ap", this);
//| endfunction
//|
//| task run_phase(uvm_phase phase);
//| trans t;
//| ...
//| ap.write(t);
//| ...
//| endfunction
//| endclass
uvm_analysis_port
is defined as
// @uvm-ieee 1800.2-2020 auto 12.2.10.1.1
class uvm_analysis_port # (type T = int)
extends uvm_port_base # (uvm_tlm_if_base #(T,T));
and write
calls tif.write()
and tif
is returned from get_if
.
// @uvm-ieee 1800.2-2020 auto 12.2.10.1.4
function void write (input T t);
uvm_tlm_if_base # (T, T) 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
uvm_tlm_if_base Link to heading
Let’s get uvm_tlm_if_base
out of the way first, In uvm_tlm_ifs.svh
, uvm_tlm_if_base
is abstract class with port methods:
- get
- put
- ..etc
// @uvm-ieee 1800.2-2020 auto 12.2.4.1
virtual class uvm_tlm_if_base #(type T1=int, type T2=int);
but they are all virtual and derived class must implement them.
// @uvm-ieee 1800.2-2020 auto 12.2.4.2.3
virtual task peek( output T2 t );
uvm_report_error("peek", `UVM_TASK_ERROR, UVM_NONE);
endtask
uvm_port_base Link to heading
The chunk of work is done in uvm_port_base
defined in uvm_port_base.svh
// @uvm-ieee 1800.2-2020 auto 5.5.1
virtual class uvm_port_base #(type IF=uvm_void) extends IF;
uvm_port_base::get_if()
is called in uvm_analysis_port::write()
. which returns one port depending on the index.
function uvm_port_base #(IF) get_if(int index=0);
string s;
....
....
....
foreach (m_imp_list[nm]) begin
if (index == 0)
return m_imp_list[nm];
index--;
end
endfunction
m_imp_list
is populated by m_add_list
.
local function void m_add_list (this_type provider);
...
...
for (int i = 0; i < provider.size(); i++) begin
imp = provider.get_if(i);
if (!m_imp_list.exists(imp.get_full_name()))
m_imp_list[imp.get_full_name()] = imp; // <===================================
end
endfunction
m_add_list
is called by resolve_bindings
. resolves_bindings
gets the port list from m_provided_by
.
// This method is automatically called just before the start of the // end_of_elaboration phase. Users should not need to call it directly.
virtual function void resolve_bindings();
if (m_resolved) // don't repeat ourselves
return;
if (is_imp()) begin
m_imp_list[get_full_name()] = this;
end
else begin
foreach (m_provided_by[nm]) begin
this_type port;
port = m_provided_by[nm];
port.resolve_bindings();
m_add_list(port); // <===================================
end
end
endfunction
And finally, m_provided_by
should be populated by connect
// @uvm-ieee 1800.2-2020 auto 5.5.2.14
virtual function void connect (this_type provider);
...
... =
m_provided_by[provider.get_full_name()] = provider; // <===================================
provider.m_provided_to[get_full_name()] = this;
endfunction