《UVM实战》——3.3节field automation机制

3.3 field automation机制
3.3.1 field automation机制相关的宏
在第2章介绍filed_automation机制时出现了uvm_field系列宏,这里系统地把它们介绍一下。最简单的uvm_field系列宏有如下几种:
代码清单 3-25
来源:UVM源代码

`define uvm_field_int(ARG,FLAG)
`define uvm_field_real(ARG,FLAG)
`define uvm_field_enum(T,ARG,FLAG)
`define uvm_field_object(ARG,FLAG)
`define uvm_field_event(ARG,FLAG)
`define uvm_field_string(ARG,FLAG)
上述几个宏分别用于要注册的字段是整数、实数、枚举类型、直接或间接派生自uvm_object的类型、事件及字符串类型。这里除了枚举类型外,都是两个参数。对于枚举类型来说,需要有三个参数。假如有枚举类型tb_bool_e,同时有变量tb_flag,那么在使用field automation机制时应该使用如下方式实现:
代码清单 3-26
typedef enum {TB_TRUE, TB_FALSE} tb_bool_e;
…
tb_bool_e tb_flag;
…
`uvm_field_enum(tb_bool_e, tb_flag, UVM_ALL_ON)
与动态数组有关的uvm_field系列宏有:
代码清单 3-27
来源:UVM源代码
`define uvm_field_array_enum(ARG,FLAG)
`define uvm_field_array_int(ARG,FLAG)
`define uvm_field_array_object(ARG,FLAG)
`define uvm_field_array_string(ARG,FLAG)
这里只有4种,相比于前面的uvm_field系列宏少了event类型和real类型。另外一个重要的变化是enum类型的数组里也只有两个参数。
与静态数组相关的uvm_field系列宏有:
代码清单 3-28
来源:UVM源代码
`define uvm_field_sarray_int(ARG,FLAG)
`define uvm_field_sarray_enum(ARG,FLAG)
`define uvm_field_sarray_object(ARG,FLAG)
`define uvm_field_sarray_string(ARG,FLAG)
与队列相关的uvm_field系列宏有:
代码清单 3-29
来源:UVM源代码
`define uvm_field_queue_enum(ARG,FLAG)
`define uvm_field_queue_int(ARG,FLAG)
`define uvm_field_queue_object(ARG,FLAG)
`define uvm_field_queue_string(ARG,FLAG)
同样的,这里也是4种,且对于enum类型来说,也只需要两个参数。
联合数组是SystemVerilog中定义的一种非常有用的数据类型,在验证平台中经常使用。UVM对其提供了良好的支持,与联合数组相关的uvm_field宏有:
代码清单 3-30
来源:UVM源代码
`define uvm_field_aa_int_string(ARG, FLAG)
`define uvm_field_aa_string_string(ARG, FLAG)
`define uvm_field_aa_object_string(ARG, FLAG)
`define uvm_field_aa_int_int(ARG, FLAG)
`define uvm_field_aa_int_int_unsigned(ARG, FLAG)
`define uvm_field_aa_int_integer(ARG, FLAG)
`define uvm_field_aa_int_integer_unsigned(ARG, FLAG)
`define uvm_field_aa_int_byte(ARG, FLAG)
`define uvm_field_aa_int_byte_unsigned(ARG, FLAG)
`define uvm_field_aa_int_shortint(ARG, FLAG)
`define uvm_field_aa_int_shortint_unsigned(ARG, FLAG)
`define uvm_field_aa_int_longint(ARG, FLAG)
`define uvm_field_aa_int_longint_unsigned(ARG, FLAG)
`define uvm_field_aa_string_int(ARG, FLAG)
`define uvm_field_aa_object_int(ARG, FLAG)

这里一共出现了15种。联合数组有两大识别标志,一是索引的类型,二是存储数据的类型。在这一系列uvm_field系列宏中,出现的第一个类型是存储数据类型,第二个类型是索引类型,如uvm_field_aa_int_string用于声明那些存储的数据是int,而其索引是string类型的联合数组。

3.3.2 field automation机制的常用函数
field automation功能非常强大,它主要提供了如下函数。
copy函数用于实例的复制,其原型为:
代码清单 3-31
来源:UVM源代码

extern function void copy (uvm_object rhs);
如果要把某个A实例复制到B实例中,那么应该使用B.copy(A)。在使用此函数前,B实例必须已经使用new函数分配好了内存空间。
compare函数用于比较两个实例是否一样,其原型为:
代码清单 3-32
来源:UVM源代码
extern function bit compare (uvm_object rhs, uvm_comparer comparer=null);
如果要比较A与B是否一样,可以使用A.compare(B),也可以使用B.compare(A)。当两者一致时,返回1;否则为0。
pack_bytes函数用于将所有的字段打包成byte流,其原型为:
代码清单 3-33
来源:UVM源代码
extern function int pack_bytes (ref byte unsigned bytestream[],
                       input uvm_packer packer=null);
在第2章的例子中已经用过这个函数,这里不多做介绍。
unpack_bytes函数用于将一个byte流逐一恢复到某个类的实例中,其原型为:
代码清单 3-34
来源:UVM源代码
extern function int unpack_bytes (ref byte unsigned bytestream[],
                         input uvm_packer packer=null);
pack函数用于将所有的字段打包成bit流,其原型为:
代码清单 3-35
来源:UVM源代码
extern function int pack (ref bit bitstream[],
                   input uvm_packer packer=null);
pack函数的使用与pack_bytes类似。
unpack函数用于将一个bit流逐一恢复到某个类的实例中,其原型为:
代码清单 3-36
来源:UVM源代码
extern function int unpack (ref bit bitstream[],
                    input uvm_packer packer=null);
unpack的使用与unpack_bytes类似。
pack_ints函数用于将所有的字段打包成int(4个byte,或者dword)流,其原型为:
代码清单 3-37
来源:UVM源代码
extern function int pack_ints (ref int unsigned intstream[],
                      input uvm_packer packer=null);
unpack_ints函数用于将一个int流逐一恢复到某个类的实例中,其原型为:
代码清单 3-38
来源:UVM源代码
extern function int unpack_ints (ref int unsigned intstream[],
                        input uvm_packer packer=null);
print函数用于打印所有的字段。
clone函数,3.1.6节中有过介绍,其原型是:
代码清单 3-39
来源:UVM源代码
extern virtual function uvm_object clone ();

它的使用方式可以参考3.1.6节。
除了上述函数之外,field automation机制还提供自动得到使用config_db::set设置的参数的功能,这点请参照3.5.3节。

3.3.3 field automation机制中标志位的使用
考虑实现这样一种功能:给DUT施加一种CRC错误的异常激励。实现这个功能的一种方法是在my_transaction中添加一个crc_err的标志位:
代码清单 3-40

  4 class my_transaction extends uvm_sequence_item;
  5
  6   rand bit[47:0] dmac;
  7   rand bit[47:0] smac;
  8   rand bit[15:0] ether_type;
  9   rand byte      pload[];
 10   rand bit[31:0] crc;
 11   rand bit       crc_err;
 …
 22   function void post_randomize();
 23     if(crc_err)
 24       ;//do nothing
 25     else
 26       crc = calc_crc;
 27   endfunction
…
 42 endclass
这样,在post_randomize中计算CRC前先检查一下crc_err字段,如果为1,那么直接使用随机值,否则使用真实的CRC。
在sequence中可以使用如下方式产生CRC错误的激励:
代码清单 3-41
`uvm_do_with(tr, {tr.crc_err == 1;})
只是,对于多出来的这个字段,是不是也应该用uvm_field_int宏来注册呢?如果不使用宏注册的话,那么当调用print函数时,在显示结果中就看不到其值,但是如果使用了宏,结果就是这个根本就不需要在pack和unpack操作中出现的字段出现了。这会带来极大的问题。
UVM考虑到了这一点,它采用在后面的控制域中加入UVM_NOPACK的形式来实现:
代码清单 3-42

 29    `uvm_object_utils_begin(my_transaction)
 30       `uvm_field_int(dmac, UVM_ALL_ON)
 31       `uvm_field_int(smac, UVM_ALL_ON)
 32       `uvm_field_int(ether_type, UVM_ALL_ON)
 33       `uvm_field_array_int(pload, UVM_ALL_ON)
 34       `uvm_field_int(crc, UVM_ALL_ON)
 35       `uvm_field_int(crc_err, UVM_ALL_ON | UVM_NOPACK)
 36    `uvm_object_utils_end
使用上述语句后,当执行pack和unpack操作时,UVM就不会考虑这个字段了。这种写法比较奇怪,是用了一个或(|)来实现的。UVM的这些标志位本身其实是一个17bit的数字:
代码清单 3-43
来源:UVM源代码
//A=ABSTRACT Y=PHYSICAL
//F=REFERENCE, S=SHALLOW, D=DEEP
//K=PACK, R=RECORD, P=PRINT, M=COMPARE, C=COPY
//--------------------------- AYFSD K R P M C
parameter UVM_ALL_ON      = 'b000000101010101;

parameter UVM_COPY        = (1<<0);
parameter UVM_NOCOPY      = (1<<1);
parameter UVM_COMPARE     = (1<<2);
parameter UVM_NOCOMPARE   = (1<<3);
parameter UVM_PRINT       = (1<<4);
parameter UVM_NOPRINT     = (1<<5);
parameter UVM_RECORD      = (1<<6);
parameter UVM_NORECORD    = (1<<7);
parameter UVM_PACK        = (1<<8);
parameter UVM_NOPACK      = (1<<9);

在这个17bit的数字中,bit0表示copy,bit1表示no_copy,bit2表示compare,bit3表示no_compare,bit4表示print,bit5表示no_print,bit6表示record,bit7表示no_record,bit8表示pack,bit9表示no_pack。剩余的7bit则另有它用,这里不做讨论。UVM_ALL_ON的值是'b000000101010101,表示打开copy、compare、print、record、pack功能。record功能是UVM提供的另外一个功能,但是其应用并不多,所以在上节中并没有介绍。UVM_ALL_ON | UVM_NOPACK的结果就是'b000001101010101。这样UVM在执行pack操作时,首先检查bit9,发现其为1,直接忽略bit8所代表的UVM_PACK。
除了UVM_NOPACK之后,还有UVM_NOCOMPARE、UVM_NOPRINT、UVM_NORECORD、UVM_NOCOPY等选项,分别对应compare、print、record、copy等功能。

3.3.4 field automation中宏与if的结合
在以太网中,有一种帧是VLAN帧,这种帧是在普通以太网帧基础上扩展而来的。而且并不是所有的以太网帧都是VLAN帧,如果一个帧是VLAN帧,那么其中就会有vlan_id等字段(具体可以详见以太网的相关协议),否则不会有这些字段。类似vlan_id等字段是属于帧结构的一部分,但是这个字段可能有,也可能没有。由于读者已经习惯了使用uvm_field系列宏来进行pack和unpack操作,那么很直观的想法是使用动态数组的形式来实现:
代码清单 3-44

class my_transaction extends uvm_sequence_item;
  rand bit[47:0] smac;
  rand bit[47:0] dmac;
  rand bit[31:0]  vlan[];
  rand bit[15:0] eth_type;
  rand byte    pload[];
  rand bit[31:0] crc;

  `uvm_object_utils_begin(my_transaction)
     `uvm_field_int(smac, UVM_ALL_ON)
     `uvm_field_int(dmac, UVM_ALL_ON)
     `uvm_field_array_int(vlan, UVM_ALL_ON)
     `uvm_field_int(eth_type, UVM_ALL_ON)
     `uvm_field_array_int(pload, UVM_ALL_ON)
  `uvm_object_utils_end
endclass
在随机化普通以太网帧时,可以使用如下的方式:
代码清单 3-45
my_transaction tr;
tr = new();
assert(tr.randomize() with {vlan.size() == 0;});
协议中规定vlan的字段固定为4个字节,所以在随机化VLAN帧时,可以使用如下的方式:
代码清单 3-46
my_transaction tr;
tr = new();
assert(tr.randomize() with {vlan.size() == 1;});
协议中规定vlan的4个字节各自有其不同的含义,这4个字节分别代表4个不同的字段。如果使用上面的方式,问题虽然解决了,但是这4个字段的含义不太明确。
一个可行的解决方案是:
代码清单 3-47

  4 class my_transaction extends uvm_sequence_item;
  5
  6   rand bit[47:0] dmac;
  7   rand bit[47:0] smac;
  8   rand bit[15:0] vlan_info1;
  9   rand bit[2:0]  vlan_info2;
 10   rand bit       vlan_info3;
 11   rand bit[11:0] vlan_info4;
 12   rand bit[15:0] ether_type;
 13   rand byte      pload[];
 14   rand bit[31:0] crc;
 15
 16   rand bit       is_vlan;
…
 31   `uvm_object_utils_begin(my_transaction)
 32     `uvm_field_int(dmac, UVM_ALL_ON)
 33     `uvm_field_int(smac, UVM_ALL_ON)
 34     if(is_vlan)begin
 35       `uvm_field_int(vlan_info1, UVM_ALL_ON)
 36       `uvm_field_int(vlan_info2, UVM_ALL_ON)
 37       `uvm_field_int(vlan_info3, UVM_ALL_ON)
 38       `uvm_field_int(vlan_info4, UVM_ALL_ON)
 39     end
 40     `uvm_field_int(ether_type, UVM_ALL_ON)
 41     `uvm_field_array_int(pload, UVM_ALL_ON)
 42     `uvm_field_int(crc, UVM_ALL_ON | UVM_NOPACK)
 43     `uvm_field_int(is_vlan, UVM_ALL_ON | UVM_NOPACK)
 44   `uvm_object_utils_end
 …
 50 endclass
在随机化普通以太网帧时,可以使用如下的方式:
代码清单 3-48
my_transaction tr;
tr = new();
assert(tr.randomize() with {is_vlan == 0;});
在随机化VLAN帧时,可以使用如下的方式:
代码清单 3-49
my_transaction tr;
tr = new();
assert(tr.randomize() with {is_vlan == 1;});

使用这种方式的VLAN帧,在执行print操作时,4个字段的信息将会非常明显;在调用compare函数时,如果两个transaction不同,将会更加明确地指明是哪个字段不一样。

时间: 2024-08-30 03:15:01

《UVM实战》——3.3节field automation机制的相关文章

《UVM实战》——导读

目 录 前言第1章 与UVM的第一次接触1.1 UVM是什么1.2 学了UVM之后能做什么第2章 一个简单的UVM验证平台2.1 验证平台的组成2.2 只有driver的验证平台2.3 为验证平台加入各个组件2.4 UVM的终极大作:sequence2.5 建造测试用例第3章 UVM基础3.1 uvm_component与uvm_object3.2 UVM的树形结构3.3 field automation机制

《UVM实战》——2.3节为验证平台加入各个组件

2.3 为验证平台加入各个组件 2.3.1 加入transaction 在2.2节中,所有的操作都是基于信号级的.从本节开始将引入reference model.monitor.scoreboard等验证平台的其他组件.在这些组件之间,信息的传递是基于transaction的,因此,本节将先引入transaction的概念. transaction是一个抽象的概念.一般来说,物理协议中的数据交换都是以帧或者包为单位的,通常在一帧或者一个包中要定义好各项参数,每个包的大小不一样.很少会有协议是以b

《UVM实战》——2.2节只有driver的验证平台

2.2 只有driver的验证平台 driver是验证平台最基本的组件,是整个验证平台数据流的源泉.本节以一个简单的DUT为例,说明一个只有driver的UVM验证平台是如何搭建的. 2.2.1 最简单的验证平台 在本章中,假设有如下的DUT定义: 代码清单 2-1 1 module dut(clk, 2 rst_n, 3 rxd, 4 rx_dv, 5 txd, 6 tx_en); 7 input clk; 8 input rst_n; 9 input[7:0] rxd; 10 input r

《UVM实战》——3.1节uvm_component与uvm_object

第3章 UVM 基 础3.1 uvm_component与uvm_object component与object是UVM中两大最基本的概念,也是初学者最容易混淆的两个概念.本节将介绍uvm_object与uvm_component的区别和联系. 3.1.1 uvm_component派生自uvm_object 通过对第2章搭建的验证平台的学习,读者应对UVM有了较直观的认识,不少读者会认为uvm_component与uvm_object是两个对等的概念.当创建一个类的时候,比如定义一个seque

《UVM实战》——2.5节建造测试用例

2.5 建造测试用例 2.5.1 加入base_test UVM使用的是一种树形结构,在本书的例子中,最初这棵树的树根是my_driver,后来由于要放置其他component,树根变成了my_env.但是在一个实际应用的UVM验证平台中,my_env并不是树根,通常来说,树根是一个基于uvm_test派生的类.本节先讲述base_test,真正的测试用例都是基于base_test派生的一个类. 代码清单 2-74 4 class base_test extends uvm_test; 5 6

《UVM实战》——1.2节学了UVM之后能做什么

1.2 学了UVM之后能做什么 1.2.1 验证工程师 验证工程师能够从本书学会如下内容: 如何用UVM搭建验证平台,包括如何使用sequence机制.factory机制.callback机制.寄存器模型(register model)等. 一些验证的基本常识,将会散落在各个章节之间. UVM的一些高级功能,如何灵活地使用sequence机制.factory机制等. 如何编写代码才能保证可重用性.可重用性是目前IC界提及最多的几个词汇之一,它包含很多层次.对于个人来说,如何保证自己在这个项目写的

《UVM实战》——3.1节UVM的树形结构

3.2 UVM的树形结构 在第2章中曾经提到过,UVM采用树形的组织结构来管理验证平台的各个部分.sequencer.driver.monitor.agent.model.scoreboard.env等都是树的一个结点.为什么要用树的形式来组织呢?因为作为一个验证平台,它必须能够掌握自己治下的所有"人口",只有这样做了,才利于管理大家统一步伐做事情,而不会漏掉谁.树形结构是实现这种管理的一种比较简单的方式. 3.2.1 uvm_component中的parent参数 UVM通过uvm_

《UVM实战》——1.1节UVM是什么

第1章与UVM的第一次接触1.1 UVM是什么1.1.1 验证在现代IC流程中的位置现代IC(Integrated circuit,集成电路)前端的设计流程如图1-1所示.通常的IC设计是从一份需求说明书开始的,这份需求说明书一般来自于产品经理(有些公司可能没有单独的职位,而是由其他职位兼任).从需求说明书开始,IC工程师会把它们细化为特性列表.设计工程师根据特性列表,将其转化为设计规格说明书,在这份说明书中,设计工程师会详细阐述自己的设计方案,描述清楚接口时序信号,使用多少RAM资源,如何进行

《UVM实战》——2.1节验证平台的组成

第2章一个简单的UVM验证平台 2.1 验证平台的组成验证用于找出DUT中的bug,这个过程通常是把DUT放入一个验证平台中来实现的.一个验证平台要实现如下基本功能:验证平台要模拟DUT的各种真实使用情况,这意味着要给DUT施加各种激励,有正常的激励,也有异常的激励:有这种模式的激励,也有那种模式的激励.激励的功能是由driver来实现的.验证平台要能够根据DUT的输出来判断DUT的行为是否与预期相符合,完成这个功能的是记分板(scoreboard,也被称为checker,本书统一以scoreb