【PCIe】CDNS PCIe VIP -- Callback使用举例

4 篇文章 2 订阅

【PCIe】CDNS PCIe VIP 杂记 -- Callback-CSDN博客

前言:之前针对CDNS PCIe VIP Calback部分进行了学习,并写了上面的博客。学习就是为了应用,本文就将记录一些我实际用到的我觉得比较典型的例子。仅供学习参考。

需求:

PCIe VIP作为EP,DUT是RC。EP发了一笔memory write,后对同一个地址进行memory read,想要check都回来的read data和write data是否一致。

注:实际按照CDNS PCIe VIP UG里讲的使用方法,VIP的使用一般都是成对出现的,即一个active agent(这里是EP本P)和一个passive agent(这里是DUT RC的monitor)作为monitor。因此,即使不做上述需求的check,这里的active和passive agent也是会进行比对的。从实际仿真结果也证明如此。

分析&实现:

对于read data:

基于callback的学习认知,可以从callback入手。之前的博文里也说了,对于read data可以从callback:TL_TX_completion_queue_exit里从payloadAccumulated[]获得。

第一种方法:

在CbF里直接从payloadAccumulated[]中获取read data。具体实现code如下。

基于我之前博文讲的,这种方法的实现其实是在monitor重载CbF function函数的。

但是这种方法,因为在function实现的,不能在仿真过程中实时进行比对。【当然,针对单一test测试,所有操作包括check都可以在monitor里实现,但并不通用】至少目前为止,我自己并没有找到合适好用的方法。因此,此方法比较适合monitor。

第二种方法: 

 在sequence里实现,即在发送完memory read request traffic后,并行等待TL_TX_completion_queue_exit callbck trigger后,进一步获取read data。具体实现code如下。

对于write data: 

和read data类似,我们也可以从相应的callback函数获取,具体如下。

第一种方法:

根据这张图https://img-blog.csdnimg.cn/direct/7ab567150aa24a8496bfbe89c53d7fc2.png看,可以从callback:TL_TX_packet或者TL_transmit_queue_exit里获取。

由于我knowledge的limitation,目前我觉得这种只适合进行monitor使用。

第二种方法:

同样在sequence里进行实现。在实现过程中,我也尝试过从调用callback着手,但是如下这种实现方式会造成仿真hang。

之前一直找不到原因,后来对callback打印信息的capture,发现:比如我这里连续发了2笔write和2笔read,VIP model是会将这4笔traffic同时放到transmit queue里的。从实际仿真的时间戳也可以看出来。因此,我上面的while是会漏capture的。【除非就是每发一笔就等一笔,但这样就和我之前讲的一样,会造成仿真一笔一笔发送-完成,这在大量traffic的仿真很不现实也不通用】

因此,就只能【目前基于我自己的knowledge】在发traffic的时候获取地址和write data,这很容易办到。打印信息也如上。因此在sequence里做data check也就顺利成章了。

=============================分割线=======================================

更新一下完整的check方法:

上面的例子里,只是对连续两笔memory wr-rd,而且只是分别将write和read的data在sequence种获取/打印出来,并没有进行check。(当然,如之前提到的,passive monitor也会对同一个地址的读写进行backdoor check的)

思路分析:

1. 需要对同一个地址(address)的wr_data和rd_data进行对比。因此是两个信息,address和data。获取方式如上所述,read从callback中获得,write在gen traffic的时候获得。

2. 因为sequence在gen trafficd的时候,是一次性gen出来的,从时间戳来看是同一时间的,因此想进行一笔一笔check不现实。因此,想到的方法就是先将所有gen出来的write traffic存到一个结构体(包括地址和wr_data)类型的数组中。对于read traffic,通过fork_join方式,在gen traffic的同时,按照上面的方法,去TL_TX_completion_queue_exitCbF里去获得地址和rd_data,同样存在一个结构体类型的数组中。在最后进行两个数组的地址和数据比对。

具体实现:

1. 定义一个结构体类型变量,并声明write和read的数组变量。

2. 定义相关要用到的变量:

其中:tlp_cpl之所以声明成为denaliPcieTlpMemPacket类型,是为了下面调用callback的时候$cast成功,因为只有这个类型的Tlp有地址。

3. 在sequence body()中new出两个动态数组,分配空间

4.发送wr/rd traffic,同时获得write traffic的地址和data,存入数组中。

5.  获取read traffic的address和data,并存入read pkt 数组。

最后一步是进行check。调用virtual task mem_datachk();

6. virtual task mem_datachk();定义在base sequence里。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值