uvm_primer ch21 uvm transaction
MOOCOW
- 使用uvm_transaction的好处之一:在多个模块多个对象中都可以看到相同的数据,在模块较小的TinyALU中可能考不到优势,如果我们的设计包含250个port,原本需要250份备份数据的空间,现在只需要一个即可。
- 双刃剑:上述机制也存在一定的短板:
无论任何一个对象对数据进行了修改,整个测试环境看到的数据都会变化。因此引入了MOOCOW(Manual Obligatory Object Copy On Write)机制,如果我们希望对transaction中的数据进行操作就需要强制拷贝一个备份,并在自己的世界里进行修改。
- 当然,有些设计中希望在某个模块(如uvm_callbacks)检测transaction数据,发现异常的时候就进行修改,这样也是充分利用了uvm_transaction的优势。
通过多个handle来共享一个对象;
$sformatf 是sv中返回一个特定格式字符串的函数,可以用在uvm_info中
function string convert2string();
string s;
s = $sformatf("A: %2h B: %2h op: %s",
A, B, op.name());
return s;
endfunction : convert2string
clone_me函数
uvm_object类和其子类都包含copy()函数和clone()函数,其中copy函数拷贝一个对象的数据至另一个同类型对象,clone函数返回数据完全一致的同类型的对象;copy是将数据拷贝一份,clone是返回一个新的对象。???还是有疑问,两种是否共享内存空间
- clone是肯定不共享存储空间的,返回的对象是一个和原来独立的;
copy函数和clone函数能够工作的前提是:我们必须重构do_copy函数,do_copy函数的工作机制和我们上一章节定义lion的convert2string的机制一致,需要调用父类的同名函数。
在command_transaction中定义
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")
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
function command_transaction clone_me();
command_transaction clone;
uvm_object tmp;
tmp = this.clone(); //通过clone函数,我们得到的是一个新的对象,具有独立的存储空间
$cast(clone, tmp);
return clone; //函数的返回值是新的对象,和this具有不同的存储空间,但是包含完全一致的数据
endfunction : clone_me
transaction 重写
class add_test extends random_test;
`uvm_component_utils(add_test);
function void build_phase(uvm_phase phase);
command_transaction::type_id::set_type_override(add_transaction::get_type());
super.build_phase(phase);
endfunction : build_phase
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction : new
endclass
get_type()
- get_type ()函数:返回当前对象的代理(或者wrapper)。默认的实现方式会产生一个error并返回null。要启用此方法,用户的子类型必须实现返回子类型包装的版本。
- 因为uvm_component是uvm_object的子类,所以uvm_component也可以使用这个方法;
- 一般是在重载的情况下使用
function uvm_object_wrapper uvm_object::get_type();
uvm_report_error("NOTYPID", "get_type not implemented in derived class.", UVM_NONE);
return null;
endfunction
uvm_config_db #(uvm_object_wrapper)::set(this, "m_env.rst_agent.rst_seqr.reset_phase", "default_sequence", reset_sequence::get_type() );
- get_object_type ()函数:返回当前对象的代理(或者wrapper)。与get_type()方法类似,但使用已分配的对象来确定要访问的类型代理(而不是使用静态对象)。使用工厂机制并通过get_type_name()的返回值来进行查找,如果通过get_type_name()返回的类型没有注册工厂机制,那么返回空句柄。
typedef
typedef class uvm_report_object;
typedef class uvm_object_wrapper; //uvm_object_wrapper=class
typedef class uvm_objection;
typedef class uvm_component;
typedef bit[31:0] uint;
在driver中常用clone
uvm_object.sv中对于clone的定义
// clone
// -----
function uvm_object uvm_object::clone();
uvm_object tmp;
tmp = this.create(get_name());
if(tmp == null)
uvm_report_warning("CRFLD", $sformatf("The create method failed for %s, object cannot be cloned", get_name()), UVM_NONE);
else
tmp.copy(this);
return(tmp);
endfunction
这个用法经常在driver/monitor中使用;
这里的rsp和req都是item;
class my_driver extends uvm_driver
...
task run_phase(uvm_phase phase)
seq_item_port.try_next_item(req);
$cast(rsp, req.clone()) //把req.clone()然后给rsp,这样rsp和req就是独立的了;
endtask
copy()、clone()和create()方法之间有什么区别?
【数字IC前端】UVM常见问题系列
create()方法用于构造一个对象。
copy()方法用于将一个对象复制到另一个对象。
clone()方法同时完成对象的创建和复制。
SV中的shallow copy 和 deep
SV中的shallow copy 和 deep
如果在SV中要deep copy的话,就得为所有包含的类都准备好copy函数,既容易出错,工作量又大。好消息是UVM已经内建了copy以及clone操作,可以将你从手写copy中解放出来,我们会在后续的文章中讲解其中的细节,