Parag Goel, Senior Corporate Application Engineer, Synopsys
In the previous post, we looked at how you can enable/disable different types of coverage encapsulated in the Coverage Model wrapper class. In this post, let’s look at how we can easily create an infrastructure to pass different inputs to the wrapper class so as to able to configure the coverage collection based on user. The infrastructure ensure that these elements values percolate down to the to the sub-coverage model groups.
The following are some of the key inputs that needs to be passed to the difference coverage component classes
1. SV Virtual Interfaces so that different signal activity can be accessed
2. The Transactions observed and collected by the physical level monitors
3. The ‘Configuration’ information

Let’s look at how the we can easily pass the signal level information to the Coverage Model
Step I: Encapsulation of the interface in the class wrapper.
class intf_wrapper extends vmm_object;
virtual axi_if v_if ;
function new (string name, virtual axi_if mst_if);
super.new(null, name);
this.v_if = mst_if;
endfunction
endclass: master_port
Step II: In the top class/environment- Set this object using vmm_opts API.
class axi_env extends vmm_env;
`vmm_typename(axi_env)
intf_wrapper mc_intf;
function void build_ph();
mc_intf = new(“Master_Port”, tb_top.master_if_p0);
// Set the master port interface
vmm_opts::set_object(“VIP_MSTR:vip_mstr_port“, mc_intf, env);
endfunction:build_ph
endclass: axi_env
Step III: Connecting in the coverage class.
A. Get the object containing interface in the coverage model class using vmm_opts.
assert($cast(this.mst_port_obj, vmm_opts::get_object_obj(is_set, this, “vip_mstr_port“)));
B. Connecting local virtual interface to one contained in the object.
this.cov_vif = mstr_port_obj.v_if;
Now, we need to pass the collected transaction object from the monitor needs to the coverage collector. This can be conveniently done in VMM using TLM communication. This is achieved through the vmm_tlm_analysis_port, which establishes the communication between a subscriber & an observer.
class axi_transfer extends vmm_data;
. . .
class axi_bus_monitor extends vmm_xactor;
vmm_tlm_analysis_port#(axi_bus_monitor, axi_transfer) m_ap;
task collect_trans();
//Writing to the analysis port.
m_ap.write(trans);
endtask
endclass
class axi_coverage_model extends vmm_object;
vmm_tlm_analysis_export #( axi_coverage_model, axi_transfer) m_export;
function new (string inst, vmm_object parent = null);
m_export = new(this, “m_export”);
endfunction
function void write(int id, axi_transfer trans);
//Sample the appropriate covergroup, once the transaction is received
in the write function.
endfunction
endclass
To set up the TLM Connections in the agent/environment, we need to do the following:
class axi_subenv extends vmm_group;
//Instantiate the model classes and creates them.
axi_bus_monitor mon;
axi_coverage_model cov;
. . .
virtual function void build_ph;
mon = new( “mon”, this);
cov = new( “cov”, this);
endfunction
virtual function void connect_ph;
//Bind the TLM ports via VMM – tlm_bind
monitor.m_ap.tlm_bind( cov.m_export );
endfunction
To make the Coverage Model truly configurable, we need to look at some of the other key requirements as well at different level of granularity. This can be summarized as the ability to do the following.
1. Enable/Disable coverage collection for each covergroup defined . Every covergroup should be created only if a user wishes to do so. So there should be a configuration parameter which restricts the creation of the covergroup altogether. And this should also be used to control the sampling of a covergroup.
2. The user must be able to configure the limits on the individual values being covered in the coverage model within a legal set of values. Say for example, transaction field BurstLength – user should be able to guide the model what are the limits on this field that one wishes to get coverage on within a legal set of values ranging from ‘1’ to ‘16’ as per AXI spec. So providing lower and upper limits for transaction parameters like burst size, burst length, address etc. makes it re-usable. This limits should be modeled as variables which can be overwritten dynamically
3. The user should be able to control the number of bins to be created. For example in fields like address. auto_bin_max option can be exploited to achieve this in case the user doesn’t have explicitly defined bins..
4. The user must be able to control the number of hits for which a bin can be considered as covered. option.atleast can be used for this purpose and the input to this can be a user defined parameter.
5. The user should also have the control to specify his coverage goal, i.e. when the coverage collector should show the covergroup “covered” even though the coverage is not 100%. This can be achieved by using option.goal, where goal is again a user defined parameter.
All the parameters required to meet the above requirements can be encapsulated in the class (i.e. coverage configuration class) and this can be set and retrieved in a similar fashion described for setting & getting the interface wrapper class using vmm_opts API’s.
class coverage_cfg extends vmm_object;
int disable_wr_burst_len;
. . .
function new( vmm_object parent=null, string name);
super.new(parent, name);
endfunction
coverage_cfg cfg;
function new(vmm_object parent=null, string name);
bit is_set;
super.new(parent, name);
$cast(cfg, vmm_opts::get_object_obj(is_set, this,
"COV_CFG_OBJ”));
endfunction
Wei Hua presents another cool mechanism of collecting this parameters using vmm_notification mechanism in this earlier blog :
A Generic Functional Coverage Solution Based On vmm_notify
Hope you found this useful. I will be talking about how to track Error Coverage in my next blog, so stay tuned!