一个req-ack接口引发的血案

本文转载自: FPGA的现今未微信公众号

最近定位了一个bug,代码是以前的同事留下的,没有经过太多充分的测试,且没有仿真平台,定位的过程是相当的痛苦,前后花了差不多一个星期。但是解决这个bug后,回头看,其实也是一个很简单的问题,就是请求应答(req_ack)接口处理不正确造成的……

问题现象
项目在上板测试过程中必现报文被丢弃的现象,方案不是很复杂。FPGA从CPU获取报文索引,然后根据索引读取CPU内存的报文(为了描述简单,这里省去项目相关信息)。

定位过程
1、该模块以前没有问题,后继模块工作频率降低后,给该模块反压了,才会出现该问题,首先是各种统计,上板测试没有发现问题,说明逻辑内部处理报文的时候没有丢包;

2、这里省略1万字各种怀疑各种测试,多方位证实了逻辑内部处理报文的时候确实是没有丢包的;

3、怀疑是不是CPU丢了索引,或者FPGA丢了索引?但是都不太好证实,因为丢弃报文的时候FPGA本身不感知,也不知道软件下发了多少索引。

4、在和同事一起讨论怀疑点,检视代码的时候,看到CPU告知FPGA描述符的时候,通过写寄存器的方式来告知,FPGA处理采用的是req_ack接口。如下图所示:其实这也不是一个标准的req_ack接口,因为请求方只给一拍的wen信号,req和ack的处理都是应答方内部的一种处理方式。

所以有一个大胆猜想,会不会是上一次req还没有处理完,CPU又来了下一个req导致有索引丢弃,从而导致了报文丢弃了?这个现象很好监测,当wen和req同时为1时,即为错误,监测代码如下所示:

always@(posedge clk_sys or posedge rst)
begin
if(rst == 1'b1) begin
error <= 1'b0;
end
else if((wen == 1'b1) && (req == 1'b1)) begin
error <= 1'b1;
end
end

增加error信号后,再次测试的过程中,果然error信号拉高了。

解决方案
首先CPU在写寄存器的过程中,并不知道FPGA是否正确处理上一个索引,其次FPGA处理一个索引和报文的时间是未知的,和后继模块的性能有关。所以解决这个问题的方案就是先缓存CPU写入的索引,然后再读出来慢慢处理。如下图所示:

CPU写入索引后,先不处理,全部缓存到一个fifo中,然后再从fifo中读出每一个索引依次处理。修改后的方案再次做稳定性测试,上述问题不再出现。

这里会有一个问题,该fifo不会溢出吗?在这个项目中,是不会的,因为CPU连续写入索引的最大个数是32个,所以只要fifo的深度大于32即可。那如果CPU连续写入索引的个数没有限制呢?上述方案也就无效了,必须和CPU之间建立一个发压的机制,保证CPU写入的索引不会丢失。

总结
本案例中的问题,是使用req_ack接口时,常见的一个问题,请求方和应答方要保持好握手,在上一个任务处理结束前,不可以发起下一个任务。

另外这种接口在高性能场景下,是有一定的性能损耗,尽可能采用流式接口来处理。关于接口的处理可参考:FPGA内部接口设计

最新文章

最新文章