parameterized class queue in sv

773 Views Asked by At

In my testbench there are a couple of pcie_agents which have the different lanes. I extended my own class from the pcie VIP. Something like :

class mt_pcie_agent#(int INST=0) extends pcie_agent((INTS==0)?2:(INTST==1)?4:(INST==2)?8:16);//different lanes by instance.
...
endcase

Now I want to put them into queue in my env.

class mt_env extend uvm_env;
...
mt_pcie_agent rc_agent[$:8];
...
virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  ...
  for(int i=0; i<`NUM_RC; i++) begin //`NUM_RC = 1~8
    case (i)
      0: begin
           rc_agent.push_back(mt_pcie_agent#(0)::type_id::create($sformatf("rc%0d_agent",i), this);
         end
      1: begin
           rc_agent.push_back(mt_pcie_agent#(1)::type_id::create($sformatf("rc%0d_agent",i), this);
         end
      ...
   endcase
   ...
endfunction
...
endclass

It's okay for VCS to compile these code. But since mt_pcie_agent#(0) is a different type from mt_pcie_agent#(1), I wonder whether if these code has some side-effects in run-timing?

Any help is appreciated.

1

There are 1 best solutions below

1
On

Most simulators will throw an error from type mismatch. As you recognized mt_pcie_agent#(1) is not the same type or considered an extended class of mt_pcie_agent#(0). There may be a simulator out there that only throws a warning and let you get away with it, but it is not a good practice.

You can change mt_pcie_agent rc_agent[$:8]; to uvm_agent rc_agent[$:8]; (or some intermediate non-parameter or common-parameter-value parent class of pcie_agent). A parent handle can point to a child object, but the scope of that it can access is limited. For example you will not be able to directly connect a sequencer to the agent/driver in the env's connect phase because the uvm_agent handle doesn't know the object has one to connect to or not.

You could get around this via the config_db, where you ::set the set the sequencer that will be connected to the rc_agent in env's build_phase, then ::get it in the rc_agents connect_phase.

Or, sometimes it is easier to just add rc_agent flavors to the environment and only ::create the ones you need. It is just more typing. If you specificly needed the queue of agents, you can keep it as well (two pointers to the same object). Example:

mt_pcie_agent#(0) rc0_agent;
mt_pcie_agent#(1) rc1_agent;
...
mt_pcie_agent#(7) rc7_agent;
uvm_agent rc_agent[$]; // for what ever reference
...
virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  ...
  for(int i=0; i<`NUM_RC; i++) begin //`NUM_RC = 1~8
    case (i)
      0: begin
           rc0_agent = mt_pcie_agent#(0)::type_id::create($sformatf("rc%0d_agent",i), this);
           rc_agent.push_back(rc0_agent);
         end
      1: begin
           rc1_agent = mt_pcie_agent#(1)::type_id::create($sformatf("rc%0d_agent",i), this);
           rc_agent.push_back(rc1_agent);
         end
      ...
   endcase
   ...
endfunction