本文从微信公众号--数字IC小站,转载,欢迎关注,微信公众号更新更多更快
SystemVerilog中Packagemp.weixin.qq.com![e4fe42e491c51ff2de252d8373e30658.png](https://i-blog.csdnimg.cn/blog_migrate/9c0041e7d31db1aed0b066593a16584c.jpeg)
Package是systemverilog中的语言结构,它使相关的声明和定义能够组合在一起。Package可能包含类型定义,常量声明,函数和类模板。为了能在一个范围内使用Package,必须先导入它,然后才能引用其内容。
我们一般把不同模块的类定义在不同的Package中,这样可使得分属于不同的模块验证的类来自不同的Package中。
需要注意的是,不同的package可以包含同名不同内容的文件,甚至可以包含同一个文件而不引起多重定义问题。原因在于package是将命名空间分开的,因此如果出现相同文件,我们只需要注意是使用哪个package中的就好。
以下分情况讨论package的使用情况,所有仿真都是基于VCS2019.06版本。
- 如果不引入package,也不使用上次讲到的ifndef宏定义的情况下,多个文`include同一个文件会出现多重定义的情况,所以首先来看下在package下是什么情况。
![f656d9d9329c0fb954e1590e73464d25.png](https://i-blog.csdnimg.cn/blog_migrate/1a1f8d586f9c4c4ae1a849b7d5a9ac17.png)
![9af5cd9f0429084caa26bcfe414d2993.png](https://i-blog.csdnimg.cn/blog_migrate/ab853a32ae5c161fb5a5c4e3e3c61c24.png)
![aef0a351fdb3d9ffe8d015256d4a78db.png](https://i-blog.csdnimg.cn/blog_migrate/c7c2dec6db3a70d17ab655562a6e7f1f.png)
![9c761a505b2e44a41a36b02cb492979d.png](https://i-blog.csdnimg.cn/blog_migrate/30bc3feac6f58a7e864fde8e9d252493.png)
需要注意的是,因为在a_pkg和b_pkg中包含了同样的文件名的文件,因此我们定义的时候建议使用 a_pkg::monitor这种写法,否则可能有错误。
仿真结果如下:
![5e0d9da2ec15ff7b8a39a4df4c152dfb.png](https://i-blog.csdnimg.cn/blog_migrate/212cd8522018922176d8df9e9fbd9b5d.png)
特别的,如果上面的monitor3也更改名字为monitor,那么我们再来看下各种情况的区别:
![e0474e90abf4f4794df38b6baf43768d.png](https://i-blog.csdnimg.cn/blog_migrate/9a7631d2fe13469ca18ef83c960663dc.png)
上图这种写法,仿真结果会报Error:因为在多个地方定义了monitor:
![f9b1a7bd9badeb54aa079f117535f682.png](https://i-blog.csdnimg.cn/blog_migrate/15595bb34b67cb3739a98f240ce7f584.png)
但是需要注意的是,上述代码在questa sim10.6c中是可以通过编译的...所以为了减少不必要的错误,我们推荐使用不同的名称,当然,使用相同名称时,需要所有的类名前都加上*_pkg::,这种写法是任意仿真器都允许的。
需要注意的是,如果把testbench中的class放到module中,上述语句是可以执行的,因此,为了减少不必要的麻烦,我们还是推荐VCS的写法。
- 再加点,如果我们在c_pkg中import入a_pkg,那么我们能不能在module中引入c_pkg,从而调用a_pkg中的class呢?
代码如下所示:
![5298fd5b9d37dd7360ee71c12fc066c7.png](https://i-blog.csdnimg.cn/blog_migrate/d2ab5d707812718ab3e1da489def1a65.png)
![c2298aceea15ed81793ad765066482de.png](https://i-blog.csdnimg.cn/blog_migrate/6c7137ae488815dddf6b2bce2e75040d.png)
![8387425c7d01d131f501b89b12ee34b2.png](https://i-blog.csdnimg.cn/blog_migrate/9a5c8abb929a53913989872803b728d9.png)
结果是不行的,因为import操作使得类型可见范围限制在只调用该import的域,因此到module中则不行了,仿真结果如下:
![f685750919557d724381c4ed3d962231.png](https://i-blog.csdnimg.cn/blog_migrate/db6666cff677d31aec8e7951ed012b7c.png)
解决方法是使用export语句,使得重新得到定义:
![1997aa4598e6d87caaf4b988bcc7cdf2.png](https://i-blog.csdnimg.cn/blog_migrate/64ff9230176d72407e09c7f732f4397a.png)
则仿真结果如下:
![4ca39d30ac0900f9f21a29a34b330e8c.png](https://i-blog.csdnimg.cn/blog_migrate/0e68611d88bf7a9ce37d64e472ec8ce2.png)
- 总结下:
- 我们可以在module、program、interface中通过import的方法引入package。
- package一般用来共享参数、数据、类型、任务、函数以及类等
- 不允许出现reg,wire信号
- 如果是泛式引用,即import *_pkg::*;,则会先在本身的模块、程序内寻找,找不到才会去pkg内寻找。
- 如果是指定引用,如import *_pkg::monitor;则直接调用,这时候我们在module、program中不应该出现相同名字的类型定义,否则报错。
- 在module、program中的二级引用需要添加export *_pkg::*;语句。