"Cannot evaluate parameter override" error is occured when overriding parameter in a class

When I has compiled below code, an error has occured:

Error-[NCE] Non-constant expression
The following expression should be a constant.
Expression: $psprintf(“dti_axi4lite_m_burst #(%1d, %1d)”,
AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)
“…/libs/dti_axi4lite_vip/master/uvm/dti_axi4lite_m_burst.sv”, 26
Source info: localparam TYPE_NAME = $psprintf(“dti_axi4lite_m_burst
#(%1d, %1d)”, AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH);

Code is here:

22. class dti_axi4lite_m_burst #(
23.   parameter   AXI4LITE_ADDR_WIDTH = 32,
24.   parameter   AXI4LITE_DATA_WIDTH = 32
25. ) extends uvm_sequence_item;
26.     localparam  TYPE_NAME = $psprintf("dti_axi4lite_m_burst #(%1d, %1d)", AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH);
27.   `dti_axi4lite_object_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH), TYPE_NAME)
28.
29. <code here>
30. 
31. endclass

Where `dti_axi4lite_object_utils is a macro which is defined in other file:

`define dti_axi4lite_object_utils(T, S) \
  typedef uvm_object_registry#(T, S) type_id; \
  static function type_id get_type(); \
    return type_id::get(); \
  endfunction \
  virtual function uvm_object_wrapper get_object_type(); \
    return type_id::get(); \
  endfunction \
  `m_uvm_object_create_func(T) \
  `m_uvm_get_type_name_func(T) \
  `uvm_field_utils_begin(T) \
  `uvm_object_utils_end

If i replace TYPE_NAME at line 27 with string “dti_axi4lite_m_burst #(12, 32)”, it is ok. But I want above code is flexible with other parameter values.

Please help me debug this error.

In reply to watashi:
It’s a little bit confusing what you are doing with your macros, because your individual macros are not needed. The UVM is providing already these mechanisms with UVM macros.
But your problem is the localparam declaration. If you move this to the parameters in the class definition it will work.
BTW, please use code tags to make your code more readable.

In reply to chr_sue:
Thanks chr_sue for supporting.
The dti_axi4lite_object_utils is a user defined macro to register a user defined uvm component. I have declared it in a file to reused at any where.

If I change
localparam TYPE_NAME = $psprintf(“dti_axi4lite_m_burst #(%1d, %1d)”, AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH);
to
static string TYPE_NAME = $sformatf(“dti_axi4lite_m_burst #(%1d, %1d)”, AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH);

An error has occour:
Error-[CEPO] Cannot evaluate parameter override
…/libs/dti_axi4lite_vip/master/uvm/dti_axi4lite_m_burst.sv, 31
The parameter override should be an expression containing only constant
numbers and previously defined parameters.
The override was applied to parameter ‘Tname’ of instance
‘dti_dynamo_axi4l_pkg.dti_axi4l_adapter_reg2bus_burst.type_id’.
Source info:
uvm_pkg::uvm_object_registry#(dti_axi4lite_m_burst#(AXI4LITE_ADDR_WIDTH,
AXI4LITE_DATA_WIDTH) , \this .TYPE_NAME)

Are you want to move `dti_axi4lite_object_utils macro into class dti_axi4lite_m_burst ?

In reply to watashi:

What I mean is the following. Change your definition to this:

 class dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH = 32, AXI4LITE_DATA_WIDTH = 32, 
    TYPE_NAME = $psprintf("dti_axi4lite_m_burst #(%1d, %1d)", AXI4LITE_ADDR_WIDTH,
    AXI4LITE_DATA_WIDTH) extends uvm_sequence_item;

In reply to chr_sue:
I have update code follow your ideal, but compilation error still has occured.

Error-[NCE] Non-constant expression
The following expression should be a constant.
Expression: $psprintf(“dti_axi4lite_m_burst #(%1d, %1d)”,
AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)
“…/libs/dti_axi4lite_vip/master/uvm/dti_axi4lite_m_burst.sv”, 25
Source info: ) extends uvm_sequence_item;

Seem return value from $psprintf task is not accepted as a parameter.

In reply to watashi:

The $psprintf returns a string. Did you check what your psprintf is returning? Is there a space inside?

In reply to chr_sue:

Yes, $psprintf return a exact string, and that string is used in UVM macro uvm_object_registry#(T, Tname) to create a type. But seem Tname argument of uvm_object_registry can not be accept to overide.
I have replaced dti_axi4lite_object_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH), TYPE_NAME) with UVM macro uvm_object_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)), and print factory, it show registered type is:
dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)
Why does’t registered type is dti_axi4lite_m_burst #(12, 32) instead of dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH) ?

In reply to watashi:
If you want to register a parameterized object you have to use

`uvm_object_param_utils

In reply to chr_sue:

I have replace with: `uvm_object_param_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)). But it has not registered type of dti_axi4lite_m_burst in factory.

In reply to chr_sue:
I have replace with: `uvm_object_param_utils(dti_axi4lite_m_burst #(12, 32)) but that error still appear.

In reply to watashi:

I had a closer look to your code and have a question. What is the need of your localparam TYPE_NAME?

In reply to chr_sue:
uvm_object_registry#(T, S) macro is a UVM defined macro to register a type to factory. In which, T is type, and S is string of T name. In my code, i generate a param TYPE_NAME to represent name of T which is pass to S argument.

Therefore, you see here:

localparam TYPE_NAME = $psprintf(“dti_axi4lite_m_burst #(%1d, %1d)”, AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH);
`dti_axi4lite_object_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH), TYPE_NAME)

And

`define dti_axi4lite_object_utils(T, S)
typedef uvm_object_registry#(T, S) type_id; \

I have try a simple way is using `uvm_object_param_utils instead of implement full uvm_object_registry macro. And it has an error which you saw above.

In reply to watashi:

$psprintf need to be placed in an procedural bock for it to work. E.g. initial/function/task. While macro expansion works at probably compile/elaboration. This cannot be used!

UVM code also does not implement type_name/get_type_name() for parameterized classes. Refer `uvm_*_param_utils() macro for this. Either use your macros without String argument, in that case type_name based override will not be possible(same as UVM code) for parameterized class.

You could try using define in place of parameters and use below code, from UVM base class, and see if it works.. This basically converts anything to a string. Not sure of order for define and "S" as which will be resolved first.

`define m_uvm_component_registry_internal(T,S) \
   typedef uvm_component_registry #(T,`"S`") type_id; \
   static function type_id get_type(); \
     return type_id::get(); \
   endfunction \

If this does not work, then you are better without string argument to uvm_object_registry class.

`define m_uvm_object_registry_param(T) \
   typedef uvm_object_registry #(T) type_id; \
   static function type_id get_type(); \
     return type_id::get(); \
   endfunction \
   virtual function uvm_object_wrapper get_object_type(); \
     return type_id::get(); \
   endfunction

In reply to MayurKubavat:
Dear MayurKubavat
I have tried 2 way but nothing change.
When i haven’t use my macro: `dti_axi4lite_object_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH), TYPE_NAME):

  • if I use `uvm_object_utils (dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)), factory printed:
    dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)

  • if I use `uvm_object_param_utils (dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)), factory printed nothing. Seem it has not registered with factory.

Why that?

In reply to watashi:

See this piece of code. Does this match your intent?

 import uvm_pkg::*;
 `include "uvm_macros.svh"

 class dti_axi4lite_m_burst #(parameter AXI4LITE_ADDR_WIDTH = 32, parameter AXI4LITE_DATA_WIDTH = 32) extends uvm_sequence_item;
   `uvm_object_param_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH))

 function new (string name = "");
   super.new(name);
 endfunction  


endclass

module top #( AXI4LITE_ADDR_WIDTH = 32, AXI4LITE_DATA_WIDTH = 32);
 dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH) dti;
initial begin
  dti = new("dti");
  
 `uvm_info("ID", $sformatf("dti #(%1d, %1d)", AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH), UVM_LOW)
end
endmodule

In reply to chr_sue:
I have implemented code similar to your idea.

class dti_axi4lite_m_burst #(
  parameter AXI4LITE_ADDR_WIDTH = 32,
  parameter AXI4LITE_DATA_WIDTH = 32
) extends uvm_sequence_item;
  `uvm_object_param_utils(dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH))

And in top:

initial begin
  `uvm_info("ID", $sformatf("dti_axi4lite_m_burst #(%1d, %1d)", `CFG_AXI4LITE_ADDR_WIDTH, `CFG_AXI4LITE_DATA_WIDTH), UVM_LOW);
end

Result of uvm_info is: UVM_INFO ../src/top/dti_dynamo_tb.sv(124) @ 0.0 ps: reporter [ID] dti_axi4lite_m_burst #(12, 32). Its correct. But uvm_object_param_utils still can not register type of class to factory.

In reply to watashi:

How do you see it is not registered with the factory?

In reply to chr_sue:

In reply to watashi:
How do you see it is not registered with the factory?

I use factory.print() to display registered type.

  • if I use `uvm_object_utils (dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)), factory printed:
    dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)

  • if I use `uvm_object_param_utils (dti_axi4lite_m_burst #(AXI4LITE_ADDR_WIDTH, AXI4LITE_DATA_WIDTH)), factory printed nothing.