Jump to content


  • Posts

  • Joined

  • Last visited

Reputation Activity

  1. Like
    enchanter reacted to alangloria in "Mixin" classes - parametrizing the base class   
    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_field_object(wait_barrier_, UVM_ALL_ON)
            `uvm_field_object(fin_barrier_, UVM_ALL_ON)
        function new(string name="");
            wait_barrier_ = new("wait_barrier_", 2);
            fin_barrier_ = new("fin_barrier_", 2);
        // to be called by sequence
        task wait_for_transaction;
        task finish_transaction;
        // to be called by driver
        task indicate_transaction;
    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).
  2. Like
    enchanter reacted to Philipp A Hartmann in How to pass modified Template argument to sub module?   
    I don't understand, why using the top module with different values of TOP_DEPTH is a showstopper for declaring the DEPTH_MODULE_xxx as static members of my_top.
    Integer template arguments have to be known at compile-time in order to instantiate the correct type.  Would something like the following be sufficient for your situation?
    template <int DEPTH=10> SC_MODULE(sub_module_xxx); template <int TOP_DEPTH=10> SC_MODULE(my_top) { static const int depth = TOP_DEPTH; // I usually forward template constants to proper member constants static const int depth_a = depth + 1; // or other math on depth static const int depth_b = depth / 2; // ... sub_module_a<depth_a> sub_a; // no need for pointers? sub_module_b<depth_b> sub_b; SC_CTOR(my_top) : sub_a("sub_a") // initialize sub-modules , sub_b("sub_b") {} }; int sc_main(int, char*[]) { my_top<17> t1("t1"); my_top<42> t2("t2"); sc_assert( t1.depth == 17 && t1.depth_a == 18 ); sc_assert( t2.depth == 42 && t2.depth_b == 21 ); return 0; } Greetings from Oldenburg,
  • Create New...