Factory type override of sequence item does not work

Hi,

Can Factory override the uvm_sequence_item ?
Following code does not override the sequence item type used by the driver class.
set_type_override_by_type(mem_seq_item::get_type(), child_seq_item::get_type());

I can’t get the child_seq_item item in Driver. So I add child_seq_item csi; in the driver for a workaround.

  child_seq_item csi;

Any clue why Factory override does not work ?

This is the code.

class mem_seq_item extends uvm_sequence_item;

  rand bit [1:0] addr;
  ...

  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
   ...
  `uvm_object_utils_end
  
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  
endclass



class child_seq_item extends mem_seq_item;

   rand bit [7:0] A;
   rand bit [7:0] B;
   ...
  
  `uvm_object_utils_begin(child_seq_item)
    `uvm_field_int(A,UVM_ALL_ON)
     ...
  `uvm_object_utils_end
  
  function new(string name = "child_seq_item");
    super.new(name);
  endfunction
  
endclass


Here is sequence

class mem_sequence extends uvm_sequence#(mem_seq_item);
 ...
endclass

class my_sequence extends mem_sequence;
  
   child_seq_item  child_item;
  `uvm_object_utils(my_sequence)
   
  function new(string name = "my_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    child_item = child_seq_item::type_id::create("child_item");

    `uvm_do(child_item)
     child_item.print();
  endtask
endclass

And I execute the sequence in my test class.

class mem_wr_rd_test extends mem_model_base_test;

  `uvm_component_utils(mem_wr_rd_test)
  mem_sequence seq;

  function new(string name = "mem_wr_rd_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

 
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
      seq = mem_sequence::type_id::create("seq");
  endfunction : build_phase
  
  task run_phase(uvm_phase phase);
    
    phase.raise_objection(this);
      seq.start(env.mem_agnt.sequencer);
    phase.drop_objection(this);
    
    //set a drain-time for the environment if desired
    phase.phase_done.set_drain_time(this, 50);
  endtask : run_phase
  
endclass 

class my_test extends mem_wr_rd_test;

  `uvm_component_utils(my_test)
  my_sequence my_seq;

  function new(string name = "my_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

  virtual function void build_phase(uvm_phase phase);
    set_type_override_by_type(mem_seq_item::get_type(), child_seq_item::get_type()); 
    super.build_phase(phase);

    // Create the sequence
    my_seq = my_sequence::type_id::create("my_seq");
  endfunction : build_phase
  
 
  task run_phase(uvm_phase phase);
    
    phase.raise_objection(this);
      my_seq.start(env.mem_agnt.sequencer);
    phase.drop_objection(this);
    
    //set a drain-time for the environment if desired
    phase.phase_done.set_drain_time(this, 50);
  endtask : run_phase
  
endclass 

This is the Driver.

class mem_driver extends uvm_driver #(mem_seq_item);
  child_seq_item csi;
  virtual mem_if vif;
  `uvm_component_utils(mem_driver)
  
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
      csi = child_seq_item::type_id::create("csi", this);
  endfunction: build_phase

  virtual task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      drive(req);
       `DRIV_IF.addr <= req.addr; 
       `DRIV_IF.addr <= req.B; //<======!!!! HERE, I can't get the item B.!!!!!!!
       `DRIV_IF.addr <= csi.B; 
      seq_item_port.item_done();
    end
  endtask : run_phase
  
   virtual task drive(input mem_seq_item trans );
    `DRIV_IF.wr_en <= 0;
    `DRIV_IF.rd_en <= 0;
    @(posedge vif.DRIVER.clk);
    
    `DRIV_IF.addr <= trans.A; //<======!!!! HERE, I can't get the item A.!!!!!!!
    
    if(req.wr_en) begin // write operation
      `DRIV_IF.wr_en <= req.wr_en;
      `DRIV_IF.wdata <= req.wdata;
      @(posedge vif.DRIVER.clk);
    end
    else if(req.rd_en) begin //read operation
    ...

In reply to UVM_LOVE:

Can Factory override the uvm_sequence_item ?

It surely can !

It would be easier for me if you could share an edaplayground link of your complete code .

In reply to ABD_91:

The override replaces the object that is created at runtime. However, at compile time, you need to use the right handle type. Your driver is specialized to use the base type but you have hardcoded references to properties A and B that only exist in the child class. This driver uses child_seq_item properties, so declare it that way.

class mem_driver extends uvm_driver #(child_seq_item);

Or move the properties A and B from the child class into the base class.

In reply to chrisspear:

One could also use dynamic cast in driver and if it’ successful , access those extended class properties .

The $cast would be successful only if the override takes effect .

In reply to ABD_91:

I thought about that, and it works if you don’t always need properties from the derived class. The way the code was written, with the derived handle at the class level, makes it look like it always needs these properties, so why not declare the driver that way. But then the sequence and sequencer also need to be specialized with the derived type.

In reply to chrisspear:

But then the sequence and sequencer also need to be specialized with the derived type.

I believe as long as ::

  • Specialization of driver - sequencer ( via TLM ) are of base REQ type
  • Argument to start_item , finish_item in the sequence is Cast Compatible with REQ type of sequencer
  • and we override the base-type with extended-type from Top component like test class

the TB need not be changed i.e using the base class ( REQ type parameter ) specialization for driver , sequencer and sequence it would still work

EDIT : Dynamic cast logic would be required within driver to access extended class properties .

In reply to ABD_91:

What is the exact problem you are seeing? The code you gave won’t compile.

virtual task drive(input mem_seq_item trans );
    `DRIV_IF.wr_en <= 0;
    `DRIV_IF.rd_en <= 0;
    @(posedge vif.DRIVER.clk);
 
    `DRIV_IF.addr <= trans.A; //<======!!!! HERE, I can't get the item A.!!!!!!!

Forget about overrides. The handle trans is the base type and does not have an A member, so this code can not compile. If that property is needed to drive the interface, move it from the child_seq_item to the mem_seq_item. It’s like you have a base Animal handle and are trying to use a property that only exists in the derived class like ‘horn’ or ‘gills’.

Once you have code that compiles, let us know the result.

In reply to chrisspear:

As I had replied earlier : To access the extended class property a dynamic cast would be required .


virtual task drive(input mem_seq_item trans );
 child_seq_item  ext_item ;

    `DRIV_IF.wr_en <= 0;
    `DRIV_IF.rd_en <= 0;
    @(posedge vif.DRIVER.clk);
 
    if ( $cast( ext_item , trans ) ) begin

      `DRIV_IF.addr <= ext_item.A;
       .........
    end

My last reply was related to your comments " then the sequence and sequencer also need to be specialized with the derived type."

I do agree that the way driver logic has been coded , it would be better to specialize driver , sequencer and sequence with extended type parameterization .

But if the user insists of using base type parameterization and use a factory override , they would require to add the $cast logic within driver class .

In reply to ABD_91:

Where do things stand now? Does the testbench compile and simulate?

If the user insists on base type parameterization, have them look at this SystemVerilog blog that I wrote on the topic.

In reply to chrisspear:

Where do things stand now? Does the testbench compile and simulate?

We have provided our inputs , I think this is for the user to check and confirm .