前言
该内容与我还没有写的<uvm field机制以及UVM树>紧密相关,你可以先去看看别人写的内容理解一下
从现在开始,你把自己当成一个游戏玩家。在玩一个叫做UVM的游戏,需要在UVM世界里面建立一个完整可以运行的体系。你可以运用这个游戏给你的资源,为了让这个体系更好地运行,你建立并且管理了一个机构(uvm树),这个机构最顶层,最大的是uvm_root,也就是uvm_test_top,你在这个顶层的下面衍生建立了许多小的附属办公室。 机构的结构是这样的: 这是一幢大楼,楼顶是等级最高的办公室,有了最高的办公室才有下面的小办公室,括号内的名字是办公室的类别,上面的才是办公室真正的名字,就相当于:别列兹喵(台州人),你得用别列兹喵称呼我,不能用台州人称呼我,毕竟一条街上可能有30个台州人。
为了更好地管理这个机构,让机构变得有序,机构之间的不同办公室需要用同一个纲领来指导工作。为了避免重复下发的工作。于是你使用了这个世界给你的信箱工具:config_db
config机制
机制概要
你可以当做这个名为uvm的世界,为每一个办公室都建立了一个信箱区域。当你需要下发一个纲领时,你需要另一个办公室跟着你的纲领行事,你就可以在这个办公室边上的放置一个信箱,给信箱取一个名字,每当你纲领更新的时候,你就可以直接改信箱内容,而那个办公室需要使用这个纲领的时候,就直接去看信箱的内容就可以了。 简而言之,就是一个指向同一个区域的指针。
现在我们需要建立一个信箱,信箱里面放我们的interface内容,那么我们需要确认的就有几个点: 1.设立信箱的办公室 2.信箱的地点 3.什么信箱 3.信箱内容 4.哪些办公室可以取信
config_db#()::set
既然你需要建立信箱,那么你需要填写一个申请单,这个申请单长这个样子: uvm_config_db#(uvm_object)::set(null,“uvm_test_top.drv”,“vif”,vif); 首先,申请单应该在你需要下发指令的地方填写,但是这个下发指令的地方未必是设立信箱的办公室。 我们可以这么理解,有一个int类型的A值,值是在mdl中定义的,那么mdl就应该是写申请单的地方(就是写config_db函数的地点),但是信箱可以让env来建立(由config_db函数来定义)。 那这个时候,这个申请单就应该长这样: uvm_config_db#(int)::set(uvm_test_top.env,“scb”,“A”,5); 现在,我们就理解了set后面的第一个参数的意义:设立信箱的办公室。这里需要注意一点,设立信箱的必须是树状结构里面的固定办公室,不能是在树状结构之外的编外组织,比如sequence。但是申请单可以写在编外组织内。这就可以理解为什么需要两个参数来定义一个设立信箱的地址。
uvm_config_db#(uvm_object)::set(null,“uvm_test_top.drv”,“A”,5); 接下来我们回头来说说第一个括号内的参数含义。前面有说到,什么信箱是需要规定的,第一个uvm_object就是信箱的类型。了解工厂机制的都知道,uvm_object是UVM的一个基础类,里面包括了大部分的基础类型,以及你后来在这个基础上定义的其他类型。 简单的来说,这就是个下拉的菜单选项,你可以在里面选择他已经有的类,包括各种参数类型,和你后续定义的类型。
uvm_config_db#(uvm_object)::set(uvm_test_top.env,“scb”,“A”,b); 现在我们知道了信箱的类型和设立信箱的办公室,那么来说说如何确认信箱的地点。第二个括号内的地址就是信箱的地点,但是是第一个地址的相对地址。 可以这么理解:env被确认是设立信箱的办公室,所以由他的视角看出去,按图索骥,scb是他下面的部门,他就只需要写scb就可以了,如果是sqr办公室,他就需要写成i_agt.aqr。这就是相对于env的办公室地址。
uvm_config_db#(uvm_object)::set(uvm_test_top.env,“scb”,“A”,b); 这样,信箱就建立完成了,还剩下信箱的名字和信箱内容,分别是括号内的第三个和第四个参数。第四个值可以是一个固定值,也可以是一个在写申请单的地方定义的一个参数,你只要改变了这个参数,信箱内的值就会相应的改变。
config_db#()::get
信箱建立完成了,那么需要用到信箱内容的地方就需要去取,这时候,我们也需要在用到信箱内容的地方写申请单,也就是: uvm_config_db#(uvm_object)::get(this,"",“A”,a); 这个函数的第一个括号与上面的函数是一样的,是信箱的类型,你需要取同样的内容,那必然要把类型设置成一致。
第二个括号的前三个内容,就奠定了这个办公室(或许不是办公室,只是个编外组织),需要去哪里取信。前两个是取信的地址,我们可以结合上面设立信箱的申请单来看,这个信箱设立在了scb的办公室。假如就是scb办公室需要取这个信,那么他的第一个参数就可以写成this,第二个设置为空,也就是在自己这里取就可以了。 事实上这里括号内的两个参数是冗余的,只需要一个就可以决定去哪里取信。但也并不完全冗余。
第三个是信箱的名字,与设立信箱时的一致(也可以不一致,但是最好一致,所以这里不写不一致的情况)。 第四个参数就是实际的值,一般来说,会在填写面单的地方定义一个相同类型的参数,然后把信箱内取到的值赋给他,就可以使用这个值了。
null
get后面括号内的第二个参数不完全冗余是因为有一个参数null的存在,null的意思就是这个机构的顶层,也就是uvm_test_top,这里是为了简化写法,避免玩家写错顶层名字,就可以把第一个参数定义为null,第二个参数从顶层的后面开始写相对地址即可,这里在set函数中也是同样的用法。设立顶层为设立信箱的机构,然后写相对地址,指示信箱具体设立在哪里。
优先级
加入在不同的地方都填写了一个需要设立在相同办公室的相同名字的信箱,最后这个信箱的内容是由谁来决定的呢? 信箱的内容由建立办公室的等级决定,等级越高,这个信箱就该是谁的。 比如你在mdl和scb都填写了申请单,但是mdl的申请的信箱是由env建立的,i_agt申请的信箱是由自己建立的 mdl:uvm_config_db#(int)::set(uvm_test_top.env,“i_agt.sqr",“A”,a); i_agt:uvm_config_db#(int)::set(this,“sqr",“A”,a); 虽然他们发送的是同样的地方,但是只有mdl的信箱会被真正地建立起来,因为env的等级更高一些,信箱内的内容也将是由mdl来决定的。
假如是由同一个地方建立的信箱呢? mdl:uvm_config_db#(int)::set(uvm_test_top.env,“i_agt.sqr",“A”,a); i_agt:uvm_config_db#(int)::set(uvm_test_top.env,“i_agt.sqr",“A”,a); 那么他们两个共用这同一个信箱,都可以对信箱内的内容进行改变,所以在sqr中取到的将是最新的值。
看到这里,我相信你就已经可以驾驭这个函数的大部分使用场景了。
|