从标题来看,内容与SystemVerilog的拷贝有关,既然是拷贝,为什么叫浅拷贝呢 ?本文来聊一聊什么是SystemVerilog的浅拷贝,其现象是什么,并且举例说明我们应该如何使用它。
什么是浅拷贝 ?
浅拷贝,英文名为 shallow copy,顾名思义,copy是浅层次的,不彻底的。一言以蔽之:对象的拷贝,对于SystemVerilog 常用的数据类型(例如int型)则会正常拷贝,对于class数据类型,拷贝则只是copy其引用。
为了很好的说明浅拷贝,举个栗子
- class p2s_tr,有成员变量 int data.
- class p2s_item,内含p2s_tr,即其中例化了 p2s_tr.
- 在sequence中,做了如下步骤:
1)create p2s_item,其名字为 req,并打印其内容
2)create p2s_item,其名字为 req_copy,将req 的内容复制给 req_copy,并打印其内容(复制语句为下图中第31行,req_copy = new req)
3)修改 req 的内容,然后分别打印 req 与 req_copy 的内容,观察有什么变化
仿真结果如下图所示:
可以看出,req 的原始内容与 copy 后的 req_copy的内容相同,可见 copy已经成功了,且容易造成假象,copy后的数据属于自己拥有,不受原始数据的影响,即如果原始数据被修改,那么copy后的数据不会被影响,真的是这样吗?
接下来,修改 req.data/req.addr/req.read/req.write以及req.tr.data,然后再次打印 req 的内容以及 req_copy的内容。仿真结果看出,除了 req_copy.tr.data 随着 req.tr.data被改变之外,其他变量都不受影响。
为什么会这样呢 ?
这个现象就是 SystemVerilog的浅拷贝造成的。由于 p2s_tr 包含在 p2s_item 中(暂且称 p2s_tr 为 p2s_item的内部类),即一个类中包含另一个类的句柄,那么在拷贝时,其实只拷贝了内部类的引用,也就是其句柄,并不会将内部类的成员变量一并拷贝。
这样会有什么问题呢?
由于是浅拷贝,如果修改原始数据,那么会影响到 copy的数据。(例子中 req.tr.data被修改后,req_copy.tr.data 同样被修改了,因为此时 req.tr 与 req_copy.tr 其实引用的同一个对象)。如果在验证的过程中用到了SV的拷贝,这一点一定要格外注意,否则容易出现非常奇怪且异常隐秘的问题,难以debug。
那么我们应该怎么做呢?
如果非要使用 SV 的 copy ,那么建议每个对象使用自己的存储空间,即不要使用浅拷贝。如何将一个或者多个内部类再次拷贝使其拥有自己的存储空间,需要用户自己去维护。
如果内部类较少的情况下,可以手动的去copy。如果内部类较多的情况下,需要编写递归函数,通过递归函数将内部类一一地 create 出来,然后将需要 copy 的类复制过来。