System Verilog(SV)语言的Class本身就带有“打包”的基因。众所周知,SV语言的很多特性是派生自C++语言的。C++的class就把变量、参数以及相关的处理操作都打包在一起了。SV的class也天然具备了这个品性。关于这点本文不过多赘述,只谈谈与验证者编码时可真真切切直观感受到的那些“打包”的操作痕迹。
Chapter1. config_file(cfg)
验证者在验证平台中定义的参数和变量,既可调整
仿真的行为,也可约束配置的范围,是对验证平台的必要的装点和修饰。若把验证平台比作一个姑娘,那么参数和变量就像是姑娘身上的发卡、耳环、项链和手表。
通常验证者会创建一个config_file(cfg),在其中定义参数和变量。对于一些rand变量,也会在该文件中定义相关的constraints。同时,也会在该cfg文件中对全部的变量参数进行注册(register)。
关于这种做法,有同学难免要问:在验证平台组件中,直接定义要用的参数或变量,不香么?随时要用,随手定义。
闵老师觉得,这个世界上绝对的事情非常稀少,尤其是在成年人的世界,非黑即白,从来鲜有。这也是他多年成长的领悟之一。
具体来说,与在组件中直接定义参数和变量相比,统一定义,即用cfg文件“打包”全部的参数和变量,有三点好处:两小一大。
小的好处1:rand变量可统一随机,即通过执行cfg.randomize()实现全部cfg内的rand变量都根据定义的constraint进行随机。一步操作,生成全部变量的随机值。
小的好处2:可统一将全部随机参数和变量,在cfg中进行注册。
大的好处:集中管理全部的参数和变量。举例说明:
其一,参数变量都在cfg中,review代码比较方便,提升了代码规范性和可读性。
其二,涉及到参数和变量的访问可都通过访问cfg实现,操作方便。
其三,可通过传递cfg句柄的方法实现全部的参数和变量的“打包”传输。
其四,统一随机全部rand变量。
其五,可通过继承扩展(extend)cfg文件,或直接实例化cfg所在验证平台,实现对cfg的重用,进而实现对该验证平台的参数和变量的重用,也提升了验证平台的重用性。
姑娘通常会找一个包统一放置她们的发卡、耳环、项链和手表,验证者也应该写一个cfg文件统一“打包”变量和参数。
Chapter2. interface.clock_block
interface文件本身就把一个接口的全部信号打包在一起了。而clock_block可认为是二次打包。即针对同一接口的信号,进行了统一的时钟同步处理和setup
time_holdTime的行为模拟。
在上图中,input skew可等价于setup time,Output skew可等价于hold time。在仿真中,clock block的信号的采样时刻应该是clock有效边沿之前input skew时间的时刻。新的数据驱动到接口的时刻是clock有效边沿之后经过output skew时间的时刻。
在clock block中定义的信号是有方向性的,这个方向是相对于TestBench或DUT而定的。参照系不同,方向也就不同。为了解决这个问题,SV又定义了modport。验证者在interface中可通过modport把不同参照系的clock block分别进行实例化,以便分开使用。该操作也可看做是对clock block的“打包”。如此这般,经过对接口信号的三次“打包”,可整体统一处理接口信号的驱动和采样,也提升了代码的规范性和清晰度。
Chapter 3. checker_scoreboard
Scoreboard,也叫计分板,是针对一种特定的事务进行统计的装置。例如在基于令牌(Token)的Cache Coherence协议中,就通过scoreboard统计Token的数目。
在验证者看来,scoreboard是针对一种特定的报文(transaction)进行自动化的比对和结果统计的组件。报文是扩展自uvm_sequence_item,报文的比对函数compare()也在uvm_sequence_item的父类uvm_object中被定义好了。因此,一个scoreboard可实现一种特定报文的检查。
当需要检查多种报文该怎样做?直接在环境顶层文件env中实例化多个scoreboard吗?
从“打包”的角度看,直接定义多个scoreboard不好。会显得代码组件分布的有些散乱,就像把各色的盘子零散的放到了厨房的各个角落。还是建议把各个scoreboard也“打包”一下。创建一个专门的组件中,姑且给他命名为checker。再将各个scoreboard实例化到checker中。最后只需要再在env中实例化一个checker组件。这样一来,checker组件作为专门负责检查报文的组件,在验证平台中占据了重要的一席之地,不仅所有的scoreboard也都归他管理,而且环境中定义的一些动态比对操作,检查RTL信号的操作,也可“打包”放置到checker中。就像橱柜收纳了所有的盘子碗碟后厨房变得整洁了,checker组件使得验证平台变得规整了很多。
Chapter 4. agent_drv/mon/seqr/transaction
有一天,几个验证同学在教室里聊天,有个同学提了一个问题:“transaction是报文,sequence管理报文,sequencer发送报文,driver将事务级的报文按时序驱动到接口,monitor把接口的时序采样成事务级的报文。他们似乎已把接口的行为模型要干的活儿都干完了,为啥UVM还要搞一个agent?这个家伙在接口数据流的行为模拟中,除了把sequencer和driver连接起来,也没有啥具体的或者实质性的工作,为啥UVM还把整个接口行为模拟相关的多个组件组合起来称为agent。”
“凭啥?怎么看怎么像是一个尸位素餐却身居高位的闲人。”提问的同学越说越生气。
“其实这里有“打包”的思想的影子呢。”闵老师走进教室,轻轻拍了拍那同学的肩膀,让他坐下。“如果没有agent,各个接口行为模型的各个组件散落开来,那么验证平台会多么散乱呀,尤其是当DUT有多个接口,需要开发多个接口的行为模型时。验证者要怎么安置这些driver,monitor,sequencer呢,直接把它们都实例化到env中去吗,那岂不是乱了套了。咱们是高三16班,试想下如果没有分班,整个年级的学生都做在一起,那可怎么上课。”
“哦,我明白了,就是把agent当成一个空空的口袋,把接口行为模型的那些代码都装进去,打个包,方便存取。”同学恍然大悟,“我妈也买了一个大衣柜,专门用来放她的成堆的衣服、鞋包。”
Chapter5. virtual_sequencer/virtual_sequence
曾经有位验证者说过,UVM定义的virtual sequencer有点“鸡肋”。鸡肋者,食之无味,弃之可惜也。用uvm_do_on发送sequence时,可以直接使用各个agent.sequencer。定义的virtual sequencer也只是在其中把各个agent的sequencer声明一下,然后需要把各个agent.sequencer的句柄指向该virtual sequencer中声明的各个sequencer。实质上,还是用的各agent.sequencer。
既然这样,何必多此一举呢?
揣测UVM定义virtual sequencer的初衷,应该也是“打包”的思想。通过virtual sequencer把各个agent.sequencer“打包”在一起,或在test case中直接使用,或传输到virtual sequence中使用都方便很多,代码也会整洁很多。
刚提到了virtual sequence。当构造一个复杂的场景时,需要多个sequence进行配合。把多个sequence“打包”在一起,形成一个big-sequence。这便是virtual sequence。从此角度看,这也是“打包”思想的体现。
至此,我们的示例也讲完了。
原作者:一只特立独行的猪