What does super.build_phase() do? - system-verilog

According to uvm users guide 1.1, page 62:
"If the UVM field automation macros are used, super.build_phase() is called as the first line of the
ubus_example_tb’s build_phase() function. This updates the configuration fields of the
ubus_example_tb."
class ubus_example_tb extends uvm_env;
...
...
// build_phase()
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase); // Configure before creating the
// subcomponents
...
endclass : ubus_example_tb
Why the "super.buildphase(phase)" updates ubus_example_tb and not his parent(super)?

If you do not use the `uvm_component_utils_begin() macro, you should not call super.build_phase() in the class that directly extends from uvm_component. That creates unnecessary overhead. If you do use the macro, that macros inserts a virtual function that gets called from uvm_component::build_phase. That is what gets called from super.build_phase.
I strongly recommend against using the field macros as they are very inefficient. See this post that shows how 1 line of code expands to 50.
Also be careful with the terms parent and super. I recommend against using parent and child when referring to OOP inheritance. Parents create(construct) children and they are distinct objects from their parents. When you inherit property, that property becomes yours and all your property belongs to one object. Use base and extended.
The UVM uses terms parent and child to refer to relationships between objects when build a hierarchical tree/graph structure. The class uvm_component has a handle to its parent and handles to all its children so that you can traverse the hierarchical structure. This terminology is used in most programming languages and is independent of OOP.

Related

UVM- run test() in top block and Macros

I'm reading the following guide:
https://colorlesscube.com/uvm-guide-for-beginners/chapter-3-top-block/
In Code 3.2 line 24- run_test();
I realized that it supposed to execute the test, but how it know which test, and how, and why should I write it in the top block.
In Code 4.1 lines 11-14 (https://colorlesscube.com/uvm-guide-for-beginners/chapter-4-transactions-sequences-and-sequencers/):
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_field_int(inb, UVM_ALL_ON)
`uvm_field_int(out, UVM_ALL_ON)
`uvm_object_utils_end
Why should I add the "uvm_field_int" , what would happend if i didn't add them, and what is "UVM_ALL_ON"?
run_test is a helper global function , it calls the run_test function of the uvm_root class to run the test case. There are two ways by which you can pass the test name to the function.The first is via the function argument and the second is via a command line argument. The command line argument takes precedence over the test name passed via the function argument.
+UVM_TESTNAME=YOUR_TEST_NAME
run_test("YOUR_TEST_NAME");
run_test function in the uvm_root uses the factory mechanism to create the appropriate instance of the umm_test class and so the test case must register itself with the factory using the macro `uvm_component_utils for the factory mechanism (create_component_by_name) to function.
class YOUR_TEST_NAME extends umm_test ;
// register the class with the factory
// so that run_test can find this class when the
// string test_name is passed to it.
`uvm_component_utils(YOUR_TEST_NAME)
.....
endclass
The run_test function then kicks of the uvm_phases (..,build_phase,connect_phase,...) starting the uvm portion of the simulation. There should be no time ticks consumed before the run_phase starts , so it is essential that run_test case is called in the initial block itself. Also we want the uvm and test bench to be ready to drive and receive data as soon as the RTL is ready for which it is essential that we start the run_test at the earliest. Any delay in doing so will generate an error.
`uvm_field_int/uvm_field_object/.. are called field automation macros. They are not mandatory in the class definition and are provided as a helper macros to ease the use of many common/routine functions of the uvm_object. Examples of thse functions in uvm_object are - copy,compare,pack,unpack,print, etc and these macros generate code to automatically use these functions.
If you are not using the uvm_object common functions leaving out these macros from the class definition will not produce any errors.
In case you implement you own version of the common operations you can also leave out these macros from the class.
UVM_ALL_ON - enables all functions like compare/copy/... to be implemented for the particular field.
link with examples -
http://www.testbench.in/UT_04_UVM_TRANSACTION.html
For example the uvm_object has a compare function which compare two instances of the same class and return true if all the variables in the class are equal.
virtual function bit do_compare( uvm_object rhs, uvm_comparer comparer );
.....
// return 1 if all the variables match
return ( super.do_compare( rhs, comparer ) &&
this.var_1 == rhs.var_1 &&
this.var_2 == rhs.var_2 &&
......
this.var_n == rhs.var_n );
endfunction: do_compare
// use in main code
if ( new_class.compare(old_classs) )
...
//instead of
if ( new_class.var1 == old_class.var1 && new_class.var2 == old_class.var2 && ... new_class.varn == old_class.varn )
...
The above compare has to be written for each class and updated and maintained for every new variable that is added to the class. This could become error prone as newer variables are added. A similar process has to be followed for all the standard functions uvm_object provides.
The field automation macro generates function to address all these functionality automatically. So doing a do_print for a class with the macros will print out all the fields without explicitly writing any code for it.
// compare/print/.. functions for class simpleadder_transaction are provided by using `uvm_field_int macro.
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_object_utils_end
BUT a word of caution , the use of these macros are discouraged as they add a significant amount of code into the class.. Most of these functions may not be needed by the class yet they get generated by default.
run_test is defined in the documentation (link) as:
virtual task run_test (
string test_name = ""
)
So, in principle, you can state there the test name as a string. But what's usually done is to pass it in the command line of your simulator using the argument: +UVM_TESTNAME=TEST_NAME
The uvm_object macros are a bit more complicated. They generate several methods and more importantly they register the object in the UVM factory, which is what makes them necessary (at least if you are using, as you should, the factory to create them). Citing from the UVM Class Reference documentation (Section 20.2 Component and Object Macros):
Simple (non-parameterized) objects use the uvm_object_utils* versions,
which do the following:
Implements get_type_name, which returns TYPE as a string
Implements create, which allocates an object of type TYPE by calling its constructor with no arguments. TYPE’s constructor, if
defined, must have default values on all it arguments.
Registers the TYPE with the factory, using the string TYPE as the factory lookup string for the type.
Implements the static get_type() method which returns a factory proxy object for the type.
Implements the virtual get_object_type() method which works just like the static get_type() method, but operates on an already
allocated object.

Is it ok to put methods/fields to base class that will only be used by some of the derived classes

This is a bit of a generic software design question. Suppose you have a base class and lots of classes that derive from it (around 10).
There is some common functionality that is being shared between some of the classes (3-4 of derived classes need it). Basically a field for a UI control, an abstract method to create a UI control and the common code that uses the abstract method to recycle the UI piece (8-9 lines of code) using the abstract method. Something like this:
class BaseClass {
...
protected UIControl control;
protected abstract UIControl CreateUI();
protected void RecycleUI() {
if (/* some condition is met */) {
if (this.control != null) {
control.Dispose();
}
this.control = this.CreateUI();
this.AddToUITree(control);
}
}
...
}
Do you think it is OK to put this to base class instead of replicating the code in derived classes.
Drawback is that this piece of code is only used for some of the base classes and completely irrelevant for the other classes.
One alternative is to create an intermediate class that derives from BaseClass and use it as the base to the ones that need the functionality. I felt like creating a derived class for a couple line of code for a very specific purpose felt heavy. It doesn't feel like it is worth interrupting the inheritance tree for this. We try to keep the hierarchy as simple as possible so that it is easy to follow and understand the inheritance tree. Maybe if this was C++ where multiple inheritance is an option, it wouldn't be a big issue but multiple inheritance is not available.
Another option is to create a utility method and an interface to create/update the UI control:
interface UIContainer {
UIControl CreateUIControl();
UIControl GetUIControl();
void SetUIControl(UIControl control);
}
class UIControlUtil {
public void RecycleUI(UIContainer container) {
if (/* some condition is met */) {
if (container.GetUIControl() != null) {
container.GetUIControl().Dispose();
}
UIControl control = container.CreateUI();
container.SetUIControl(control);
container.AddToUITree(control);
}
}
}
I don't like this option because it bleeds UI logic externally which is less secure as its UI state can be manipulated externally. Also derived classes have to implement getter/setter now. One advantage is that there is another class outside of the aforementioned inheritance tree and it needs this functionality and it can use this utility function as well.
Do you have any other suggestions? Should I just suppress the urges that brew inside me to have common code not repeated?
One alternative is to create an intermediate class that derives from
BaseClass and use it as the base to the ones that need the
functionality.
Well, this is what I thought is the most appropriate. But it depends. The main question here is the following: are objects, that require UI recycling and really different from those, that do not? If they are really different, you have to create a new base class for them. If difference is really negligible, I think it's ok to leave things in a base class.
Do not forget about LSP.
We try to keep the hierarchy as simple as possible so that it is easy
to follow and understand the inheritance tree
I think more important here is to keep things not only simple, but also close to your real world things so that modeling new entities would be easy. Seeming easiness now may cause real troubles in the future.

UVM Phase Query

I have couple of questions in relation with UVM phases build() and run(). They might be applicable to other verification methodologies as well
a> Why is the build() phase executed in top-down order. Does this mean we need to new all the components in the build() phase and then proceed with execution of build() of other sub-components instantiated in the class?
b> During the run() phase is something like super.run() called? What is the order of execution of run() phase
Yes, the build_phase() of the UVM executed in top-down order because the children don't exist until they are constructed within the build_phase() of the parent component (And the UVM recommends using the factory create() method instead of calling the constructor new() directly). The build_phase() is also executed top-down so that the parent can provide override setting that the children will use when they execute their build_phase()
The run_phase() of each component is executed concurrently with no defined order you can depend on.
You only need to call super.method() if you are extending a class an need the functionality of the base method. There is nothing inside the run_phase() of a uvm_component, so there is no need to call super.run_phase() when extending from it. You may want to call it when extending your classes from your base classes.

static methods inheritance in backbone over different modules

I am using backbone.js for a web app.
I have different component views which are derived from few base classes.
Each of the view has few static methods for initializing and creating instances.
For example:
class Base extends Backbone.View
#create:(config)->
*do some processing based on config*
*generate view parameters*
viewparams = ....
return new #(viewparams)
class Derived extends Base
**some customizations and functions**
**at some point some where**
instanceDerived = Derived.create(*some params*)
The advantage of this method is that, it becomes natural to re-use the create method. The "#" or "this" refers to the Derived class (constructor) and hence the object can be created easily.
The code works well when both the classes are in same module. However, when the objects are in different modules, the "#" or "this" inside create function refers to "Base.create" instead of the Derived class constructor.
I dont know if I am doing some unconventional coding here. Can some one please advice of how to resolve/structure this problem?

MEF: what is the role, lifetime and knowledge of the 'container'?

i'm playing with MEF and in the example i see this code ( i call it the MEF compose code):
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts();
In most examples this is done in the same source file as the Startup Program class lives, as well as all of the other interfaces and classes.
Now i want to use the MEF, but i wonder what this container does. As far as i guessed it does the export / import mapping, but what if i have this code (from a windows forms app:
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
and in that Form1 i want to create an object of type Auditer (which has a property of type ILogger marked import, and i have a class implementing ILogger marked export).
Do i have to place the MEF compose code in the void Main(), in the Load event of Form1, or in the constructor of the Auditer class?
I only get it to work when i put it (the MEF compose code) in the constructor of the Auditer class, but the examples i read somehow give me the idea that you only have to call the compose code once.
The CompositionContainer is the class that actually composes your parts in MEF.
When you want to use MEF, you need to always compose the part that's attributed with the import definitions. If you have a property in Form1 that's marked with [Import(typeof(ILogger))], at some point, you'll need to compose your Form1 instance.
The CompositionContainer is the class that actually performs this composition. It finds the appropriate exported ILogger based off the Catalog(s) contained within the container, and constructs types, matches exports to the imports, etc.
The reason that the MEF samples only "compose" one time is that, often, with DI, you'll have a single instance of the container constructed and setup at the beginning of the application, and it will compose your "main" window. All other classes will be composed automatically if they're being used as part of the main window. (For example, if Form1 composes an ILogger, but your ILogger implementation has an [Import] of it's own, it too will get composed in that pass.)
That being said, there is no fixed rule that specifies you can't compose more than once. In WPF and Silverlight, for example, it's frequent that MEF can't construct your object, which means it can't automatically compose your object for you. In these situations, a common pattern is to use the CompositionInitializer (in the box in Silverlight, not in the desktop) to have parts compose themselves, based off a static catalog. I recently blogged about this approach for WPF.
With Windows Forms, this may be less necessary, since there isn't a third party product (the XAML parser) constructing your types. However, you could still use this same approach, if you so choose.