OVM Hints and Tips
Avoiding Common Pitfalls when using OVM 1.0Doulos, February 2008
We got caught out many times as we started using OVM 1.0. We have compiled this list of hints and tips so you can avoid making some of the same mistakes:
Do not forget to include the macro `ovm_object_utils in every transaction class and `ovm_component_utils in every component class, otherwise they will not get registered with the factory, and methods such as copy, compare and print will not be available. Moreover, make sure to use `ovm_component_utils for components, and `ovm_object_utils for other objects.
If your classes have properties that you want to configure, print, randomize etcetera, use the appropriate `ovm_field_* macro for each member, enclosed between `ovm_object|component_begin and `ovm_object|component_end.
For maximal portability between simulators, class properties should be declared before they are referenced by an `ovm_field_* macro. Invoking the macros just before the endclass statement will satisfy this requirement.
If you create a new component by copying the code for an an existing component, do not forget to change the argument to the `ovm_component_utils macro to correspond to the new component name, otherwise you will see some very obscure error messages.
Remember not to put a semicolon at the end of any macro invocation.
One of the header files "ovm.svh" or "ovm_macros.svh" must be included at the top of any source code file that uses the OVM macros.
The OVM-1.0 kit recommends two approaches to including header files, either import ovm_pkg::*; and `include "ovm_macros.svh" or `include "ovm.svh". In the latter case, care must be taken to include "ovm.svh" in the same scope as any parameterised class declarations, such as within a package or a module. But importing two or more packages that both include "ovm.svh" causes a compile error in some simulators. Careful use of conditional compilation is required to create portable code with current simulators, for example:
`ifdef INCA `include "ovm.svh" `else `include "ovm_macros.svh" import ovm_pkg::*; `endif
The Phase Callbacks and Component Instantiation
Remember to call super.new() at the start of your component constructor and pass all constructor arguments through, even if they have default values.
Remember to call super.build() from any overridden build method. If you do not call super.build() explicitly, it will be called implicitly, but not necessarily at the correct point in the build phase. Calls to super.xxx() are not necessary for the other phase hooks.
When instantiating components (classes derived from ovm_component) using either new or create_component, it is a really good idea to make sure that the component hierarchy is rigorously defined, that is, every component has a single parent, except for one top-level component, the test (derived from ovm_test). Otherwise, things tend not to work as expected.
With method set_inst_override, the full hierarchical pathname to the instance must be given. But in the case of ovm_factory::create_component, the inst_path argument must be the hierarchical name of the parent of the component being created.
Certain built-in classes such as ovm_random_stimulus, tlm_fifo and ovm_scenario_controller_base are parameterised and do not use the utility macros, so cannot be created by a factory in the same way as a user-defined component.
OVM phase callbacks combine features from AVM and URM, which is good from the point of view of backward compatibility, but can be confusing. In OVM, post_new calls build, and pre_run calls configure. The user should override the build and configure hook methods.
Although the export_connections and import_connections hook methods from AVM still exist for backward compatibility, they are no longer necessary, because port binding is deferred to a point just before end_of_elaboration (a similar mechanism to SystemC). connect is sufficient by itself.
TLM ports and exports are objects, so remember to create them explicitly within the constructor or build phase of the parent ovm_component.
The method to connect the sequence item producer interface and consumer interface is named connect_if rather than connect. The connect_if method is defined for both interfaces, and either method may be called
Remember that although ovm_threaded_component has a run method, ovm_component does not. If you define a run method in an ovm_component, it will not get called.
When a run method suffers event starvation, the final simulation phases (extract, check, report) do not get called, even though simulation stops. This can be remedied by calling global_stop_request or set_global_timeout.
Configuration and set_config / get_config
The set_config / get_config methods that form the configuration interface are unrelated to the configuration callback of the same name.
set_config / get_config only works within the hierarchy of ovm_components, not with other object types such as transactions and sequencers.
If there is an overlap between instance and field names across multiple calls, possibly using wildcards, the last call wins.
A wildcard "*" in an instance name will match any expanded path at that point in the hierarchical name, not just a single level of hierarchy. A wildcard "*" in a call to get_config will only match a corresponding wildcard in a call to set_config: it will not match a more specific name.
When set_config is called, there is no obligation for a corresponding field to have been registered, but if it has been then the type should be match (that is, int, string, or object), and the value of the field will be overwritten.
According to the documentation, get_config searches for the given field from the top of the hierarchy down to current component instance, but the implementation does not seem to work that way.
The value of the command line plusarg +OVM_TESTNAME=my_test must not be in quotes; otherwise, the quotes become part of the filename!
set_type_override and set_inst_override do not work on sequences added to a sequencer using `ovm_update_sequence_lib_and_item(transaction_type), that is, the simple_sequence. They do work on user-defined sequences explicitly registered with the sequencer using `ovm_sequence_utils.
Portability between Simulators
Here are some issue you may run into when porting OVM code between simulators. Hopefully, these issues will go away as vendors update their tools:
At the time of writing, some simulator vendors encourage you to put "ovm_pkg.svh" on the command line, others encourage you to include "ovm.svh" in the source code. Do not do both, or some simulators may suffer from duplicate definitions.
Some simulators are more sensitive than others to the positioning of the ovm_field_* macros within a class. For maximal portability, place the macro invocations after the declarations of the corresponding fields.
With some simulators, having empty virtual methods, such connect or configure, may cause a compile-time error. The problem goes away if the empty method is deleted or executable code is inserted.
In some circumstances, some simulators seem to require there to be at least one static reference to an item within a package in order for that package to be successfully loaded at run time. As a workaround, you could define a dummy variable in the package and assign it in the top-level module.
When using +OVM_TESTNAME=my_test with class my_test placed within the top-level module, some simulators may require class my_test must be placed before the call to run_test.
Click here to download this page in PDF format. In exchange, we will ask you to enter some personal details. To read about how we use your details, click here. On the registration form, you will be asked whether you want us to send you further information concerning other Doulos products and services in the subject area concerned.