A generic functional coverage solution based on vmm_notify
Posted by Wei-Hua Han on June 15th, 2009
Weihua Han, CAE, Synopsys
Functional coverage plays an essential role in Coverage Driven Verification. In this blog, I’ll explain a modular way of modeling and implementing functional coverage models.
SystemVerilog users can take the advantage of the “covergroup” construct to implement functional coverage. However this is not enough. The VMM methodology provides some important design-independent guidelines on how to implement functional coverage in a reusable verification environment.
Here are a few guidelines from the VMM book that I consider very important for implementing a functional coverage model:
“Stimulus coverage shall be sampled after submission to the design” because in some cases it is possible that not all generated transactions will be applied to DUT.
“Stimulus coverage should be sampled via a passive transactor stack” for the purpose of reuse so that the same implementation can be used in a different stimulus generation structure. For example in another verification environment, the stimulus may be generated by a design block instead of testbench component.
“Functional coverage should be associated with testbench components with a static lifetime” to avoid creating a large number of coverage group instances. So “Coverage groups should not be added to vmm_data class extensions”. These static testbench components include monitors, generators, self-checking structure, etc.
“The comment option in covergroup, coverpoint, and cross should be used to document the corresponding verification requirements”.
You can find some more details on these and other functional coverage related guidelines in the VMM book, pages 263-277.
In an earlier post “Did you notice vmm_notify?”, Janick showed how vmm_notify can be used to connect a transactor to a passive observer like a functional coverage model. Here, let me borrow his idea to implement the following VMM-based functional coverage example.
1. Transaction class
1. class eth_frame extends vmm_data;
2. typedef enum {UNTAGGED, TAGGED, CONTROL} frame_formats_e;
3. rand frame_formats_e format;
4. rand bit[3:0] src;
5. …
6. endclass
There is some random property defined in the transaction class. We would like to collect the coverage information for these properties in our coverage class, for example “format” and “src”.
2. A generic subscribe class
1. class subscribe #(type T = int) extends vmm_notify_callbacks;
2. local T obs;
3. function new(T obs, vmm_notify ntfy, int id);
4. this.obs = obs;
5. ntfy.append_callback(id, this);
6. endfunction
7. virtual function void indicated(vmm_data status);
8. this.obs.observe(status);
9. endfunction
10. endclass
The generic subscribe class specifies the behavior for “indicated”method which will be called when vmm_notify “indicate” method is called. Then with using this generic subscribe class, functional coverage and other observer models only need to implement the desired behavior with “observe” method. Please note that in line 8 the vmm_data object is passed to “observe” method through vmm notification status information.
3. Coverage class
1. class eth_cov;
2. eth_frame tr;3. covergroup cg_eth_frame(string cg_name,string cg_comment,int cg_at_least);
4. type_option.comment = “eth frame coverage”;
5. option.at_least = cg_at_least;
6. option.name=cg_name;
7. option.comment = cg_comment;
8. option.per_instance=1;
9. cp_format:coverpoint tr.format {
10. type_option.weight=10;
11. }
12. cp_src: coverpoint tr.src {
13. illegal_bins ilg = {4′b0000};
14. wildcard bins src0[] = {4′b0???};
15. wildcard bins src1[] = {4′b1???};
16. wildcard bins src2[] = (4′b0??? => 4′b1???);
17. }
18. format_src_crs: cross cp_format, cp_src {
19. bins c1 = !binsof(cp_src) intersect {4’b0000,4’b1111 };
20. }
21. endgroup22. function new(string name=”eth_cov”, vmm_notify notify, int id);
23. subscribe #(eth_cov) cb=new(this,notify,id);
24. cg_eth_frame = new(”cg_eth_frame”,”eth frame coverage”,1);
25. endfunction
26. function void observe (vmm_data tr);
27. $cast(this.tr,tr);
28. cg_eth_frame.sample();
29. endfunction
30. endclass
The coverage group is implemented in coverage class eth_cov. And this coverage class is registered to one vmm_notify service through scubscribe class. The coverage group is sampled in “observe” method so when the notification is indicated the interesting properties will be sampled.
4. Monitor
1. class eth_mon extends vmm_xactor;
2. int OBSERVED;
3. eth_frame tr; // Contains reassembled eth_frame transaction4. function new(…)
5. OBSERVED = this.notify.configure();
6. …
7. endfunction
8. protected virtual task main();
9. forever begin
10. tr = new;
11. //catch transaction from interface
12. …
13. this.notify.indicate(OBSERVED,tr);
14. …
15. end
16. endtask
17. endclass
The monitor extracts the transaction from the interface then it indicates the notification with the transaction as the status information (line 13).
5. Connect monitor and coverage object
1. class eth_env extends vmm_env;
2. eth_mon mon;
3. eth_cov cov;
4. …
5. virtual function void build();
6. …
7. mon = new(…);
8. cov = new(”eth_cov”,mon.notify,mon.OBSERVED);
9. …
10. endfunction
11. …
12. endclass
In the verification environment, the coverage object is created with the monitor notification service interface and the proper notification ID.
There are other ways to implement functional coverage in VMM based environments. For example a callback-based implementation is used in the example located under sv/examples/std_lib/vmm_test in the VMM package which can be downloaded from www.vmmcentral.org.
I haven’t discussed assertion coverage in this post, which are another important type of “functional coverage”. If you are interested in using assertions for functional coverage please check out chapter 3 and chapter 6 in the VMM book for its suggestions.
Posted in MODs, RAL, SV, VMM | 2 Comments »












