Quantcast
Channel: UVM SystemVerilog Discussions Forum RSS Feed
Viewing all articles
Browse latest Browse all 410

"Mixin" classes - parametrizing the base class

$
0
0

Hi UVM and SystemVerilog users,

 

I've stumbled upon a particular pattern of writing a "utility" class, which I have called "mixin".

 

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<nitz> > 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_ojbect_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.

 

What do you think?

 

I've tested it on Cadence IUS10.20-s103, and it seems to work properly.  From my understanding of the IEEE standard, the above is not specifically disallowed (but then it might not be well supported on actual simulators).

 


Viewing all articles
Browse latest Browse all 410

Latest Images

Trending Articles



Latest Images