暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SV lab5 分析

IC打工魂 2022-07-25
804
lab4只是部分采用类替代,lab5将替换更多组件,验证结构如下图所示

而代码实现上,在program内,需要有Generatro,Driver, Scoreboard和Receiver类支持

下面分析类的实现,研究一个类,只需要掌握其数据的含义和操作数据的方法。程序设计,不过是对变量进行操作。
1、router_test.h
头文件一般负责定义,该文件将Packet类设置为可以先使用后声明,同时将消息类型为Packet对象的信箱设置为pkt_mbox,通过pkt_mbox声明句柄

2、Generator.sv
Generator赋值激励值的产生,比dut的端口层次更高,可以说它负责功能,即应该发送什么,而Driver则是负责如何把Generator的数据正确通过协议时序发送出去。
其组成如下,成员变量name用于区分不同的实例,pkt2send句柄可以通过randomize方法随机化其成员,out_box是信箱动态数组(有中括号)。

其中,new方法对name赋初值,创建Packet对象pkt2send,然后分配16个信箱的存储空间,对于每一个信箱使用new()方法创建一个无界信箱。由于共有16个通道,每个通道都有自己独立的激励。

gen方法通过.name访问成员变量name修改其名称,通过randomize方法对随机变量赋值。在调用randomize方法最好在if内,如此可以检查随机化的成败。

start方法要产生run_for_packets次激励,使用for循环控制次数,在一次激励中,先调用gen方法随机化pkt2send句柄指向的对象,然后通过浅拷贝将Generator类的pkt2send对象拷贝给pkt,最后在对应的通道的信箱存入Packet句柄。

3、DriverBase.sv
该部分,将负责激励的部分封装成一个类。通过虚接口rtr_io控制端口信号的电平,name用于区分不同的实例,sa,da,payload三个成员值由Generatro产生。

new方法实现如下,new方法主要对成员变量初始化赋值。DriveBase作为基类,负责对name和rtr_io变量进行赋值

其他方法负责发送激励,与之前的类似,只是访问接口信号的层次改变了,DriverBase类的实例要控制接口信号时,要使用this指针访问rtr_io成员,rtr_io就能访问cb内的具体信号。

4、Driver.sv
不改变原来的代码而修改设计功能,继承是个不错的方案。
基类DriverBase只是完成了由sa,da,payload控制一次传输,但并没有实现如何拿到Generator的数据。Driver类将补充实现
其成员如下,driver既要通过信箱拿到Generator的数据,还要把数据发送给Scoreboard参与比较。因此不同组件的通信,需要信箱in_box和out_box,另外还需要信号量sem动态数组,用于进程间通信。

new方法首先调用父类的new方法,一般子类的new方法第一行语句就是调用父类new方法。父类new方法需要name和rtr_io参数。尽管Driver类没有定义sa成员,但父类有,因此把port_id传给sa,要注意的是,激励部分只需要知道sa就可以了。另外,还要传入sem,in_box和out_box对成员赋初值

start方法,通过in_box的get方法接收Generator的信息存入变量pkt2send中,由于每个通道都有driver,因此判断pkt2send的sa是否和当前通道的sa相等,不相等则退出,重新get信息。当sa相等时,将pkt2send的da成员和payload成员赋给Driver的对应成员。
为了控制与Scoreboard的通信,毕竟完成一次发送就和接收端进行一次比较,因此要让Driver发完后再让Scoreboard检查。代码中,将通道da的信号量sem[da]通过get获取1个key,然后执行send方法完成一次激励发送,把pkt2send写入信箱out_box,最后返还key。这里阻塞接收端,理论上发送和接收都是并行工作,但显然发送先于接收

5、ReceiverBase.sv
该类负责对输出端口监测,通过rtr_io访问具体的信号,name用于区分实例,da则是表征哪个输出通道,pkt2cmp_payload则是将一次接收数据存入队列中,还有一个pkt2cmp句柄,毕竟通信的消息是Packet句柄

new方法要初始化name和rtr_io,并要创建Packet实例pkt2cmp。

recv方法,是原来的改版,不过是通过类的方法调用get_payload,get_payload方法可以得到队列pkt2cmp_payload,最后把da和pkt2cmp_payload组织成一个Packet实例,即用pkt2cmp存储结果

get_payload方法逻辑没有改变,只是变量都要采用类的方式访问

6、Receiver.sv
Receiver.sv仅仅采样interface信号,把结果存入成员pkt2cmp。Receiver增加了信箱和Scoreboard通信
其组成如下,out_box成员用于和Scoreboard通信

new方法如下,依然是对成员赋初值

start方法首先调用recv方法得到采样数据pkt2cmp,然后通过浅拷贝赋值给pkt,并存入信箱。

7、Scoreboard.sv
该类实现比较的功能,是对原来任务check的封装实现。其成员如下,为了比较,需要从Driver和Receiver接收数据,接收的Packet句柄分别存入pkt2send和pkt2cmp,即从信箱到本地。为了功能的正确性,还需要参考模型,即refPkt,该队列元素为Packet句柄。为了进程间通信,成员DONE用于触发

new方法如下,要注意的是传入的信箱句柄参数可能为空,因此判断其是否为空,为空则为信箱创建实例。

start方法先调用receiver_mbox信箱get方法从receiver拿到输出结果存入pkt2cmp,然后通过while循环拿出所有的driver_mbox信息,将其存入refPkt,然后调用check方法

check方法首先通过find_first_index方法查找第一个匹配da和pkt2cmp.da相等的元素索引,该方法返回一个队列。然后通过索引访问refPkt,赋值给pkt2send,然后调用Packet类的compare方法进行比较。当所有数据都比较完毕,触发DONE事件

8、test.sv
首先声明组件句柄,由于Driver和Receiver都有16个通道,采用动态数组。

再initial块,创建类实例,动态数组要先声明大小,对于每个通道的信号量sem初始分配1个key,输入通道连接Generator的out_box成员,即连接通过new赋值实现,同时连接Scoreboard的driver_mbox成员。对于输出通道,连接Scoreboard的receiver_mbox成员。
完成组件的连接后,调用任务reset进行复位,然后调用每个组件的start方法,最后等待DONE事件触发后结束

9、总述
下图反映了类之间的联系,图中不足之处有driver和receiver不是邮箱数组,即对于一个driver实例而言,只有一个inbox和outbox,这里简易起见,只画一个driver连接generator


文章转载自IC打工魂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论