Should you use VMM Callbacks or TLM Analysis ports?
Posted by S. Prashanth on January 27th, 2010
With the addition of OSCI TLM2.0 features in VMM1.2, it is now becoming possible to use analysis ports for broadcasting transaction information from a transactor to any components such as scoreboard, functional coverage models, etc…
But, does it mean that VMM callbacks which are traditionally used for this purpose are not required anymore?
In short, the answer is no: both analysis port and callback have their own advantages. Before getting into more details, let me show you two simple examples I’ve created to encompass the analysis port and callback usage.
Communication through analysis port
Step1: In my transactor, I’ve 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: Let’s now see how to model a subscriber such as a coverage model. In this model, I’ve simply instantiated a vmm_tlm_analysis_export instance [Line 3] and provided the implementation of the write method() [Line 4]. Once 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 my transactor and my subscribers. This is simply done by using the transactor tlm_bind() method. Of course we should be 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 you can see in these examples, analysis ports are easy to use. But they are not meant to allow subscribers to modify the transaction and are very much restricted to only one method with only one argument, i.e. write().
Communication through callback
Step1: I’ve created a generic callback that is nothing but a container that extends the vmm_xactor_callbacks base class with empty virtual methods [Line 1-3]. I have deliberately left these methods empty so that they can overridden for any particular usage such as a coverage model, scoreboard, etc.Next step is have my 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); endtask
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, I can extend the previous class and provide the implementation the 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: Once both transactor and subscribers are implemented, I can simply instantiate them in my implicitly phased environment [Line2-3]. Then, I can register the extended callback instance to the transactor by using append_callback() method Line[6]. Note that this registration happens 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 you can see in above examples, callbacks are also easy to use. As opposed to analysis port, their subscribers can possibly modify the transaction and can contain multiple methods with any kind of arguments.
Comparison
1. Analysis ports follow OSCI TLM2.0 standard.
2. Unlike callbacks, user do not need to create class with empty virtual methods, instead pre-defined method write() is 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. Analysis ports can only be used by classes based on vmm_object. Callbacks can be used by any class.
In summary
- If a transactor needs to broadcast only one transaction, then analysis port can be used. If a transactor needs to send different kinds of information at different points, and 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.
January 28th, 2010 at 12:46 am
Thanks Prashanth this post is indeed informative and relieves users when it comes to VMM-1.2 development/migration related issues/debates, to choose between callbacks and analysis ports.
Your last line in this
“Both analysis port and callback can also be provided, publishing analysis port after callbacks.”
I think what you mean to say here is, “Instantiaing the analysis ports in the callback classes.”
As far as my experience with vmm-1.2 says, This is something users would choose in the most cases.
Reasons:
Callbacks are the lovely and amazing creatures introduced by Synopsys brains, to add the flexible hook up points in the xactors. At the same time, when Era has changed to interoperability between mulitple languages, no one wants to stay back and avoid using TLMs because its great to keep window for everything in the xactors, who knows where it could be REUSED tomorrow.
To use the both the things at the same time, I would suggest to Keep the hook up points in your Xactors as callbacks only, and instantiate the required TLM ports in the Callbacks. This will,
-> Keep your xactor flexible to Change the transaction before you pass it to the observers using analysis ports.
-> It will keep a window for every advantage of Callbacks like as you said, inserting delays, error injections etc.
-> Add the TLM interoperability advantage in your xactor as you have TLM ports in the callbacks, So what I indicate here is, “Every VMM-1.1 xactor which has callbacks at proper points is of-course interoperable using TLM with foreign code/VMM-1.2 code which uses TLM”
Cheers,
Shunty
February 1st, 2010 at 1:05 am
Calbbacks are basically introduced to keep xactor reusable. Passing transaction to sb/cov is one of the side-use of the callback. TLM is intended to be used as a comunication mechanism.
Dhaval