路科验证的个人空间 https://blog.eetop.cn/1561828 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

UVM世界观之五:核心基类(上)

已有 6638 次阅读| 2017-6-12 00:03 |个人分类:验证系统思想|系统分类:芯片设计


在《类库地图》一节中,读者可以看到UVM世界中的类最初都是从一个uvm_void根类(root class)中得来的,而实际上这个类并没有一个成员变量和方法,它只是一个虚类(virtual class),还在等待将来继承与它的子类去开垦。在继承与uvm_void的子类中,有两类,一个类为uvm_object,另外一个类为uvm_port_base。

在后面的章节关于TLM传输的部分中我们会讲解uvm_port_base,而在本节中我们来重点分析uvm_object这一个类的核心功能和扮演的角色是什么。要知道,UVM世界的类库地图中除过事务接口(transaction interface)类继承与uvm_port_base,其它所有的类都是从uvm_object一步步继承而来的。

从uvm_object提供的方法和相关的宏操作来看,它的核心方法主要提供与数据操作的相关服务:
  • Copy
  • Clone
  • Compare
  • Print
  • Pack/Unpack

对于一个将来可能含有多种成员变量的类而言,其对象的拷贝和克隆要复杂得多,更多的需要创建类的verifier自己去定义copy和clone等方法,这就为编码带来了不方便的地方。

在介绍uvm_object如何实现规模化的数据拷贝和对象克隆之前,需要再提醒一些初识面向对象编程的读者们,下面的这个操作并不是对象的拷贝:
module object_handle_copy;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef enum {RED, WHITE, BLACK} color_t;
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`uvm_object_utils(box)
function new(string name="box");
super.new(name);
this.name = name;
endfunction
endclass
box b1, b2;
initial begin
b1 = new("box1");
b2 = b1;
b2.name = "box2";
$display("b1 box name is %s", b1.name);
$display("b2 box name is %s", b2.name);
end
endmodule

输出结果:
b1 box name is box2
b2 box name is box2

在之前SV核心篇章中,读者已经见过类似的例子用来表明将b1赋值于b2,并不是将b1内的数据悉数拷贝给b2,而只是将b1的句柄拷贝给b2。由于b2与b1都指向了同一个对象,所以通过b2或者b1进行对象的数据操作都是对同一个对象成员变量的修改,最终的输出结果也反映了这一点。那么,如果要将b1的数据拷贝到b2,应该如何呢?在之前SV《激励器的封装》中关于对象的拷贝,读者需要自己编写copy()成员方法,来规定哪些成员数据需要拷贝。

可以想象的是,如果对于uvm_object类的成员数据的拷贝、打印操作如果都需要用户自己去定义的话,那么这会带来额外的编码负担,并且由于用户代码的不规范也容易出错。那么UVM是如何解决数据本身存放和相关操作的“基础建设”的呢?

域的自动化 (Field Automation)
UVM通过一些域的自动化,使得用户在注册UVM类的同时也可以声明今后会参与到对象拷贝、克隆、打印等等操作的成员变量。仍然是上面的例子,我们来看看通过UVM与域的自动化相关的宏,如何简化了对象的拷贝。

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

typedef enum {RED, WHITE, BLACK} color_t;

class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`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_object_utils_end
function new(string name="box");
super.new(name);
this.name = name;
endfunction
endclass

box b1, b2;
initial begin
b1 = new("box1");
b1.volume = 80;
b1.color = BLACK;
b2 = new();
b2.copy(b1);
b2.name = "box2";
$display("%s", b1.sprint());
$display("%s", b2.sprint());
end
endmodule

输出结果:
-------------------------------
Name Type Size Value
-------------------------------
box1 box - @336
volume integral 32 'h50
color color_t 32 BLACK
name string 4 box1
-------------------------------

-------------------------------
Name Type Size Value
-------------------------------
box box - @337
volume integral 32 'h50
color color_t 32 BLACK
name string 4 box2
-------------------------------

从这个使用域的自动化宏的例子来看,在注册box的同时,也声明了将来会参与到uvm_object数据操作的成员变量。凡是声明了的成员变量,都将在数据操作时自动参与进来。那么,如果有一些数据,没有通过域的自动化来声明的话,它们也将不会自动参与到数据的拷贝、打印等操作,除非用户自己去定义。

这里,我们按照域的类型来将域的自动化时用来声明数据的宏进行分类:
域类型域自动化的宏声明成员类型
标量`uvm_field_int(ARG, FLAG)整形
`uvm_field_object(ARG, FLAG)继承与uvm_object的类型句柄
`uvm_field_string(ARG, FLAG)字符串类型
`uvm_field_enum(T, ARG, FLAG)枚举类型
`uvm_field_event(ARG, FLAG)事件类型
`uvm_field_real(ARG, FLAG)实数类型
静态数组`uvm_field_sarray_int(ARG, FLAG)包含整形的一维静态数组
`uvm_field_sarray_object(ARG, FLAG)包含uvm_object的一维静态数组
`uvm_field_sarray_string(ARG, FLAG)包含字符串的一维静态数组
`uvm_field_sarray_enum(T, ARG, FLAG)包含枚举类型的一维静态数组
动态数组`uvm_field_array_int(ARG, FLAG)包含整形的一维动态数组
`uvm_field_array_object(ARG, FLAG)包含uvm_object的一维动态数组
`uvm_field_array_string(ARG, FLAG)包含字符串的一维动态静态数组
`uvm_field_array_enum(T, ARG, FLAG)包含枚举类型的一维静态数组
队列`uvm_field_queue_int(ARG, FLAG)包含整形的队列
`uvm_field_queue_object(ARG, FLAG)包含uvm_object的队列
`uvm_field_queue_string(ARG, FLAG)包含字符串的队列
`uvm_field_queue_enum(T, ARG, FLAG)包含枚举类型的队列
关联数组键类型:
字符串
`uvm_field_aa_int_string(ARG, FLAG)包含整形的关联数组
`uvm_field_aa_object_string(ARG, FLAG)包含uvm_object的关联数组
`uvm_field_aa_string_string(ARG, FLAG)包含字符串的关联数组
键类型:
整形
`uvm_field_aa_object_int(ARG, FLAG)由int索引的包含uvm_object的关联数组
`uvm_field_aa_int_int(ARG, FLAG)由int索引的包含int的关联数组
`uvm_field_aa_int_int_unsigned(ARG, FLAG)由int unsigned类型索引
`uvm_field_aa_int_integer(ARG, FLAG)由integer类型索引
`uvm_field_aa_int_integer_unsigned(ARG, FLAG)由integer unsigned类型索引
`uvm_field_aa_int_byte(ARG, FLAG)由byte类型索引
`uvm_field_aa_int_byte_unsigned(ARG, FLAG)由byte unsigned类型索引
`uvm_field_aa_int_shortint(ARG, FLAG)由shortint类型索引
`uvm_field_aa_int_shortint_unsigned(ARG, FLAG)由shortint unsigned类型索引
`uvm_field_aa_int_longint(ARG, FLAG)由longtin类型索引
`uvm_field_aa_int_longint_unsigned(ARG, FLAG)由longting unsigned类型索引
`uvm_field_aa_int_key(ARG, FLAG)由任何整形类型索引
`uvm_field_aa_int_enumkey(ARG, FLAG)由任何枚举类型索引

而上面的这些用于域的自动化的宏声明应当在uvm_object或者uvm_component注册时发生。即应该在`uvm_object_utils_begin和`uvm_object_utils_end之间,或者在`uvm_component_utils_begin和`uvm_component_utils_end之间签入要自动化的域。

在签入要自动化的域时,除过需要注意运用正确地宏来匹配域的成员类型(ARG),还应当声明这些域在将来会参与到的数据操作(FLAG),这一声明即由下面不同的枚举类型来确认。

数据操作方法属性描述
拷贝UVM_COPY该域会被自动拷贝(默认)
UVM_NOCOPY该域不会被自动拷贝
UVM_DEEP对象域将被深拷贝,对象应当实现copy方法(默认)
UVM_SHALLOW对象域将被浅拷贝
UVM_REFERENCE对象域只会拷贝句柄
比较UVM_COMPARE该域会被自动比较(默认)
UVM_NOCOMPARE该域不会被自动比较
打印UVM_PRINT该域会被自动打印(默认)
UVM_NOPRINT该域不会被自动打印
UVM_NODEFPRINT该域的值如果等于缺省值则不会被打印
UVM_BIN, UVM_DEC,
UVM_UNSIGNED,
UVM_OCT, UVM_HEX,
UVM_STRING,
UVM_TIME, UVM_ENUM
规定打印该域时的字符串输出格式
记录UVM_RECORD该域会被自动记录(默认)
UVM_NORECORD该域不会被自动记录
打包UVM_PACK该域会被自动打包(默认)
UVM_NOPACK该域不会被自动打包
其它UVM_DEEP对象域进行深层次递归操作(拷贝/比较/打印/记录/打包)
UVM_SHALLOW对象域进行浅层次递归操作(拷贝/比较/打印/记录/打包)
UVM_REFERENCE对象域只对句柄操作(拷贝/比较/打印/记录/打包)
UVM_READONLY对象域不会被自动配置
UVM_ALL_ON使能该域参与所有的数据操作
UVM_DEFAULT采取默认的域操作方法

UVM小白们在刚开始使用时,不妨先将FLAG写为UVM_ALL_ON或者UVM_DEFAULT。目前,UVM_ALL_ON和UVM_DEFAULT的功能是一致的,即将所有的数据操作方法打开,而UVM推荐的是UVM_DEFAULT,因为不排除日后添加一些其它的数据操作方法,而默认被关闭。

如果用户不写UVM_ALL_ON或者UVM_DEFAULT,那么只需要写出哪些操作是应当被关闭的。例如,FLAG设置为UVM_NOCOMPARE,那么该域会被排除出比较操作,但其它操作仍然是默认执行的。

此外,各种数据操作属性也可以进行多项指定,这里我们只推荐使用按位或操作符“|”。例如,"UVM_NOCOPY | UVM_NOCOMPARE",即将该域的拷贝操作和比较操作关闭,而保留其它操作。本书不推荐使用加法操作符"+"的原因在于,如果有多个相同属性参与到属性运算中,则容易导致无法预期的行为。

因此,通过上述的域自动化的方法,可以给读者省去一大笔编码的时间,同时uvm_object也具备了可以进行常用数据操作的方法。同时,通过上面的宏虽然节省了用户编码的时间,然而由于宏而引入的上百行额外的代码,这也会对仿真运算造成非常大量的隐形消耗。关于宏的这把双刃剑,我们也将在后面的文章《宏的优劣探讨》中详细分析。

接下来,我们可以分别深入这几种数据操作方法当中,基本掌握各个方法的用途。




点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 253

    粉丝
  • 25

    好友
  • 33

    获赞
  • 45

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-25 22:33 , Processed in 0.015140 second(s), 12 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部