UVM Cookbook is a great tech reference; I appreciate your time and expertise creating it.
I am reading spi_env_config.svh (TestbenchBuild/uvm_tb_build_ss_tb/tb_build/sub_system_tbs/pss_tb/env/pss_env_config.svh), but I could not understand how this line works:
extern static function pss_env_config get_config( uvm_component c);
A static method cannot access automatic properties; pss_env_config is not static. How can this work?
In this method, macro `uvm_fatal is used. This is not “enabled” yet; how can this work?
The only thing special about a static method is that is has no this handle. You cannot reference members of the class the method is defined. t is an automatic variable inside the scope of the get_config() method, and a static method may access anything within its scope.
`uvm_fatal will call the global uvm_report_fatal() function defined in the uvm_pkg. It will not call this.uvm_report_fatal().
Many thanks for your speedy response; you’re great always.
The pss_env_config is the returned type; when memory is allocated for the static method pss_env_config::get_config, this type is not created yet. Would it not result in “undefined type” during compilation?
As written in line 186 of the uvm_globals.svh, the uvm_globals::uvm_report_fatal is not a static method; an access to this automatic method in a static method will result a syntax error. In the old days, we used macro uvm_fatal_context which uses static uvm_root::get to get around this issue. Has there been a new revision of the UVM, and this issue has been taken care of and there is no need for uvm_*_context?
This is called a self-referential type. Remember that when you declare a class variable, you are only declaring the space to hold a handle to a class object, not the class object itself. (Take my short class on classes). The compiler only needs to know that pss_env_config is going to be a type, it does not need a complete definition. As another example, the class uvm_component has many self-referential types as well:
class uvm_component extends uvm_report_object;
...
extern function new (string name, uvm_component parent);
uvm_component m_parent;
protected uvm_component m_children[string];
protected uvm_component m_children_by_handle[uvm_component];
...
endclass
The terminology of OOP is heavily overloaded. There is a difference between the static qualifier of a class method, and the static storage lifetime qualifier of a function. The storage lifetime (static or automatic) of a function is legacy from Verilog and does not apply to class methods which only have automatic lifetimes. See this link for more info. A static method of a class can refer to anything that does not require a ‘this’ handle.
Great responses! I know that I’m gonna learn much from you any time I’d ask; really appreciate this; I agree with most of them.
Indeed the compile needs to know if a type exists; I must agree with your response on this principle. This is precisely why we sometimes do typedef class uvm_component; etc.
The point is a compile may not know what pss_env_config is until it is defined; therefore, the code as written may not work. More likely or not, it will result in a syntax error due to “undefined” type. For your example, the reason that uvm_component works is that it is typedef’ed in its parent class uvm_report_object line 26.
Who knows and remembers all the terminologies of OOP all the time? Thanks a bunch to point it out :-) I completely agree with you about their loaded words!
The key word “static” is not a legacy term; it is defined in all IEEE 1800’s including the IEEE 1800-2012 section 8.10 page 141. It is stated that “A static method has no access to non-static members (class properties or methods)”. Accessing a non-static method as shown in pss_env_config::get_config will be a syntax error.
The reason that uvm_fatal_context works and uvm_fatal does not is that uvm_fatal_context uses a static method but uvm_fatal does not.
The point of my inquiry is that the code as written will have at least a syntax error unless there is some clever trick hidden somewhere which I don’t know and would like to learn.
In my humble opinion, the code would be fine if it would has been written as:
1.
typedef class pss_env_config; include “pss_env_config.svh” These can be written in the package in which the pss_env_config.svh is include’d.
uvm_fatal_context should be used instead of uvm_fatal.
Thanks again; it is always a pleasure reading your posts; I am a big fan of yours.
Best regards
A typedef is not required in this case because pss_env_config is known to be a type when it appears in the variable declaration t. The class pss_env_config in the line above takes care of that. The only time a typedef is absolutely required is when the compiler encounters a never before seen identifier. That happens when you have a pair of cyclic definitions: class A needs a handle to class B, and class B needs a handle to class A. You can only define one class first, the other will need a typedef. The other place you will see typedefs used is then the scripts used to compile code are lax in their compilation order. You will see a lot of that in the UVM.
If you are getting a syntax error from the compilation of the pss_env_config.svh file, then show the error and let your vendor know they have a bug.
The key word in section 8.10 is members. “A static method has no access to non-static members (class properties or methods)” It does have access to everything else visible within its scope. The functions uvm_report_enable() and uvm_report_fatal() are both defined in the package uvm_pkg, they are not member class methods. So they are visible and accessible to the static method pss_env_config::get_config. Had the class pss_env_config been extended from uvm_component (which is extended from uvm_report_object), then there would be a legitimate syntax error. That is because uvm_report_object does have class member methods named uvm_report_enable and uvm_report_fatal. Those non-static class methods names would be found first, hiding the functions defined at the top-level of the package.
This is because uvm_sequence_item has its own reporting interface. It delegates to the sequencer the sequence is running on, or the uvm_top if the sequencer is null (virtual sequence)
You need to use `uvm_info_context to provide some context for reporting. Without knowing why you need a static method, I can only suggest using uvm_root::get() as the context