Parametrization

what will happen if we didn’t parametrize driver and sequencer to the transaction type and why shouldn’t we parametrize other testbench components?

The uvm_driver and sequencer base classes contain ports and exports members that are parametrized with a generic transaction type. If you didn’t parametrized these classes, you would have to cast the transaction to the actual type before accessing specific members. People do parameterize other testbench components, but usually they are written specifically for a particular type that they declare the class specializations inside that class.

In reply to dave_59:

Will you be able to provide small example to explain “People do parameterize other testbench components, but usually they are written specifically for a particular type that they declare the class specializations inside that class.”? How that will help I just want to understand that.

In reply to Digesh:

The uvm_driver class is just

class uvm_driver #(type REQ=uvm_sequence_item,
                   type RSP=REQ) extends uvm_component;
  uvm_seq_item_pull_port #(REQ, RSP) seq_item_port;

  uvm_analysis_port #(RSP) rsp_port;

  REQ req;
  RSP rsp;

  function new (string name, uvm_component parent);
    super.new(name, parent);
    seq_item_port    = new("seq_item_port", this);
    rsp_port         = new("rsp_port", this);
  endfunction

  const static string type_name = "uvm_driver #(REQ,RSP)";
  virtual function string get_type_name ();
    return type_name;
  endfunction

endclass

Let say you want to create a different kind of driver with two different seq_item_pull ports and no response port.

class my_driver extends uvm_component;
  `uvm_component_utils(my_driver)
  uvm_seq_item_pull_port #(my_req_type1, my_rsp_type1) seq_item1_port;
  uvm_seq_item_pull_port #(my_req_type2, my_rsp_type2) seq_item2_port;

  my_req_type1 req1;
  my_req_type2 req2;
  my_rsp_type1 rsp1;
  my_rsp_type2 rsp2;

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

  endfunction

  function void build_phase(uvm_phase phase);
    seq_item1_port    = new("seq_item1_port", this);
    seq_item2_port    = new("seq_item2_port", this);
    ...
  endfunction

  task run_phase(uvm_phase phase);
    fork
       forever send1; // tasks that would get their respective items from each sequencer
       forever send2;
    join
  endtask
endclass

You could do something similar a monitor or coverage collector, etc. The key is the component is written with specific transaction classes in mind.

In reply to :

Yes, but why do this unnecessary step and get the correctly typed class in the first place? Also, you will get compiler errors if you do not get it right, otherwise a $cast error is at run-time.

In reply to dave_59:

can i have multiple seq_item_port in a single driver class and should i extend this drver class from uvm_component and not from uvm_driver?