[SystemVerilog语法拾遗] 关于package使用时的一些注意事项

[SystemVerilog语法拾遗] 关于package使用时的一些注意事项

我们先看看Systemverilog 2017的标准里对package的定义:
在这里插入图片描述

SV语言提供了一种在多个module、interface、program和checker之间共享parameter、data、type、task、function、sequence、property以及checker声明的机制,即利用package(包)的方式来实现。
package显式声明了一套独立于module之外的命名空间,这么做的好处在于将同一组相关的类、变量声明在统一的命名空间中,这样可以通过package来区别类的归属问题(不同package中允许出现同名类型)。
checker是sv里的一种组件类型(类似于interface一样需要instance,里面主要包含了一些assertion相关的check),这里不做引申。

标准还对package的使用场合做了一些规定
在这里插入图片描述

对上面这段话做如下总结:
1、packgae中一般包含了类型定义(声明变量、枚举类型、struct、class等)、公共的任务、函数(不属于任何的class),后续将这些定义的内容统称为item。
2、package里面不允许出现层次引用item(例如tb.dut…这种),除非定义在package内或者通过import package可见的,这就导致了package里包含的class就不同直接通过hierarchy的方式访问dut里的信号了。
3、package不允许访问定义在 u n i t 编译单元里的 i t e m ,关于这一点非常重要,这就导致了我们定义在全局的 c l a s s 、枚举类型、一般变量类型在 p a c k a g e 内无法访问,但是 i n t e r f a c e 编译了之后在 p a c k a g e 内的 c l a s s 里是可以识别的,后面我们也会有个例子来印证这个描述。这点区别于 m o d u l e 、 i n t e r f a c e 等静态类型,在 unit编译单元里的item,关于这一点非常重要,这就导致了我们定义在全局的class、枚举类型、一般变量类型在package内无法访问,但是interface编译了之后在package内的class里是可以识别的,后面我们也会有个例子来印证这个描述。这点区别于module、interface等静态类型,在 unit编译单元里的item,关于这一点非常重要,这就导致了我们定义在全局的class、枚举类型、一般变量类型在package内无法访问,但是interface编译了之后在package内的class里是可以识别的,后面我们也会有个例子来印证这个描述。这点区别于moduleinterface等静态类型,在unit编译单元定义的全局item在后编译的module/interface里是可见,所以我们全局import uvm_pkg:😗*后在module和interface里就不需要在import了,但是在package里还需要再import uvm_pkg:😗;

引用package里定义的item可以有两种方法:
1、通过import package::item; 将package里定义的item导入当前namespace(或者namescope),也可以将item换成通配符*导入所有item。
2、通过 :: 的访问方式直接访问package中定义的item。

下面我们看看package作用域相关的问题
在module内部 “import pkg_name:😗”,则代表的是该package中定义的类型可能会在module等内部有效可见。只有当module等无法在内部索引到正确地类型时,才会转而去package中去搜寻,如果索引到了那么该package中的这个类型则变得在module中可见。
package a_pkg;
class mon;
endclass
endpackage

module module1;
class mon;
endclass
import a_pkg:😗;
mon mon1 = new(); // 已经有内部mon定义,因此不会搜寻a_pkg
endmodule

如果用户使用了 “import pkg_name::type_name”,则表示直接让package_name::type_name类型在module等内部变为可见,那么此时需要注意的是,module内部不应该再有其它同名的类型定义,避免发生同名类型定义的冲突。
package a_pkg;
class mon;
endclass
endpackage

module module1;
class mon;
endclass
import a_pkg::mon;
mon mon1 = new(); // 同时有内部mon定义和引入a_pkg::mon,发生同名类型冲突
endmodule

如果在package a_pkg中import了package b_pkg::type_b,那么在module1中import a_pkg::*时,无法引用到type_b。因为a_pkg只是使得b_pkg::type_b在a_pkg域中可见并加以使用,并未定义在a_pkg中。所以,用户需要牢记一点的是,import操作使得类型可见的域只是调用该import时当前的域。例如下面的例子中,a_pkg中可见b_pkg::b_mon,但是module1则无法可见a_pkg::b_mon。
package b_pkg;
class b_mon;
endclass
endpackage

package a_pkg;
import b_pkg::b_mon;
class a_mon;
endclass
endpackage

module module1;
import a_pkg:😗;
a_mon mon1 = new(); // a_mon可见
b_mon mon2 = new(); // b_mon不可见,报错
endmodule

要解决上面的问题,用户可以使用export来让b_mon在a_pkg中得到二次定义。从下面这个例子中可以发现,a_pkg中需要额外使用export来让b_pkg::b_mon在a_pkg得到定义。因此,在module1中import a_pkg:😗,可以搜寻到a_pkg中的a_mon和b_mon两种类型。
package b_pkg;
class b_mon;
endclass
endpackage

package a_pkg;
import b_pkg::b_mon;
export b_pkg::b_mon;
class a_mon;
endclass
endpackage

module module1;
import a_pkg:😗;
a_mon mon1 = new();
b_mon mon2 = new();
endmodule

s d t 是 s v 内部自定义的 p a c k a g e ,我们使用到的系统函数和任务,例如 sdt是sv内部自定义的package,我们使用到的系统函数和任务,例如 sdtsv内部自定义的package,我们使用到的系统函数和任务,例如stop()、 r a n d o m i z e ( ) 等等凡是带有“ randomize()等等凡是带有“ randomize()等等凡是带有”符号的方法,另外一种调用的方式是std::method,例如std::randomize()。这隐含地是所有的系统方法都是预定义在一个称之为std包中的。用户只能使用这些包内的方法和类型,无法二次对std包做出修改和添加。

最后我们补充一个关于package对$unit编译单元可见域的仿真实验
全局编译的apb_interface在package中的文件里可见,所以在driver中可以声明virtual spi_interface
在这里插入图片描述

但是spi_master_driver里无法识别红色框中定义的枚举类型,是因为该类型定义在了 u n i t 编译单元中,即全局类型。 p a c k a g e 域中无法使用 unit编译单元中,即全局类型。 package域中无法使用 unit编译单元中,即全局类型。package域中无法使用unit域中定义的内容,因而我们希望不要在 u n i t 空间进行任何声明,所有共享的声明都要在 p a c k a g e 中。解决办法:将枚举类型的定义放到一个 p a c k a g e 中,在 unit空间进行任何声明,所有共享的声明都要在package中。 解决办法: 将枚举类型的定义放到一个package中,在 unit空间进行任何声明,所有共享的声明都要在package中。解决办法:将枚举类型的定义放到一个package中,在unit中import使得interface中能看到,在spi_pkg中import使得spi_master_driver中能看到就解决了这个问题了,同时像spi_interface文件一样也在$unit域中将该spi_global_pkg文件`include进来编译成全局可见
在这里插入图片描述
在这里插入图片描述

不仅仅是枚举类型,我们全局定义class和int在package中都是看不到的
在这里插入图片描述
在这里插入图片描述

仿真结果:
在这里插入图片描述

所以我们给出如下使用package的建议:
不要在 u n i t 空间进行任何声明,所有共享的声明都要在 p a c k a g e 中。需要时,可以将 p a c k a g e 导入到 unit空间进行任何声明,所有共享的声明都要在package中。 需要时,可以将package导入到 unit空间进行任何声明,所有共享的声明都要在package中。需要时,可以将package导入到unit中。
$unit空间声明变量或者方法时,会导致声明过于分散,结构乱,逻辑差,不利于调试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值