Question:
Do I use VMM callbacks or TLM analysis ports to broadcast information from a
transactor?
Answer:
After the OSCI TLM 2.0 features were added to VMM 1.2, it is possible to use
analysis ports for broadcasting transaction information from a transactor to
any components such as, scoreboard, functional coverage models, etc.
However, it does not mean that VMM callbacks which were originally used for this
purpose are not required anymore. Both analysis port and callback have their own
advantages.
The following two examples explain how to encompass the analysis port and callback
usage:
Example 1:Communication Through Analysis Port
===================================
Step1: Simply instantiate a vmm_tlm_analysis_port instance [line 2] and invoke
the analysis_port.write() method [line 8]to post the tr object to multiple
subscribers.
1. class cpu_driver extends vmm_xactor;
2. vmm_tlm_analysis_port#(cpu_driver, cpu_trans) analysis_port;
3. virtual function void build_ph();
analysis_port = new(this, "cpu_analysys_port");
4. endfunction
5. virtual task main();
6. cpu_trans tr;
7. ...
8. analysis_port.write(tr);
9. endtask
10. endclass
Step2: Modeling a subscriber, such as a coverage model.
In this model, you have to instantiate a vmm_tlm_analysis_export instance
[Line 3] and provide the implementation of the write method() [Line 4].
When the transactor posts a transaction to the write method, the coverage
model write_CPU gets called as well and receives this transaction, which
can be sampled and covered.
1. class cntrlr_cov extends vmm_object;
2. vmm_tlm_analysis_export #(cntrlr_cov, cpu_trans)
3. cpu_export = new(this, "CpuAnExPort");
4. virtual function void write(int id=-1, cpu_trans tr);
5. this.cpu_tr = tr;
6. CG_CPU.sample();
7. endfunction
8. endclass
Step3: The last important part is to bind your transactor and subscribers.
You do this by using the transactor tlm_bind() method. Surely, you should
have invoked for all subscribers.
1. class tb_env extends vmm_group;
2. cpu_driver drv;
3. cntrlr_cov cov;
4. function void connect_ph();
5. drv.analysis_port.tlm_bind(cov.cpu_export);
6. endfunction
7. endclass
As explained in these examples, analysis ports are easy to use. However, they are
not meant to allow the subscribers to modify the transaction and are very much
restricted to only one method with only one argument, i.e. write().
Example 2: Communication Through Callback
==============================
Step1: Creation of a generic callback that is nothing but a container that extends
the vmm_xactor_callbacks base class with empty virtual methods [Line 1-3].
These methods are intentionally left empty so that they can be overridden
for any particular usage such as a coverage model, scoreboard, etc.
Next step is to have your transactor calling this callback once the transaction
is available [Line 10]
1. class cpu_driver_callbacks extends vmm_xactor_callbacks;
2. virtual function void write(cpu_trans tr); endfunction
3. endclass
4.
5. class cpu_driver extends vmm_xactor;
6.
7. virtual task main();
8. cpu_trans tr;
9. ...
10. `vmm_callback(cpu_driver_callbacks, write(tr));
11. endtask
12. endclass
Step2: Now, you can extend the previous class and provide the implementation coverage
model directly in the callback.
1. cpu2cov_callback extends cpu_driver_callbacks;
2. cntrlr_cov cov;
3. virtual function void write(cpu_trans tr);
4. cov.cpu_tr = tr;
5. cov.CG_CPU.sample();
6. endfunction
7. endclass
Step3: When both the transactor and subscriber are implemented, you can simply
instantiate them in your implicitly phased environment [Line2-3]. Then,
you can register the extended callback instance to the transactor by using
the append_callback() method Line[6].
Note: This registration happens only in the connect phase.
1. class tb_env extends vmm_group;
2. cpu_driver drv;
3. cntrlr_cov cov;
4. function void connect_ph();
5. cpu2cov_callback cbk = new(cov);
6. drv.append_callback(cbk);
7. endfunction
8. endclass
As explained in the above examples, callbacks are easy to use. As opposed to
analysis port, their subscribers can possibly modify the transaction and can
contain multiple methods with any type of arguments.
Comparison
===========
1. Analysis ports follow OSCI TLM2.0 standard.
2. Unlike callbacks, you need not create class with empty virtual methods, instead
pre-defined method write() can be used.
3. Analysis ports can only broadcast one transaction as opposed to callbacks where
you can define the method arguments.
4. Analysis port method write() is a function whereas callback class can model its
empty virtual methods as tasks or void functions which gives you flexibility to
control the transactor as well (like inserting delays, injecting error mechanism,
etc.).
5. The `vmm_tlm_analysis_export() macro must be used to create a new analysis
fa?ade when a class need to have more than one analysis export.
6. You can use analysis ports by classes based on vmm_object. Any class can use
callbacks.
In summary
==========
if a transactor needs to broadcast only one transaction, then you can use analysis
port. However, if a transactor requires to send different types of information at
different points, and also provide some hooks for modeling variant functionality
(like inserting delays, error injections, etc), then callbacks is the way to go.
Both analysis port and callback can also be provided, publishing analysis port
after callbacks.