UVM-- 核心基类

1 核心基类

UVM_object

UVM世界中的类最初都是由一个uvm_void根类继承过来的,但实际上该类没有实际的成员变量和方法。uvm_void只是一个虚类(virtual class),里边的内容等待继承于它的子类去开垦,在继承与uvm_void的子类中,有两类,一类为uvm_object,另外一类为uvm_port_base。在类库地图中,除了事务接口类继承于uvm_port_base,其他的所有类都是从uvm_object类中一步步继承过来的。

从uvm_object提供的方法和相关的宏操作来看,它的核心方法主要提供与数据操作相关的主要事务:

copy、 clone、 compare、 print、pack/unpack

域的自动化

UVM通过域的自动化,使得用户在注册UVM类的同时也可以声明今后会参与到对象拷贝、克隆、打印等操作的成员变量

域的自动化解放了verifier的双手,这使得在使用uvm_object提供的一些预定义方法时,非常便捷,而无需再实现自定义方法。在了解了域的自动化常用的宏之后,用户需要考虑哪些成员变量 、
在注册UVM类( uvm_{component, object}_utils)的时候,也一并将它们归置到对应的域列表中,以便为稍后的域方法提供可以自动实现的基础。

class box extends uvm_object;
    int volume = 120;
    color_t color =WHITE;
    string name ="box";
    `uvm_object_utils_begin(box) 
     //域自动化部分,放置在uvm_{component, object}_utils_begin和uvm_{component, object}_utils_end 之间;
       `uvm_filed_int(volume, UVM_ALL_ON)
       `uvm_filed_enum(color_t, color, UVM_ALL_ON)
       `uvm_filed_string(name, UVM_ALL_ON)
    `uvm_object_utils_end
  //域的自动化的相关宏都是'uvm_field_{int, object, string, enum, event, real...}(ARG, FLAG), ARG表示成员变量,FLAG表示用来标记的数据操作。
   ...//省略创建部分
 endclass

 box b1,b2;
 initial begin
b1 = new("box1");
b1.volume =80;
b1.color =BLACK;
b2 =new();
b2.copy(b1);
b2.name = "box2";
end
 

从这个域的自动化宏的例子来看,在注册box的同时,也声明了将来会参与到 uvm_object数据操作的成员变量;

凡是声明了的成员变量,都将在数据操作时自动参与进来

如果有一些数据没有通过域的自动化来声明的话,它们也将不会自动参与到数据的拷贝、打印等操作,除非用户自己去定义这些数据操作方法。

按照域的类型,将在域自动化自动化是声明的宏进行分类,如下:

这些用于域的自动化的宏声明应在 uvm_object 或 uvm_ component 注册时发生, 即在`uvm_object_utils_begin 和uvm_object_ utils_end 之间,或者在'uvm_ component_ utils_ begin 和 uvm_ component_ utils _ end 之间声明要自动化的域。在声明自动化的域时,除了要注意运用正确的宏来匹配域的成员类型 (ARG), 还应声明这些域在将来参与的数据操作 (FLAG), 这一声明由下表枚举类型来表示。

建议初学者只需要默认采取UVM_ALL_ON或者 UVM_DEFAULT, 即将所有的数据操仵方法都打开。

 拷贝(copy)

•    在UVM的数据操作中, 需要对copy和clone加以区分。 前者默认已经创建好了对象,只需要对数据进行拷贝;后者则会自动创建对象并对source object进行数据拷贝, 再返回target object句柄。
•    无论是copy或者clone, 都需要对数据进行复制。
•     在进行copy时, 默认进行的是深拷贝(deep copy) , 即会执行copy()和do_copy()。

代码案例:

class ball extends uvm_object;
	 int diameter = 10; 
	 color_t color = RED;
	 `uvm_object_utils_begin(ball) 
       `uvm_field_int(diameter, UVM_DEFAULT)
	   `uvm_field_enum(color_t, color, UVM_NOCOPY)//不允许拷贝
	 `uvm_object_utils_end 
	 ...//省略创建
	function void do_copy(uvm_object rhs); 
	ball b; 
    $cast(b, rhs); 
    $display("ball::do_copy entered .. "); 
	if(b.diameter <= 20) begin 
	diameter = 20;
	end
	endfunction
	endclass
	
	 class box extends uvm_object;
	 int volume = 120; 
     color_t color = WHITE; 
	 string name = "box"; 
     ball b; 
     `uvm_object_utils_begin(box) 
       `uvm_field_int(volume, UVM_ALL_ON)
	   `uvm_field_enum(color_t, color, UVM_ALL_ON)
       `uvm_field_string(name, UVM_ALL_ON)	
       `uvm_field_object(b, UVM_ALL_ON)   
	 `uvm_object_utils_end 
	  ...//省略创建
	  endclass
	  
	  box bl, b2; 
	  initial begin
	  bl = new("boxl"); 
      bl.volume = 80; 
      bl.color = BLACK; 
      bl.b.color = WHITE; 
      b2 = new(); 
      b2.copy(bl); 
      b2.name = "box2"; 
      $display("%s", bl.sprint()); $display("%s", b2.sprint());
	  end

输出结果:

新添加了一个类ball, 并且在box中例化了一个ball的对象。 在拷贝过称中, box的其它成员都正常拷贝了, 但对于box::b的拷贝则通过了ball的深拷贝方式进行。 

•    即先执行自动拷贝copy(), 来拷贝允许拷贝的域, 由于ball::color不允许拷贝, 所以只拷贝了ball::diameter
•    接下来,再执行do_copy()函数,这个函数是需要用户定义的回调函数(callback function) , 即在copy()执行完后会执行do_copy()。
•    如果用户没有定义该函数, 那么则不会执行额外的数据操作
•    从ball::do_copy()函数可以看到, 如果被拷贝对象的diameter小于20, 那么则将自身的diameter设置为20。 囚此, 最后对象b2.b的 成员与b1.b的成员数值不同。

比较(compare)

function bit compare (uvm_object rhs, uvm_comparer comparer =null);

•    默认情况下, 如果不对比较的情况作出额外配置, 用户可以在调用compare()方法时, 省略第二项参数, 即采用默认的比较配置。
•    比较方法经常会在两个数据类中进行。 例如从generator产生的 一个transaction (数据类), 和在设计输出上捕捉的transaction(数据类), 如果它们为同一种类型, 除了可以自定义数据比较之外, 也可以直接使用uvm_object::compare()函数来实现数据比较和消息打印。

class box extends uvm_object;
	  int  volume = 120; 
      color_t color = WHITE; 
	  string name = "box"; 
      `uvm object utils begin(box) 
	  ...//省略域自动化声明
      `uvm_object_utils_end
	    ...//省略创建
		endclass
		
	  box bl, b2;
	  initial begin
	  bl = new("boxl"); 
      bl.volume = 80; 
      bl.color = BLACK; 
      b2 = new("box2"); 
      b2.volume = 90; 
      if (!b2.compare (bl)) begin
	  `uvm_info("COMPARE", "b2 comapred with bl failure", UVM_LOW)
	  end
	  else begin
	  `uvm info("COMPARE", "b2 comapred with bl succes", UVM_LOW)
	  end
	  end
	  
	  //输出结果·
        UVM_INFO @ 0: reporter [MISCMP] Miscompare for box2.volume: lhs ='h5a: rhs ='h50 
		UVM_INFO @ 0: reporter [MISCMP] 1 Miscompare(s) for object box1@336 vs box2@337 
		UVM_INFO @ 0: reporter [COMPARE] b2 comapred with b1 failure 

在上面的两个对象比较中,会将每一个自动化的域进行比较,所以在执行compare()函数时,内置的比较方法会将比较错误输出。

•    从结果来看,比较发生了错误,返回0值。那么,b1.color和b2.color虽然不相同,却没有比较错误的信息。
•    原因在于, 默认的比较器, 即uvm_package::uvm_default_comparer最大输出的错误比较信息是1, 也就是说当比较错误发生时, 不会再进行后续的比较。
•    实际上, 在uvm_object使用到的方法compare()、print()和pack(), 如果没有指定数据操作配置对象作为参数时,会使用在uvm_pkg 中例化的全局数据操作配置成员。

全局对象

在uvm_pkg中例化了不少全局对象,在本节中我们会使用到的全局配置对象包括有uvm_default_comparer, uvm_default_printer和uvm_default_packer。
如果用户不想使用默认的比较配置,而是想自己对比较 进行设定,可以考虑创建一个uvm_comparer对象,或者修改全局的uvm_comparer对象。

下表为uvm_pkg全局对象:

打印(print) 

•    打印方认是核心基类提供的另外才中便于“开发和调试的功能“;
•    通过field automation, 使得声明之后的各个成员域会在调用 uvm_object::print()函数时自动打印出来。
•   相比于在仿真中设置断点、逐从调试,打印是另外一种调试方法,它的好处在于可以让仿真继续进行,会在最终回顾执行过程中, 从全局理解执行的轨迹和逻辑。

class box extends uvm_object;
	 int volume = 120; 
     color_t color = WHITE; 
     string name = "box"; 
     'uvm_object_utils begin(box)
	 ...//域的自动化
     uvm_object_utils end
endclass
	 
	 box bl; 
     uvm_table_printer local_printer; 
	 initial begin 
	 bl = new("boxl"); 
     local_printer = new(); 
     $display ("default table printer format"); 
     bl.print(); //不指定printer,默认用uvm_default_printer下的uvm_table_printer
     $display ("default line printer format"); 
     uvm_default_printer = uvm_default_line_printer; 
	 bl.print(); 
     $display("default tree printer format"); 
     uvm_default_printer = uvm_default_tree_printer;
	 bl.print(); 
     $display("customized printer format"); 
     local_printer.knobs.full_name = l; 
     bl.print (local_printer);
	 end 

 •    只要在field automation中声明过的域,在稍后的print()函数执行时,都将打印出它们的类型、大小和数值。如果用户不对打印的格式做出修改, 那么在打印时,UVM会按照uvm_default_pri nter规定的格式来打印。
•    uvm_pkg所包含的用于打印的全局对象, 它们分别是:

  uvm_default_tree_printer: 可以将对象按照树状结构打印”;

  uvm_default_line_printer : 可以将对象数据打印到一行上;

  uvm_default_table_printer : 可以将对象按照表格的方式打印;

  uvm_default_printer : UVM坏境默认的打印设置,该句柄默认指向了 uvm_default_table_printer

•    通过给全局打印机uvm_default_printe赋予不同的打印机句柄, 就可以在调用行何uvm_object的print()方法时, 得到不同的打印格式。
•    如果用户需要自定义一些打印属性, 可以自己创建一个打印机, 进而通过修改其属件uvm_printer:: knobs中的成员, 来定制打印格式。

打包和解包(pack/unpack)

function int pack (ref bit bitstream[ ], input uvm_packer packer=null);

function int unpack (ref bit bitstream[ ], input uvm_packer packer=null); 

•    pack足为了将自动化声明后的域(标量)打包为比特流(bit stream)。即将各个散乱的数据,整理到bit数据串中,类似于 struct packed的整理方式,但又能充分利用数据空间,也更容易与硬件之间进行数据传递和比对。

•    unpack与pack相反,即将串行数据解包变为原有的各自域。该操作适用于从硬件一侧接收串行数据,进行校验后,还原为软件一侧对象中各自对应的成员变量。

•    pack与unpack在通常的UVM环境中使用较少,但是当与外界环境,例如System(发生大规模数据传递,该方法是首选,因为可以通过简单数据流实现精确的数据传输,另外,在UVM与FPGA emulator之间进行数据交换时,该方法也由于简便得到了青眯。

class box extends uvm_object;
	 int volume = 120; 
     int height = 20; 
     color_t color = WHITE;
     'uvm_object_utils begin(box)
	 ...//域的自动化
endclass
	 
	 box bl, b2;
	 bit packed_bits[]; 
	 initial begin 
	 bl = new("boxl"); 
     b2 = new ("box2"); 
     bl.volume = 100; 
     bl.height = 40; 
     bl.color = RED; 
     bl.print();
     bl.pack(packed_bits); 
     $display ("packed bi ts streamsize is %d \n", packed_bits.size()); 
	 b2.unpack(packed_bits);
	 b2.print() ; 
     end  

输出结果:

 •    b1将声明过的域通过pack()进行打包,打包好的数据存入到一个比特数组packed_bits,这个数组存放着所有经过field automation 的域值。
•    接下来b2又从packed_bits中解包, 将数据存入到自己的各个域中
•    这种操作即完成了大型标量数据的整形串发, 主要面向SV与硬件和其它语言接口直接的精确通信。
•    在pack()和unpack()的参数中,有一个是可以缺省的参数即 uvm_packer, 如果用户不做特别指定,那么打包和解包的uvm_packer将会使用uvm_pkg中例化的全局对象uvm_default_packer。
•    此外, 用户如果需要自行打包, 例如规定将b1.volume打包成多少长度的比特数组, 来匹配硬件信号的位宽, 则需要自己定义do_pack( )回调函数。

以下案例涵盖本小结的重点内容:

package object_methods_pkg;
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  
  typedef enum {WRITE, READ, IDLE} op_t;  

  class trans extends uvm_object;
    bit[31:0] addr;
    bit[31:0] data;
    op_t op;
    string name;
    `uvm_object_utils_begin(trans)
      //TODO-2.1 
      //Apply field automation macros such as
      //  `uvm_field_int(ARG, FLAG)
      //  `uvm_field_enum(T, ARG, FLAG)
      //  `uvm_field_string(ARG, FLAG)
      //to register all of member variables
	  `uvm_field_int(addr,UVM_ALL_ON);
	  `uvm_field_int(data,UVM_ALL_ON);
	  `uvm_field_enum(op_t,op,UVM_ALL_ON);
	  `uvm_field_string(name,UVM_ALL_ON);
    `uvm_object_utils_end
    function new(string name = "trans");
      super.new(name);
      `uvm_info("CREATE", $sformatf("trans type [%s] created", name), UVM_LOW)
    endfunction
    function bit do_compare(uvm_object rhs, uvm_comparer comparer);
      //TODO-2.4
      //Please just try to compare all of properties of the two properties
      //and give detailed comparison messages
	  trans t;
	  do_compare =1;
	  void'($cast(t,rhs));
	  if (addr!=t.addr)begin
	  do_compare =0;
	  `uvm_warning("COMPARE",$sformatf("addr %8x !=%8x",addr,t.addr));
	  end
	  if (data!=t.data)begin
	  do_compare =0;
	  `uvm_warning("COMPARE",$sformatf("addr %8x !=%8x",data,t.data));
	  end
	  if (op!=t.op)begin
	  do_compare =0;
	  `uvm_warning("COMPARE",$sformatf("addr %s !=%s", op,t.op));
	  end
	  if (name!=t.name)begin
	  do_compare =0;
	  `uvm_warning("COMPARE",$sformatf("addr %8x !=%8x",name,t.name));
	  end
    endfunction
  endclass

   
  class object_methods_test extends uvm_test;
    `uvm_component_utils(object_methods_test)
    function new(string name = "object_methods_test", uvm_component parent = null);
      super.new(name, parent);
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
    endfunction
    task run_phase(uvm_phase phase);
      trans t1, t2;
      bit is_equal;
      phase.raise_objection(this);
      t1 = trans::type_id::create("t1");
      t1.data = 'h1FF;
      t1.addr = 'hF100;
      t1.op = WRITE;
      t1.name = "t1";
      t2 = trans::type_id::create("t2");
      t2.data = 'h2FF;
      t2.addr = 'hF200;
      t2.op = WRITE;
      t2.name = "t2";
      //TODO-2.2 
      //Use function bit compare (uvm_object rhs, uvm_comparer comparer=null)
      //to compare t1 and t2, and check the message output
	  is_equal=t2.compare(t1);
	  if(!is_equal)begin
	   `uvm_warning("COMPARE","t2 is not equal t1")
	   end
	   else begin
	   `uvm_info("COMPARE","t2 is equal t1",UVM_LOW)
	   end
      
      //TODO-2.3
      //uvm_default_comparer (uvm_comparer type) is the default UVM global comparer, 
      //you would set its property like 'show_max' to ask more of the comparison result
      //Please set this property and do the compare again
      is_equal=t2.compare(t1);
	  uvm_default_comparer.show_max =10;
	  if(!is_equal)begin
	   `uvm_warning("COMPARE","t2 is not equal t1 ")
	   end
	   else begin
	   `uvm_info("COMPARE","t2 is equal t1",UVM_LOW)
	   end
        
      `uvm_info("COPY", "Before uvm_object copy() taken", UVM_LOW)
      //TODO-2.5
      //Use uvm_object::print() method to display all of fields before copy()
	  t1.print();
	  t2.print();
      `uvm_info("COPY", "After uvm _object t2 is copied to t1", UVM_LOW)
      //TODO-2.6
      //Call uvm_object::copy(uvm_object rhs) to copy t2 to t1
      //and use print() and compare() to follow steps above again for them
       t1.copy(t2);
	   t1.print();
	   t2.print();
	   `uvm_info("CMP","compare t1 and t2",UVM_LOW)
	   is_equal=t1.compare(t2);
	   if(!is_equal)begin
	   `uvm_warning("COMPARE","t2 is not equal t1")
	   end
	   else begin
	   `uvm_info("COMPARE","t2 is equal t1",UVM_LOW)
	   end
	   #1us;
      phase.drop_objection(this);
    endtask
  endclass
  
endpackage

module object_methods;

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

  initial begin
    run_test(""); // empty test name
  end

endmodule

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创芯人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值