Passing objects around

Hi there,

I’m trying to encapsulate a set of configuration variables into a class that I could pass around through various other classes methods, but I’m afraid this is an anti-pattern of OOP and I would like to find out a different way.
To make it more specific, here is an example. Let’s define a config class:


class config extends uvm_object;
  `uvm_object_utils(config)

  int unsigned field0;
  int unsigned field1;

  function new (string name = "config");
    super.new(name);
  endfunction // new      

  function set_default();
    field0 = DEFAULT_FIELD0;
    field1 = DEFAULT_FIELD1;
  endfunction // set_default

  function set_fields(int unsigned f0, int unsigned f1);
    this.field0 = f0;
    this.field1 = f1;
  endfunction // set_fields
endclass

Now if I would like to pass it to my sequence class in order to be able to ‘send’ it to the DUT. Assuming the config class has been created and configured by the testcase (uvm_test object), I could pass get it in the sequence in the following way:



class my_sequence extends uvm_sequence;
  `uvm_object_utils(my_sequence)

  config cfg;

  function new(string name = "my_sequence");
    super.new(name);
  endfunction // new

  function get_config(config cfg);
    this.cfg = cfg;
  endfunction // get_config

  task body();
    this.cfg.set_defaults();
    // ... `uvm_do something
  endtask // body

endclass


Now assuming that my_sequence is sitting on top of a 2/3 other base classes and that my config needs to be passed all the way down before actually be sent to the sequencer as a transaction, each of which is further adding and checking the configuration, I ask myself whether I really need to pass it through the methods interface (get_config).

One of the major drawback of this approach is that my_sequence is now ‘bound’ to the config class, making it difficult to make one evolve without touching the other, therefore violating the ‘S’ in S.O.L.I.D. OOP. So even if now my objects are all registered in the factory, I would still have issues when I want to port the environment in another project and I need to change the config class. Using set_type_override_type is not sufficient, I would also need to override my_sequence, together with all the other base classes it derives from, essentially removing any benefit of ‘reusability’ (I could simply avoid to override and reproduce the whole set of classes.

To add complexity to the table, if the newly defined config class needs to have different methods signatures because there simply are different parameters, I’m kind of stuck, since SV polymorphism doesn’t allow for different signatures, so while the set_defaults() method is ok, the set_fields() one will have to be different therefore I cannot simply override my config class during build_phase.

Since we are talking about ‘overriding’ classes, would you think that is a good approach for porting the environment to a different project? Ideally I would like to reuse the same environment, just ‘overriding’ the specific classes that need to be changed, without the need to change everything (as I showed here).

Therefore my bottom line question is how can I be able to encapsulate variables in a class, be able to override it with different ‘versions’ of the class and have my environment handle this overridden class without the need to rewrite the whole environment.

Any reference/suggestion/comment is appreciated.

Al

In reply to abs:
I think you went a-stray as soon as you defined a set_fields() method with arguments for all the fields. You need to break that up into individual mutator methods.

Another possibility is to use interface classes. See Redirecting…

and Design Patterns by Example for SystemVerilog Verification Environments Enabled by SystemVerilog 1800-2012 (look at the strategy pattern as an alternative to composition).