Parameter overriding for env class

Hi,

I have one top_env class. This class has the array of test_env class. Both of these class(top_env & test_env) has been extended from uvm_env.
test_env class is a parameterized class. Now I want the test_env to be created with different parameter value for each array element.

E.g.
class test_env #(int DATA_WIDTH=32) extends uvm_env;

endclass

class top_env extends uvm_env;
test_env #(32) m_env_array[2];

// For e.g. m_env_array[0] should be created with DATA_WIDTH = 32 & m_env_array[1] should be created with DATA_WIDTH = 64
endclass

Is there any way to override different parameter value for m_env_array[0] and m_env_array[1]?

Thanks,
Jay

In reply to Pjay:
Each unique set of overrides of a parameterized class (a generic class) creates a unique type ( specialization). Therefore you cannot directly define an array since each element must be the same type.

You can define an array of uvm_env and then assign objects of different test_env specializations to different elements. But you probably should define an intermediate un-parameterized test_env_base class and use that for your array. Put everything that does not depend on parameterization on the base class so you can access them directly from the array element without having to down-cast it first.

In reply to dave_59:

Hi Dave,

I understand your point to have test_env_base un-parameterized class and put everything which is not dependent on parameter to this test_env_base class and access using array element.

But how to access the variables using array element which are dependent on parameter?

I want to try something like this

//========================================================================

class test_env_base extends uvm_env;

  `uvm_component_utils(test_env_base)

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass


class test_env #(int DATA_WIDTH) extends test_env_base;

  bit [DATA_WIDTH-1 : 0] var_a;

  `uvm_component_param_utils(test_env #(DATA_WIDTH))

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  function print_var();
    $display("PRINT_VAR :: var_a = %b  DATA_WIDTH = %d", var_a, DATA_WIDTH);
  endfunction
endclass


class test_super_env #(type BASE=test_env #(32))extends uvm_env;
  test_env #(32) test_env_32;
  test_env #(64) test_env_64;
  test_env_base m_env_arr[2];
  

  `uvm_component_utils(test_super_env)
  function new(string name, uvm_component parent);
    super.new(name, parent);
    test_env_32 = test_env #(32)::type_id::create("test_env_32", this);
    test_env_64 = test_env #(64)::type_id::create("test_env_64", this);

  endfunction : new

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    $cast(m_env_arr[0], test_env_32);
    $cast(m_env_arr[1], test_env_64);
  endfunction
endclass


class test1 extends uvm_test;
  test_super_env  super_env;

  `uvm_component_utils(test1)
  function new(string name, uvm_component parent);
    super.new(name, parent);
    super_env = test_super_env::type_id::create("super_env", this);
  endfunction : new

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction

  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    foreach(super_env.m_env_arr[i]) begin
      $display("%b", super_env.m_env_arr[i].var_a);
    end
  endtask
endclass

Thanks,
Jay

In reply to Pjay:

Please use code tags to make your code easier to read. I have added them for you.

You need to explain why you need to access variables inside different test_env’s from outside the component. Most of the time this is not done directly anyways. (uvm_config_db or vlm ports)

In reply to Pjay:

We’ve done many similar things both within UVM and outside UVM.
You need to define your base class, with an appropriate API that serves for all specializations. The base class will likely have pure abstract definitions, which are actual implemented in the derived class i.e.


class test_env_base extends uvm_env;
 
  `uvm_component_utils(test_env_base)
 
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  pure virtual function print_var();
endclass

class test_env #(int DATA_WIDTH) extends test_env_base;
 
  bit [DATA_WIDTH-1 : 0] var_a;
 
  `uvm_component_param_utils(test_env #(DATA_WIDTH))
 
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
 
  virtual function print_var();
    $display("PRINT_VAR :: var_a = %b  DATA_WIDTH = %d", var_a, DATA_WIDTH);
  endfunction
endclass

You can then setup and array of test_env_base, - each element could be assigned a specific (and different) specialization of test_env. Then, you can use the print_var() API without knowing the underlying details of the context.

The tricky is setting up an appropriate abstraction layer, such that the base class API is parameter agnostic.

Regards,
Mark

In reply to Mark Curry:
Hi Mark & Dave,

Thank you for your reply.

The above mentioned API method will solve my 80% issue in my environment.
Now, I have one last thing to resolve on top of this API implementation.

I have a virtual sequencer instantiated inside the environment class. And virtual sequencer is again a dependent on parameters from Env class.

I have some sequences which are running in parallel on both environment.
In test case, I have code as below to start the sequence in both the environment.


for(int i=0; i<`NUM_OF_ENV; i++) begin
  automatic int j = i;
  fork
    m_seq_handle.start(super_env.m_env_arr[j].seqr_handle);
  join_none
end

If I will get help to resolve this, it will be done.

Thanks,
Jay