Wednesday, September 3, 2014

In the last post I talked about interface classes and how they can be used to separate what an object "can" do from "how" it does it. While using interface classes helps a lot in developing code that is modular and reusable, there are still things that are missing. In this discussion on LinkedIn, Ilia makes a very good observation with respect to extendibility. If we extend a base class (in our case, uvm_component), how can we propagate all of these changes to its subclasses (namely uvm_monitor, uvm_driver, etc.)? This is exactly the kind of problem which could be solved with multiple inheritance. Unfortunately, SystemVerilog doesn't support multiple inheritance, so I guess we're out of luck...

Just kidding, as you could probably tell from the title. We can use the tools at our disposal (i.e. single inheritance) to emulate multiple inheritance. The pattern we're going to look at is called a 'mixin'. What better way to illustrate what a mixin is than by looking at an example.

Let's say we want to enforce a rule that all ports of our UVM components are connected before the run phase starts. We create our own super-library based on UVM that contains this addition (and potentially more). We can add such a check to uvm_component by creating a subclass:

classvgm_uvm_componentextendsuvm_component;functionnew(stringname,uvm_componentparent);super.new(name,parent);endfunctionfunctionvoidstart_of_simulation_phase(uvm_phasephase);check_ports();endfunctionfunctionvoidcheck_ports();`uvm_info("VGM","I'm checking if all of my ports are connected",UVM_LOW);endfunctionendclass

We added the check_ports() function that makes sure that all ports are connected and we called it during the start_of_simulation phase. This will work fine for any class that extends directly from vgm_uvm_component. However, we also want to be able to extend from uvm_driver, uvm_monitor, uvm_agent, etc. These are subclasses of uvm_component, which may not provide too much now, but could potentially do more in future versions of UVM. It also makes our code's intent much clearer. What we need are vgm versions of these classes as well. The simplest way we could do this is by creating one subclass for each, where we copy the additions we made to uvm_component:

classvgm_uvm_monitorextendsuvm_monitor;functionnew(stringname,uvm_componentparent);super.new(name,parent);endfunctionfunctionvoidstart_of_simulation_phase(uvm_phasephase);check_ports();endfunctionfunctionvoidcheck_ports();`uvm_info("VGM","I'm checking if all of my ports are connected",UVM_LOW);endfunctionendclass

We'd have to do something similar for each uvm_* class, which you'll probably agree is a lot of work. Not only that, but should we find a bug in our code (maybe the check_ports() function isn't working properly), we'd have a lot of places to patch to fix it. This is basically why copy-pasting code is a cardinal sin in the software development world. Sure, we could define the added code as a macro and just include it in every class, but excessive preprocessor use is also something to be avoided.

It sure would be nice if we could make uvm_monitor inherit the changes as well, wouldn't it? It turns out that this is possible. As mentioned above, what we have to do is use a 'mixin'. What we were basically doing above was inheriting from each member of the UVM component class family. Well, why not just make the base class a parameter? Something like:

classvgm_check_ports_mixin#(typeT=uvm_component)extendsT;functionnew(stringname,uvm_componentparent);super.new(name,parent);endfunctionfunctionvoidstart_of_simulation_phase(uvm_phasephase);check_ports();endfunctionfunctionvoidcheck_ports();`uvm_info("VGM","I'm checking if all of my ports are connected",UVM_LOW);endfunctionendclass

We can then create our vgm_* class family by just parameterizing this mixin with the appropriate base class:

We can do this for any UVM component subclass. In our business code, instead of inheriting from uvm_monitor we'll inherit from vgm_uvm_monitor and so on.

I want to take a short break here and give credit where credit is due. The idea isn't mine, as mixins are already used in the software development world. I first heard of them and saw them implemented in SystemVerilog in this thread in the UVM forums. Reading it made me really excited as this technique opens up a whole new world of possibilities.

We've seen how we can use mixins to propagate additions to a base class down along its inheritance hierarchy. Let's now have a look at a slightly different example. In the last post I mentioned how interface classes can be used to write a much cleaner implementation of TLM. The code I showed was:

This snippet describes "what" each port can do (by enumerating the methods it has), but side-steps "how" it does it. Some of you may have probably been asking yourselves the following question: "Won't we have to repeat the same implementation of get(...) (for example) in both uvm_blocking_get_port and in uvm_get_port?". The answer is "Yes, we could, but as before, there's a better way". Let's do like in the previous case and start with the "bad" solution and refine it as we go.

A TLM port per definition forwards a method call on it to its connected implementation. This might be another port (which in turn forwards) or an end component which provides the actual implementation. What we first need is some solid ground to stand on. Let's define a base class that handles connecting and holding the implementation:

This code may not be much (and it will also most likely not change over time), so it might seem harmless. I might even tend to agree in this case, but just think what it would mean if the method definitions were more complicated...

This is another typical case where multiple inheritance would be extremely useful. If we could inherit from both the blocking and the non-blocking ports, we could have our "full" get port without any code duplication. Mixins helped us last time, so let's use them here as well.

Similarly to what we did for the UVM components, we'll implement the additions we make to the tlm_get_port_base class as mixins. First, let's implement the blocking get mixin:

Again, this is pretty much the non-blocking get port class, but with a parameterized base class. Implementing the get ports becomes pretty trivial; we just need to add our mixins to the appropriate base classes:

For the blocking and non-blocking ports we didn't even need to specify the base class, as we used the default values of the parameters. The "full" get port is just a blocking get port with a non-blocking mixin on top (or the other way around; either works). We just have to be careful that the class at the very base is parameterized with the proper implementation type (i.e. tlm_get_if). This is pretty much it. No duplication, less code to maintain and (pretty) easy to understand as well.

Let's summarize what we've learned. Even though SystemVerilog doesn't provide multiple inheritance, using the mixin pattern we can emulate it by using only single inheritance. Mixins can help us propagate extensions down along a class hierarchy (as we did for the UVM component class family). They can also be used to create a class that inherits from two (or even more) parallel sub-classes while avoiding the diamond problem. I for one intend to use more mixins in my code and maybe so should you.

I've added the mixin code, together with some test harnesses and the "bad" code to the blog repository, for those who want to check it out.

About

I am a Verification Engineer at Infineon Technologies, where I get the chance to work with both e and SystemVerilog.
I started the Verification Gentleman blog to store solutions to small (and big) problems I've faced in my day to day work. I want to share them with the community in the hope that they may be useful to someone else.