Mixing classes

I came across this post in accellera website by a member. Just wondering how is this more useful than overriding a sequence item if required. Does anyone has a point?

class derived_class#(type BASE=base_class) extends BASE;

....

endclass : derived_class

This pattern was inspired by some C++ Boost code I saw, where the base class is templated. The reasoning was that under some compilers, multiple inheritance had higher overhead than chains of inheritance (specifically, an “empty” base class might be allocated the minimum size, so multiple inheritance would increase the size of the object, but if you used a chain of inheritance and a derived class in the chain was “empty” (i.e. did not add any data members), it would not increase the object size). So instead of inheriting from multiple C++ classes, you’d typedef a class like foo<bar > and derive from that.

Since SystemVerilog has no multiple inheritance, I thought this pattern would be appropriate for use in SV, to at least ease some of the “oh no SV has no multiple inheritance oh no” pain.

I’ve defined a simple utility class, utility::slave_sequence_item (utility is a package) defined like so:

class slave_sequence_item#(type BASE=uvm_sequence_item) extends BASE;

local uvm_barrier wait_barrier_;

local uvm_barrier fin_barrier_;

`uvm_object_param_utils_begin(utility::slave_sequence_item#(BASE))

    `uvm_field_object(wait_barrier_, UVM_ALL_ON)

    `uvm_field_object(fin_barrier_, UVM_ALL_ON)

`uvm_object_utils_end

function new(string name="");

    super.new(name);

    wait_barrier_ = new("wait_barrier_", 2);

    fin_barrier_ = new("fin_barrier_", 2);

endfunction



// to be called by sequence

task wait_for_transaction;

    wait_barrier_.wait_for;

endtask

task finish_transaction;

    finish_barrier_.wait_for;

endtask

// to be called by driver

task indicate_transaction;

    wait_barrier_.wait_for;

    finish_barrier_.wait_for;

endtask

endclass : slave_sequence_item

Basically, this slave sequence item class adds three new methods. By default, you just derive from utility::slave_sequence_item. But if you already have an existing sequence item type derived from uvm_sequence_item, you just do typedef utility::slave_sequence_item#(my_sequence_item) my_slave_sequence_item; and the added methods and variables will get “mixed in” the my_slave_sequence_item type.