PCIe学习(三)——PCIe DMA关键模块分析之二

简介
这是学习PCIe DMA传输的第二篇博客,在前一篇中叙述了PCIe DMA传输的部分基础知识,并且较为详细的分析了接收引擎的各个状态,这里接着分析第二个关键模块:发送引擎(BMD_64_TX_ENGINE.v)。

软件:VIVADO2017.4

第一步:模块功能分析

在分析发送引擎的具体操作之前,需要多这个模块实现的功能进行简单的分析。如下是发送引擎中的标头类型

由图可知,这个模块包含5种类型的标头,这里先简单的说明这几种标头的应用场景,BMD_64_CPLD_FMT_TYPE 标志着发送一个带数据的完成包,这个使用在PC端向FPGA发送一个存储器读请求后,FPGA通过这个报文将存储器信息返回到PC端,这是PIO模式;

BMD_64_MWR_FMT_TYPE和BMD_64_MWR64_FMT_TYPE标志着FPGA发送存储器写请求TLPs,这个使用在启动DMA写时,发送引擎组建存储器写请求包将数据发送到PC上;

BMD_64_MRD_FMT_TYPE和BMD_64_MRD64_FMT_TYPE标志着FPGA发送存储读请求TLPs,这个使用在PC配置启动DMA读时,发送引擎组建存储器读请求包,PC发送带数据的完成包到FPGA上,被接收引擎接收(上一篇博客中分析的带数据的完成包)。

以上就是几种标头的应用场景,了解清楚这些对分析发送引擎的结构很有帮助。接下来就开始分析发送引擎。

第二步:具体代码分析

观察状态机跳转

首先进入复位状态BMD_64_TX_RST_STATE,这个状态中有多个判断条件,包含发送完成包、DMA读操作和DMA写操作,接下来就逐个分析。

1、假设首先发送完成包。设置compl_done_o 为0,表示完成包未发送完成,这个信号会进入接收引擎来判断PC发送的存储器读请求是否完成。然后是条件判断,req_compl_q 是从接收引擎引入的信号,其目的是让发送引擎发送完成包;compl_done_o 是上文说的完成包是否发送完成标志信号;trn_tdst_rdy_n 是从机是否准备好接收数据标志信号,此时是FPGA发送数据给PC,所以PC是从机,这个信号表示PC端是否准备好接收数据;trn_tdst_dsc_n 这个信号在FPGA上被置1了。

设置帧开始信号(trn_tsof_n)有效、帧结束信号(trn_teof_n)无效、主机准备好发送数据(trn_tsrc_rdy_n)之后,就开始组装完成包头;组装的信息来自接收引擎和PCIe IP核,这就完成了发送完成包标头的前2DW。跳转到下一状态。

由于完成包是3DW标头,所以在这个状态中发送1DW标头+1DW数据。

首先判断从机是否准备好接收数据,准备好后设置帧起始无效,由于这是PIO模式,因此只有两帧,所以这是最后一帧,设置帧结束有效,接着设置主机准备好发送数据,然后发送第二帧(1DW标头+1DW数据),然后设置trn_trem_n 有效,表明这一帧数据都有效,然后compl_done_o 表示完成包发送完成,状态跳转到BMD_64_TX_CPLD_WIT 。

这个状态中设置关键的4个信号无效,然后跳转到复位状态,准备下一次传输。

2、假设进入DMA写存储器操作,

首先判断是否启动DMA写操作、DMA写操作完成等信号,其中serv_mwr 信号是用轮询操作控制DMA写操作的进行。接着和上面完成报文传输的格式差不多,trn_trem_n为0表示这一帧的两个DW都有效,cur_mwr_dw_count表示这一个TLP中数据的数量(单位DW),拼接发送第一帧数据,即2DW标头。接着就进入轮询操作。

轮询操作的目的是在发送一段时间的存储器写TLP之后,停止一次,然后判断此时是否有DMA读存储器开始信号,如果有的话就去执行DMA读操作,否则就是停止一次传输,下一个周期开始又继续DMA写操作。其中tmwr_wrr_cnt 信号统计发送TLP的数量,而mwr_wrr_cnt_i 信号则是设定轮询操作的TLP的量,这个值是在寄存器中配置的,当这两个值相等时就发生一次轮询操作。

通过mwr_64b_en_i 信号判断发送的存储器写请求的标头是3DW还是4DW,这和完成包不一样,因为完成包只有3DW标头,而存储器写或者读的TLP有3DW和4DW两种。

先分析3DW标头,此时跳转到BMD_64_TX_MWR_QW1状态

这个状态是发送第二帧数据,包含1DW标头(地址)+1DW数据,同样设置主机有效信号,然后通过cur_wr_count判断这是不是第一个TLP,因为第几个TLP决定着需要存入存储器的地址,mwr_addr是PC端申请的连续内存的首个地址,所以cur_wr_count为0,则要存入的地址为连续内存的首地址,之后就按照每个TLP中的数据量改变下一个TLP数据的存储地址。

cur_mwr_dw_count信号初值是一个TLP中的数据量(DW),如果当前cur_mwr_dw_count为1,则表示这是最后一个数据了,那么这时通过cur_wr_count分析这是否是最后一个包,如果是最后一个包那么说明这个TLP只有两帧(3DW标头+1DW数据),此次DMA传输完全结束,mwr_done_o置1;若不是最后一个数据,说明这个TLP不止两帧数据,则跳转BMD_64_TX_MWR_QWN 状态。

一个TLP传输到最后有可能还剩下1个或者2个DW数据,所以程序中就设计两种情况,如果只有1个DW,那么还需要组装1DW无用数据,同时使用trn_trem_n 信号来表明最后一个DW无效;如果刚好还剩两个DW数据,则刚好一次传输完,此时设置trn_trem_n 为0来表示这一帧中两个DW数据都是有效的。如果还剩的数据大于2DW,则就直接每次传输2DW数据,直到出现只剩下1个或者2个DW数据。

至此,DMA写操作的流程已经分析完成了,至于DMA读操作,以及3DW或4DW标头的分析都与分析类似,就不再分析了。

此外,BMD_EP_MEM.v 以及BMD_EP_MEM_ACCESS.v两个模块可以参照PIO中的分析,BMD_EP_MEM.v中的寄存器可以参照官方资料xapp1052,在这里就不过多叙述了。

结束
以上就是PCIe DMA的全部分析,后期会上传一些参考资料及有详细注释的.v文件,有需要的同学可以下载( https://download.csdn.net/download/cllovexyh/10335472 )。

本文转载自:CLGo的博客
*本文由作者授权转发,如需转载请联系作者本人

推荐阅读