前言
之前在几篇博客中提到了下$cast方法的原理和行为:
【system verilog】OOP属性下的构造函数new,虚方法virtual和cast方法(4)
【system verilog】OOP属性下的构造函数new,虚方法virtual和cast方法(3)
【system verilog】OOP属性下的构造函数new,虚方法virtual和cast方法(2)
【system verilog】OOP属性下的构造函数new,虚方法virtual和cast方法(1)
今天发现之前的说法还是有疏漏,补充一下;
两个疏漏
第一点:$cast不检查空句柄
之前聊过$cast的本质,就像下面这个图:
那么问题是,如果$cast(a,b)中的b是一个空句柄,那么$cast是否会告警或者cast失败呢?答案是不会的,这个时候无论是$cast(a,b)还是还是if(!$cast(a,b))都不会报错,比如下面这个测试:
function my_rm::new(string name, uvm_component parent); my_transaction tr0; uvm_sequence_item tr1; super.new(name, parent); if(!$cast(tr0, tr1)) `uvm_fatal("my_rm", "hahaha"); endfunction
跑完的结果:
正因为如此,我们才需要去裹一层宏来处理,比如说这样:
`define prj_cast(to, from) \ if (from == null) begin\ `uvm_fatal("prj_cast", "cast NULL");\ end\ if(!$cast(to, from)) begin\ `uvm_fatal("prj_cast", "cast fatal");\ end\
同样刚刚的代码就会是这样:
function my_rm::new(string name, uvm_component parent); my_transaction tr0; uvm_sequence_item tr1; super.new(name, parent); if(!$cast(tr0, tr1)) `uvm_fatal("my_rm", "hahaha"); `prj_cast(tr0, tr1); endfunction
第二点:空句柄时无脑cast成功
当from为空句柄时,那么就不要指望cast检查什么行为合理了,这个时候是必然成功的。看刚刚的例子就知道了,tr1是父类句柄,tr0是子类句柄,!cast(tr0, tr1)没能检查出问题。当然了,这种也不算漏洞吧,只要你tr1 new()过就可以报出来了:
function my_rm::new(string name, uvm_component parent); my_transaction tr0; uvm_sequence_item tr1 = new(); super.new(name, parent); if(!$cast(tr0, tr1)) `uvm_fatal("my_rm", "hahaha"); endfunction
自我纠正
不知道我是写过还说说过类似这样的话:除了检查是不是左侧句柄最终指向了本身或其子类的空间之外,用$cast和用=没有区别。如果我说过的话,那就当我没说过......
$cast不仅是检查,而且符合标准是会顺利让你通过,而=是无脑不让你过,比如说这个代码:
function my_rm::new(string name, uvm_component parent); my_transaction tr0; uvm_sequence_item tr1 = my_transaction::new(); super.new(name, parent); if(!$cast(tr0, tr1)) `uvm_fatal("my_rm", "hahaha"); //tr0 = tr1; endfunction
可以说完全没有任何问题:
可是如果加上一句:
function my_rm::new(string name, uvm_component parent); my_transaction tr0; uvm_sequence_item tr1 = my_transaction::new(); super.new(name, parent); if(!$cast(tr0, tr1)) `uvm_fatal("my_rm", "hahaha"); tr0 = tr1; endfunction
哪怕tr0是完全可以指向tr1的,那也一样会报编译问题:
只能说=的检查过于苛刻和古板了。