UVM utility macros

I am a bit confused as to why field macros need to be embedded within object utils as shown below:

`uvm_object_utils_begin(simple_item)
 `uvm_field_int(addr, UVM_ALL_ON)
 `uvm_field_int(data, UVM_ALL_ON)
 `uvm_field_int(delay, UVM_ALL_ON)
`uvm_object_utils_end

Those are the Field Automation macros, which we recommend you not use. Just use

`uvm_object_utils(simple_item)

In reply to verif_learner:

To see why we don’t recommend these macros, see the amount of code these 5 macros expand to, The reason for the _begin/_end macros is they are defining a __m_uvm_field_automation function, and each field expands code as part of that function. The overhead is not just in the generated code, but in all the function calls added by the macros.

//`uvm_object_utils_begin(simple_item)
typedef uvm_object_registry#(simple_item,"simple_item") 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           
function uvm_object create (string name="");
   simple_item tmp;
   tmp = new();
   if (name!="")         tmp.set_name(name);
   return tmp;
endfunction         const static string type_name = "simple_item";
virtual function string get_type_name ();
   return type_name;
endfunction   
       
function void __m_uvm_field_automation (uvm_object tmp_data__, 
     			  		int what__,                                      
					string str__);
   begin
      simple_item local_data__;
      typedef simple_item ___local_type____;
      string string_aa_key;
      uvm_object __current_scopes[$];
      if(what__ inside {UVM_SETINT,UVM_SETSTR,UVM_SETOBJ}) begin
         if(__m_uvm_status_container.m_do_cycle_check(this)) begin
            return;
         end
         else              
	   __current_scopes=__m_uvm_status_container.m_uvm_cycle_scopes;
      end
      super.__m_uvm_field_automation(tmp_data__, what__, str__);
      if(tmp_data__ != null) if(!$cast(local_data__, tmp_data__)) return;
      
//`uvm_field_int(addr, UVM_ALL_ON)
     begin
      case (what__)        UVM_CHECK_FIELDS:          begin
            __m_uvm_status_container.do_field_check("addr", this);
          end
        UVM_COPY:          begin
            if(local_data__ == null) return;
            if(!((UVM_ALL_ON)&UVM_NOCOPY)) addr = local_data__.addr;
          end
        UVM_COMPARE:          begin
           if(local_data__ == null) return;
           if(!((UVM_ALL_ON)&UVM_NOCOMPARE)) begin
              if(addr !== local_data__.addr) begin
                 void'(__m_uvm_status_container.comparer.compare_field("addr", addr, local_data__.addr, $bits(addr)));
                 if(__m_uvm_status_container.comparer.result && (__m_uvm_status_container.comparer.show_max <= __m_uvm_status_container.comparer.result)) return;
              end
           end
        end
        UVM_PACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
           if($bits(addr) <= 64) __m_uvm_status_container.packer.pack_field_int(addr, $bits(addr));
           else __m_uvm_status_container.packer.pack_field(addr, $bits(addr));
        end
        UVM_UNPACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
           if($bits(addr) <= 64) addr =  __m_uvm_status_container.packer.unpack_field_int($bits(addr));
           else addr = __m_uvm_status_container.packer.unpack_field($bits(addr));
        end
        UVM_RECORD:             if(!((UVM_ALL_ON)&UVM_NORECORD)) begin
	   __m_uvm_status_container.recorder.record_field("addr", addr,  $bits(addr), uvm_radix_enum'((UVM_ALL_ON)&(UVM_RADIX)));
	end
        UVM_PRINT:          if(!((UVM_ALL_ON)&UVM_NOPRINT)) begin
           __m_uvm_status_container.printer.print_int("addr", addr, $bits(addr), uvm_radix_enum'((UVM_ALL_ON)&UVM_RADIX));
        end
        UVM_SETINT:          begin
           bit matched;
           __m_uvm_status_container.scope.set_arg("addr");
           matched = uvm_is_match(str__, __m_uvm_status_container.scope.get());
           if(matched) begin
              if((UVM_ALL_ON)&UVM_READONLY) begin
                 uvm_report_warning("RDONLY", $sformatf("Readonly argument match %s is ignored",                    __m_uvm_status_container.get_full_scope_arg()), UVM_NONE);
              end
              else begin
                 if (__m_uvm_status_container.print_matches)                    uvm_report_info("STRMTC", {"set_int()", ": Matched string ", str__, " to field ", __m_uvm_status_container.get_full_scope_arg()}, UVM_LOW);
                 addr = uvm_object::__m_uvm_status_container.bitstream;
                 uvm_object::__m_uvm_status_container.status = 1;
              end
           end
           __m_uvm_status_container.scope.unset_arg("addr");
        end
      endcase    end
      
// `uvm_field_int(data, UVM_ALL_ON)
      begin
	 case (what__)        UVM_CHECK_FIELDS:          begin
            __m_uvm_status_container.do_field_check("data", this);
         end
           UVM_COPY:          begin
              if(local_data__ == null) return;
              if(!((UVM_ALL_ON)&UVM_NOCOPY)) data = local_data__.data;
           end
           UVM_COMPARE:          begin
              if(local_data__ == null) return;
              if(!((UVM_ALL_ON)&UVM_NOCOMPARE)) begin
		 if(data !== local_data__.data) begin
                    void'(__m_uvm_status_container.comparer.compare_field("data", data, local_data__.data, $bits(data)));
                    if(__m_uvm_status_container.comparer.result && (__m_uvm_status_container.comparer.show_max <= __m_uvm_status_container.comparer.result)) return;
		 end
              end
           end
           UVM_PACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
              if($bits(data) <= 64) __m_uvm_status_container.packer.pack_field_int(data, $bits(data));
              else __m_uvm_status_container.packer.pack_field(data, $bits(data));
           end
           UVM_UNPACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
              if($bits(data) <= 64) data =  __m_uvm_status_container.packer.unpack_field_int($bits(data));
              else data = __m_uvm_status_container.packer.unpack_field($bits(data));
           end
           UVM_RECORD:             if(!((UVM_ALL_ON)&UVM_NORECORD)) begin
	      __m_uvm_status_container.recorder.record_field("data", data,  $bits(data), uvm_radix_enum'((UVM_ALL_ON)&(UVM_RADIX)));
	   end
           UVM_PRINT:          if(!((UVM_ALL_ON)&UVM_NOPRINT)) begin
              __m_uvm_status_container.printer.print_int("data", data, $bits(data), uvm_radix_enum'((UVM_ALL_ON)&UVM_RADIX));
           end
           UVM_SETINT:          begin
              bit matched;
              __m_uvm_status_container.scope.set_arg("data");
              matched = uvm_is_match(str__, __m_uvm_status_container.scope.get());
              if(matched) begin
		 if((UVM_ALL_ON)&UVM_READONLY) begin
                    uvm_report_warning("RDONLY", $sformatf("Readonly argument match %s is ignored",                    __m_uvm_status_container.get_full_scope_arg()), UVM_NONE);
		 end
		 else begin
                    if (__m_uvm_status_container.print_matches)                    uvm_report_info("STRMTC", {"set_int()", ": Matched string ", str__, " to field ", __m_uvm_status_container.get_full_scope_arg()}, UVM_LOW);
                    data = uvm_object::__m_uvm_status_container.bitstream;
                    uvm_object::__m_uvm_status_container.status = 1;
		 end
              end
              __m_uvm_status_container.scope.unset_arg("data");
           end
	 endcase    end
      
// `uvm_field_int(delay, UVM_ALL_ON)
      begin
	 case (what__)        UVM_CHECK_FIELDS:          begin
            __m_uvm_status_container.do_field_check("delay", this);
         end
           UVM_COPY:          begin
              if(local_data__ == null) return;
              if(!((UVM_ALL_ON)&UVM_NOCOPY)) delay = local_data__.delay;
           end
           UVM_COMPARE:          begin
              if(local_data__ == null) return;
              if(!((UVM_ALL_ON)&UVM_NOCOMPARE)) begin
		 if(delay !== local_data__.delay) begin
                    void'(__m_uvm_status_container.comparer.compare_field("delay", delay, local_data__.delay, $bits(delay)));
                    if(__m_uvm_status_container.comparer.result && (__m_uvm_status_container.comparer.show_max <= __m_uvm_status_container.comparer.result)) return;
		 end
              end
           end
           UVM_PACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
              if($bits(delay) <= 64) __m_uvm_status_container.packer.pack_field_int(delay, $bits(delay));
              else __m_uvm_status_container.packer.pack_field(delay, $bits(delay));
           end
           UVM_UNPACK:          if(!((UVM_ALL_ON)&UVM_NOPACK)) begin
              if($bits(delay) <= 64) delay =  __m_uvm_status_container.packer.unpack_field_int($bits(delay));
              else delay = __m_uvm_status_container.packer.unpack_field($bits(delay));
           end
           UVM_RECORD:             if(!((UVM_ALL_ON)&UVM_NORECORD)) begin
	      __m_uvm_status_container.recorder.record_field("delay", delay,  $bits(delay), uvm_radix_enum'((UVM_ALL_ON)&(UVM_RADIX)));
	   end
           UVM_PRINT:          if(!((UVM_ALL_ON)&UVM_NOPRINT)) begin
              __m_uvm_status_container.printer.print_int("delay", delay, $bits(delay), uvm_radix_enum'((UVM_ALL_ON)&UVM_RADIX));
           end
           UVM_SETINT:          begin
              bit matched;
              __m_uvm_status_container.scope.set_arg("delay");
              matched = uvm_is_match(str__, __m_uvm_status_container.scope.get());
              if(matched) begin
		 if((UVM_ALL_ON)&UVM_READONLY) begin
                    uvm_report_warning("RDONLY", $sformatf("Readonly argument match %s is ignored",                    __m_uvm_status_container.get_full_scope_arg()), UVM_NONE);
		 end
		 else begin
                    if (__m_uvm_status_container.print_matches)                    uvm_report_info("STRMTC", {"set_int()", ": Matched string ", str__, " to field ", __m_uvm_status_container.get_full_scope_arg()}, UVM_LOW);
                    delay = uvm_object::__m_uvm_status_container.bitstream;
                    uvm_object::__m_uvm_status_container.status = 1;
		 end
              end
              __m_uvm_status_container.scope.unset_arg("delay");
           end
	 endcase    end
      
// `uvm_object_utils_end    
   end
endfunction

In reply to tfitz:

thanks

In reply to dave_59:

Tom, Dave,
I am opening this post again as I am still have some questions.

  1. when you say, just use
`uvm_object_utils(simple_item)

Does it mean that we don’t need to use:

`uvm_field_int(addr, UVM_ALL_ON)

I am under the impression that these are needed in order to automate basic operations in a component and item (e.g. copy, print etc.)

In reply to verif_learner:

In reply to dave_59:
Does it mean that we don’t need to use:

`uvm_field_int(addr, UVM_ALL_ON)

I am under the impression that these are needed in order to automate basic operations in a component and item (e.g. copy, print etc.)

When you don’t use the field macros, you need to implement the do_copy, do_print, etc methods yourself. I say go ahead and use the macros, just be sure to run a profile to see if their slow performance is impacting you.

Sure their inefficient, but manually implementing those methods is also an inefficient use of your time, which is a much more valuable resource. A profile will tell you where your optimization efforts will return the most performance for the least amount of effort. If it’s manually reimplementing these methods, then your in luck, you have a simple straight forward job to do.

In reply to warnerrs:

The problem with that advice is by the time you get to the point where performance is an issue and you run the profiler, you’ve already wasted more simulation time than it would have taken to write your own methods, and there are many template code generators out there that do this for you without having to incur a performance penalty.

Also, usually you don’t need these methods in uvm_component classes anyway since you never copy or compare these classes. But every field you add to the uvm_config_db with these macros adds to the overall performance penalty of all usage.

In reply to dave_59:

Folks,

I am assuming that it is not recommended to use uvm_field_utils_begin/uvm_field_utils_end pair too. BTW, what is the different between uvm_field_utils_begin/uvm_field_utils_end and uvm_object_utils_begin/uvm_object_utils_end, just for my information.

In reply to verif_learner:

I think the documentation for this is very clear.

https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.1d/html/files/macros/uvm_object_defines-svh.html#`uvm_field_utils_begin