Chpater 21 UVM Transaction
21.1 Storing Data in Objects
从学习本书开始,我们将测试平台拆分形成一个小模块,每个模块,每个class只专注于一件事情。尽力避免一个class需要详细了解另一个class的工作内容的场景,两个不同class之间可以通过port的方式传递数据。以上工作都使得我们的测试平台变得十分高效,但是我们还留下了一些遗憾:没有对传输的数据进行处理!
TinyALU测试平台中的数据结构比较简单,command_s中包含三个变量:A,B,op。即使我们的TinyALU测试平台很小,我们也在许多地方反复调用这些值。driver,coverage,scoreboard,因此如果我们可以对数据进行处理优化,就可以进一步提升测试平台的工作效率。将数据存储在class中,可以使用函数进行数据处理,这是class优于struct的地方。
- 在UVM中这种数据class称作transaction,transaction封装了数据和数据的所有操作类型,这些操作如下:
- convert2string(): 将数据以字符串的形式打印;
- do_copy(): 将另外一个transaction的数据拷贝至当前transaction;
- do_compare(): 比较两个transaction的数据是否一致;
- randomize(): 利用SystemVerilog的random机制;
- 定义Transaction:
- 我们扩展uvm_transaction以生成需要的command_transaction,我们需要重新改写以下三个函数:
- do_copy()
- do_compare()
- convert2string()
21.1.1 定义数据的随机范围
command_transaction中需要定义随机变量,采用SV的rand定义,并用constraint约束变量的随机范围。这样我们就不再需要get_op()函数和get_data()函数,SV可以接手所有的随机工作,我们只需要在定变量的时候在前面增加rand关键字即可:
class command_transaction extends uvm_transaction;
`uvm_object_utils(command_transaction)
rand byte unsigned A; //定义操作数A,只需要在定义之前加rand关键字
rand byte unsigned B;
rand operation_t op;
constraint data {
A dist {
8'h00:=1, [8'h01 : 8'hFE]:=1, 8'hFF:=1};
B dist {
8'h00:=1, [8'h01 : 8'hFE]:=1, 8'hFF:=1};}
//指定A B的范围可以指定,甚至可以用dist决定随机值的出现概率
21.1.2 uvm_transaction的new函数
uvm_transaction扩展自uvm_object,不是component类型,在构造时不需要parent handle,只需要name即可。(component类型的class在构建的时候需要知道在环境中的具体节点位置,所以需要parent)
function new (string name = "");
super.new(name);
endfunction : new
21.1.3 do_copy函数
uvm_object类和其子类都包含copy()函数和clone()函数,其中copy函数拷贝一个对象的数据至另一个同类型对象,clone函数返回数据完全一致的同类型的对象;copy是将数据拷贝一份,clone是返回一个新的对象。
copy函数和clone函数能够工作的前提是:我们必须重构do_copy函数,do_copy函数的工作机制和我们上一章节定义lion的convert2string的机制一致,需要调用父类的同名函数。
function void do_copy(uvm_object rhs);
command_transaction copied_transaction_h;
if(rhs == null)
`uvm_fatal("COMMAND TRANSACTION", "Tried to copy from a null pointer")
//检查传输的rhs不是command_transaction类型,拷贝失败
if(!$cast(copied_transaction_h,rhs))
`uvm_fatal("COMMAND TRANSACTION", "Tried to copy wrong type.")
super.do_copy(rhs); // copy all parent class data
A = copied_transaction_h.A;
B = copied_transaction_h.B;
op = copied_transaction_h.op;
endfunction : do_copy
21.1.4 clone_me函数
- 使用uvm_transaction的好处之一:在多个模块多个对象中都可以看到相同的数据,在模块较小的TinyALU中可能考不到优势,如果我们的设计包含250个port,原本需要250份备份数据的空间,现在只需要一个即可。
- 双刃剑:上述机制也存在一定的短板:无论任何一个对象对数据进行了修改,整个测试环境看到的数据都会变化。因此引入了MOOCOW(Manual Obligatory Object Copy On Write)机制,如果我们希望对transaction中的数据进行操作就需要强制拷贝一个备份,并在自己的世界里进行修改。
- 当然,有些设计中希望在某个模块(如uvm_callbacks)检测transaction数据,发现异常的时候就进行修改,这样也是充分利用了uvm_transaction的优势。
function command_transaction clone_me();
command_transaction clone;
uvm_object tmp;
tmp = this.clone()