来源| 杰瑞IC验证(ID:Jerry_IC)
|原创作者| Jerry
本文最佳阅读姿势:
1.按顺序看。本文以带入探究的方式进行,而不是直接摆出结论,即每一个小节都以问题导入,进而触发新的问题,层层铺垫递进直至深刻的理解相关细节。
2.建议先自己思考抛出的问题再看解释,效果更佳。
3.篇幅略长,若时间不允许,可收藏分多次阅读。
深吸一口气,正文开始~
暗物质是宇宙中一种不可见的物质,但是却是宇宙中物质的主要组成部分,它神秘而充满诱惑!!!
其实,验证环境中也有一个这样充满神秘的空间,
每个人都会用到它,但是大部分人不知道它叫什么名字,
甚至不会注意到它的存在。
今天Jerry带大家一起探寻验证环境中那个神秘的空间,那个“暗物质”。
1
先铺个垫
话不多说,从下面这个铺垫问题开启我们今天的内容,
请问 ...... 下面这段代码,会打印出什么结果?
两个相同名字的class hello,一个是写在module中,一个是写在package中通过import的方式导入module中,当我们在module中调用hello中的同样相同名字的函数AA()时,到底调用的是module中hello的AA()还是package中hello的AA()呢?
告诉大家,上面这段代码会打印出“I live in module”。
即我们会调用module中hello的AA()。
这个现象原因其实可以简单的理解为:在module内部索引不到的需要的类型才会去package中搜索,说白了就是先在module中找,再去package中找。
有人恍然大悟,“原来Jerry今天是讲package进行import时候的坑啊?class命名很重要啊?”
这位同学说的很对,但这还不够神秘,不是今天我们要去的地方。
其实,上面的例子可以说是package的用法性质,我们import进了module中,但是Jerry想让大家想想,我们通常搭建的验证平台(或者初学者们学习到的代码),import package都在module内部吗?
其实不是,我们常常是像下面这样写:它在module的外面!
对啊,这算什么什么情况?
初学者看到这可能会突然一懵,平时还真没注意这里,写到外面有作用吗?是不是写法有问题?
总之,这个位置确实称得上神秘,总感觉说不太清楚?
2
神秘空间确实存在
接着前面的预热代码,我们再来看3组代码回答3个问题!
大家先不要慌,这3组代码很简单且相似,是预热代码的扩充版本,一分钟就能看懂。
代码一
我们现在有了两个package,a_pkg和b_pkg,还是和开场一样,他们中间以及module中都有一个名字一样叫hello的class,且class中有一个名字完全一样的叫AA的函数。
我们把a_pkg像开场的例子一样import到module中。
(注意,这里为了打消某些同学在看开场代码时可能产生的疑虑就是:import package位置和module中定义的class位置的先后顺序会不会对索引顺序有影响?我们这组例子把a_pkg导入的位置放在module中hello类的下面进行充分证明。)
此外,重要的是我们把b_pkg import到了module的外面,即那个神秘的空间中!
还是老问题:这段代码,会打印出什么结果?
有人明白了,预热问题我们是module和module中导入的package进行PK,看谁更“高贵”谁是VIP中P,现在多了一个,是module、module中导入的package(即a_pkg)、“神秘空间”中导入的package (即b_pkg)进行PK啊。
既然话说这个份上了,不猜了,摊牌了,现在这个代码将打印出“I live in module”。
代码二
这段代码,和上面一样,只不过我们把module里面的class屏蔽了,总是它得第一,该评下谁第二了吧?
module中导入的package(即a_pkg)、“神秘空间”中导入的package (即b_pkg)进行PK。
这段代码,打印出什么结果?
其实,这个代码将打印出“I live in a_pkg”
“神秘空间”不行啊?
到底是真的不行还是写在外面根本就没生效啊?闹着玩儿呢?
我们看看下面这段。
代码三
老大老二都退出了,就给“神秘空间”一个人自己玩。
我们确实看到打印出了“I live in b_pkg”。神秘空间确实存在,暗物质确实存在!
这3段代码不光证明了神秘空间的存在,更扩充了开场得到的关于索引的顺序结论:
需要的类型,先在module内部直接定义的找,找不到再去module内部import的package中找,再找不到会再去module外部的“神秘空间”去找。
Tip:这里顺便提一句,如果担心这种我们上例中的同名混淆的坑出现,可以显示带上package的名字,这也是一种好的coding style哦~
例如上代码改成: b_pkg::hello u_hello=new( ); 这样就指明了使用的是b_bkg的内容了。
3
眼睁睁看清楚“神秘空间”
前面我们确实真切的看到,这个神秘空间确实存在而且知道了它和其他空间的搜索顺序,但是这个神秘空间到底怎么个说法?
比如在module里面,不论是自己定义还是import这其实都算很合理,但是在module外面定义这叫什么事儿?
你说这个是一个合法的空间,那它叫什么啊?
各位稍安勿躁,我们已经看到了“妖怪”的行为,这里Jerry用“照妖镜”---编译工具,让它现出原形,让大家真切的看到妖怪的真面目!
怎么玩呢?我们先试一把,比如下面这段代码:
我们把a_pkg屏蔽掉,但是后面还import它,这个时候会怎么样?
没错,编译器会报语法错误!
我们以vcs编译工具为例子,会报出下面这个样的内容:
我们从这个打印信息可以看出一个秘密,那就是照妖镜会告诉你是名字叫 “tb_top”的这个区域里的问题!
没错,如果我们在“神秘空间”中搞事情,那编译器自然就会“说出”这个“神秘空间”到底是谁!
我们顺手把代码改成如下,屏蔽了b_pkg,然后在“神秘空间”中依然import:
好了,如我们所料,编译器果然说话了!报出如下内容:
编译工具终于告诉我们了,原来这个神秘空间和他都很熟,它的名字叫做---$unit!!
4
认识$unit
通过编译工具,神秘空间已摘下面纱,原来人家有名字啊!叫$unit。
这个哥们到底什么来头?调下档案看看:
Jerry结合定义大体来聊聊,其实就是这么回事:
1、
SystemVerilog源文件编译的时候,一起编译的不管是单文件还是多文件,一起编译就把它叫做一个编译单元,即如果1个文件单独编译,那这个文件就是1个编译单元,10个文件一起编译,这10个文件就是1个编译单元。
(SV手册建议编译器应该要留一个选项,允许指定文件是每个文件一个编译单元或者是所有一起编译文件一个共同编译单元。当然这个各位如果感兴趣可以后续研究下你用的编译工具有没有这样做哈)
通常我们往往都是多文件一起编译,形成唯一1个编译单元。
2、
这个叫编译单元的东西和module其实一样,也有一个作用范围,常叫做“编译单元域”,这个区域就是我们前面提到的神秘空间。
它是不在其他任何范围之内的(例如module、interface、program等),但是一起编译的其他范围都对它可见!
这就是前文为什么我们常常把一些常用的package import到编译单元域里面,一次导入一起编译的文件都可见。
3、
$unit是什么?
其实就是这个编译单元的显示名字,就像前文module的名字tb_top一样。
有了这个名字,我们便可以对编译单元域中的内容显示访问。
本文由“壹伴编辑器”提供技术支持
从相识到相知,从相知到……
到现在为止,Jerry相信大家对我们一直追寻的神秘空间有一个清楚的认知了吧~
说到这里想顺便提上一句,我们常用的编译器指令,即SystemVerilog中以重音符号开始的标识符,如`define等,他们的作用范围是什么?
有人说是全局?
其实不是!他的作用范围就是所在的编译单元域!
因为我们通常多文件一起编译且形成同1个编译单元,所以给我们一种编译器指令是全局生效的幻觉,如果每个文件一个编译单元,那编译器指令也只是某个文件中生效而已~
总结
看到这里的朋友真的是很赞了,我们再回顾下今天的探索思路:
1.以package import的一个细节知识点导入,讲解了在module内部以及module内部导入的package的索引顺序问题。
2.以此知识点对比实际项目中在module之外import常用做法,抛出这个“神秘区域”到底是什么的全文核心探索主题。
3.通过代码对比讲解证明了这个“神秘区域”的存在以及这个区域与其他区域的索引顺序。
4.以给编译器制造错误的方式,让编译器直观的告诉我们这个区域的名字是$unit。
5.认识$unit,引出编译单元的相关知识点,以及点出编译器指令“真正的”作用域。
那么今天就聊到这里,大家有什么问题可以随时评论或点击联系我们与我们从相识到相知,从相知到相爱。
如果在夜里一两点,Jerry还给你回复消息回答问题探讨人生,这是什么精神,这意味着什么......???
意味着……
Jerry真的很喜欢玩手机,哈哈,大家加油,我们下期再见!