$cast failed using parameterised uvm_sequence_item class

Hi,

I’m currently implementing the RAL adapter bus2reg method as shown below, and the $cast keeps failing. My ‘extended_seq_item’ class extends from a uvm_sequence_item class and is parameterised to a config class (e.g. class extended_seq_item#(type CFG = config_class) extends uvm_sequence_item;).

I have used RAL previously where my extended_sequence_item wasn’t parameterised and was working with the same code as shown below. I’ve checked that the UVM Agent analysis_port that is connected to the Register Model Predictor is sending the extended_seq_item class using the analysis_port.write() method.

 
  virtual function void bus2reg(uvm_sequence_item bus_item,
                                ref uvm_reg_bus_op rw);
    extended_seq_item ext;
    if (!$cast(ext, bus_item)) begin
      `uvm_fatal("NOT_EXT_TYPE","Provided bus_item is not of the correct type")
      return;
    end
    rw.kind = ext.we ? UVM_WRITE : UVM_READ;
    rw.addr = ext.addr;
    rw.data = ext.data;
    rw.status = UVM_IS_OK;
  endfunction: bus2reg
endclass: reg2apb_adapter
 

Why is my $cast failing when I start using parameterised uvm_sequence_item class and how do I fix this?

In reply to Po:

Your cast fails because the declaration of your seq_item in bus2reg is not parameterized. It should be like this:

  virtual function void bus2reg(uvm_sequence_item bus_item,
                                ref uvm_reg_bus_op rw);
    extended_seq_item#(type CFG = config_class) ext;
    if (!$cast(ext, bus_item)) begin

In reply to chr_sue:

I’ve tried the declaration as you’ve shown but it’s giving me syntax errors. I’ve tried the below method of declaring the extended_seq_item instead but my $cast is still failing.

Any ideas what else it could be please?


extended_seq_item#(config_class) ext;

In reply to Po:


// bus2reg
function void general_ahb_adapter::bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    // AHB main Transaction
    ahb_mst_trans#(32,32) ahb_rw = ahb_mst_trans#(32,32)::type_id::create("ahb_rw");
    
    if (!$cast(ahb_rw,bus_item)) begin
        `uvm_fatal("NOT_AHB_TYPE","Provided bus_item is not of the correct type")
        return;
    end
    if(ahb_rw.cmd == AHB_SINGLE_WR) begin
        rw.kind = UVM_WRITE;
        // Capturing data as observed by the bus monitor
        rw.data = ahb_rw.hwdata[0];
    end

I cannot see the class creation, where exactly are you creating your item ? remember both should be parameter specialized anyway.

Regards

In reply to Rsignori92:

The extended_seq_item class in this case is created in the Monitor class in the Agent and is sent to the Predictor via the analysis_ports. The analysis_ports are connected this way : Monitor → Agent → Predictor.bus_in

In theory I shouldn’t need to create the same extended_seq_item class again in the bus2reg method as the object is sent to this method and I just want to cast it to the handle of the same class (ext) hence the ‘ext’ handle should then point to the object that is sent from the Monitor for further access.

I’ve checked that the uvm_reg_predictor are instantiated with the same extended_seq_item and parameterised the same way:


uvm_reg_predictor #(extended_seq_item #(config_class)) predictor_h;

The ‘extended_seq_item’ created in the Monitor that is sent also have the same parameterisation:


extended_seq_item #(config_class) ext_in_monitor;

The analysis_ports are also created with the same parameterisation:


uvm_analysis_port #(extended_seq_item #(config_class)) ext_seq_item_ap;

Can anyone suggest if there’s anything else that I’ve missed?

In reply to Po:

Yes completely agree with you you do not need to create (my worry was that it was not sent/created or so hence a null pointer was used).

Having said that my only concern is now basically referring to the bus_item is not basically the same type as the one used for the casting in other words:

  • The item sent to the monitor is: extended_seq_item #(config_class)
  • The item grabbed by the predictor is extended_seq_item #(config_class)
  • But the item sent during the REG transaction is not the same type or not parametrised or simply the param is different (the casting is specialised something like the config_db)

For example:


class pc;
  function void display();
    $display("Parent class has no parameter to display");
  endfunction
endclass

class cc#(int Val=0) extends pc;
  function void display();
    super.display();
    $display("Parameter = %0d",Val);
  endfunction
endclass

module top;
  initial begin
    pc p;
    cc #(11) c = new();
    cc #(10) c1;
    p = c;         
    $cast(c1,p); 
    c1.display(); 
  end
endmodule

// this will result in 
/*
Error-[DCF] Dynamic cast failed
testbench.sv, 23
  Casting of source class type '\cc#(11) ' to destination class type '\cc#(10)
  ' failed due to type mismatch.
  Please ensure matching types for dynamic cast
*/

// This instead will Pass
module top;
  initial begin
    pc p;
    cc #(11) c = new();
    cc #(11) c1;
    p = c;         
    $cast(c1,p); 
    c1.display(); 
  end
endmodule

Sorry for the naming conventions it was just to be quick.

Regards

In reply to Rsignori92:

Yes I agree with you, I did have the concern of whether the param is different causing the $cast to fail. I’ve put in an additional line of code to print out the content of the object that is being passed into the bus2reg() method and it turns out that this method is being called twice.

The first time called, the extend_seq_item was passed in with the correct param and $cast did not fail. However, for some reason this method is called second time (I’m still trying to figure out who’s calling it the second time) and the uvm_sequence_item that I am using for the Driver is passed in causing the $cast to fail as they are not the same object type. The uvm_sequence_item is only used in the reg2bus() method for the Driver to drive transactions to the DUT so I’m not sure how the Predictor end up getting this object and passing it to the bus2reg() method.

Any suggestions on what may be causing this?

In reply to Po:

Anytime you send a TRX from the RAL to the DUT the bus2reg is called after monitoring the bus activity (now I’m now aware of your ENV structure).

Anyway


// You have something like this:
/*
REG_WRITE/READ -> REG_MAP -> ADAPTER_REG_2_BUS -> SEQUENCER -> DRIVER -> DUT
BUS_MONITOR -> PREDICTOR (if explicit and hooked up) -> ADAPTER_BUS_2_REG -> REG_ITEM -> REG in map
*/

-- according to this diagram you will be spotting 1 call only of bu2reg unless another TRX is coming or someone else is stimulating your BUS. This depends on your environment basically since there could be 2 or more clients trying to create some BUS activity or basically your BUS monitor is not properly handling the bus activity.

-- AHB for instance detects bus activity based on the HTRANS hence is unique per TRX

Regards

In reply to Rsignori92:

Yes I agree that the bus2reg should only be called once after monitoring the bus activity. I’m tracing it back to the UVM source code where the Predictor calls adapter.bus2reg after Monitor completes monitoring the bus activity. The extended_seq_item class was successfully passed into the bus2reg function in the Adapter and $cast is successful.

However, I’m also seeing that the bus2reg is also called (after the above call) within the ‘uvm_reg_map’ class in the ‘do_bus_write’ and ‘do_bus_read’ tasks, but this time the uvm_sequence_item class that the Driver is using is passed into the bus2reg function causing $cast to fail.

At the moment, I have two identical UVM Agents instantiated in the UVM Environment (but I’m only using one of them to drive transactions), and I’m only calling rm.reg.write() method in my uvm_sequence once.

I’m not sure why the uvm_reg_map is calling the bus2reg function from the Adapter and why the the uvm_sequence_item class used by the Driver is passed into it? Also, am I suppose to use the same uvm_sequence_item class for the Driver and Monitor?