VMM VIP’s on multiple buses

 

A better approach is one that was described by Janick in the “Size Does Matter” blog of using `define. Let’s expand on this and see how it works for reusable VIPs. Well, the first thing that comes to my mind is that a `define is a global namespace macro with a single value, whereas I am using my VIP with 2 different bus architectures. Therefore, the `define alone is not enough: you also need a local constant to be able to exclude unwanted bits when you have a VIP instantiated for various bus widths.

1. //default define values 

2. `define MAX_DATA_SIZE 16 

3. `define MAX_ADDR_SIZE 16

4. class pkt_c extends vmm_data; 

5. static vmm_log log = new(“Pkt”, “class”); 

6. //instance constant to control actual bus sizes 

7. const int addr_size;

8. logic [`MAX_ADDR_SIZE:0] addr; 

9. logic [`MAX_DATA_SIZE:0] data; 

10. // pass a_size as arg to coverage 

11. // ensuring valid coverage ranges. 

12. covergroup cg (int a_size); 

13. coverpoint addr 

14. {bins ad_bin[] = {[0:a_size]};} 

15. endgroup 

16. // sizes specialized at construction for pkts

17. // on buses less than MAX bus widths 

18. function new(int a_s=`MAX_ADDR_SIZE); 

19. addr_size = a_s; 

20. cg = new(addr_size); 

21. `vmm_note(log, $psprintf(“\nADDR_TYPE: “,$typename(addr), 

22. “\nDATA_TYPE: “,$typename(data), 

23. “\nMAX_BUS_SIZE: “, addr_size)); 

24. endfunction 


 

The code above allows for a default implementation and all the user needs to do is set the `MAX_ADDR_SIZE and `MAX_DATA_SIZE symbols and all the code will be fully reusable across drivers, monitors, subenv, SoC etc.

For situations where two VIP’s of differing bus architectures are used, the compiler symbols need to be set to the biggest bus architecture in the system; smaller bus-widths are set using addr_size. It is not necessary for addr_size variable to be an instance constant or set during construction. By using instance constants, this ensures the bus-widths are not changed at runtime by users. Having the value of addr_size set during construction gives the users the flexibility to setup the object as they want. For pseudo-static objects such as drivers, monitors, subenvs, masters, slaves, scoreboards etc you should check the construction of verification modules for your particular design architecture during the vmm_env::start phase.

N.B not shown above, but assumed, is that the addr_size variable would be used to ensure correct masking occurs when performing do_pack(), do_unpack() compare() etc.

Just to wrap up some loose ends…

I’m not totally discounting the merits of parameterized classes just insuring people look at all the options. For instance you could parameterize everything and then set the SIZE at the vmm_subenv level and map the SIZE parameters to all other objects. At some point you will want to monitor or scoreboard across different bus-widths and then the parameterized class casting will bite you, reducing you to manually mapping the members within the comparison objects. There is a time and place for everything, so probably need another blog showing merits and where to use parameterized classes.

The vmm_data class is not the only place you might need to know the size of the bus, the same `define & instance constant technique can be used throughout your VIP classes.

This blog does not discuss the pros and cons of putting coverage groups in your data object class. I merely used the covergroup in the data-object as a vehicle to demonstrate how you can make your classes more reusable. I think a separate blog about where best to put coverage will clarify the usage models.

All the code snippets can be run with VCS-2009.06 & VMM1.1. Contact me for more complete code examples and bugs or issues you find.

你可能感兴趣的:(SystemVerilog)