赞
踩
起始编辑日期 2024.05.29 星期三 晴天 轻松的生菜
一.前言
其实对于PCIE的学习,我只是停留在知道如何简单地应用IP核,因此,我会从一个USER,也就是使用者的角度来写下面这些东西,而不是一个CREATOR创造者的角度,如果想当一个CREATOR,先从一个USER开始做起吧,哈哈哈。
二.关于PCIE与IP核
在我看来,PCIE和UART、SPI本质上没有什么区别,只是PCIE这个协议会更加复杂,而且PCIE接口的传输速度明显快于低速接口的传输速度,一个接口如果传输速度很快,我们很自然地就会想到一件事情,也就是我们该用怎样的时钟去采集传输过来的的数据,Xilinx在设计PCIE IP核的时候其实已经把这个问题给你解决了,是利用了Xilinx芯片上的一个接口,好像叫GTX,具体的不是很清楚,总之,我们是不需要去考虑最底层的接收和解析的问题的,IP核会帮我们接收数据并且帮我们解析成TLP,这样一说是不是感觉IP核可真是大好人呢,对吧。IP核给到我们USER的数据统一称为TLP,TLP的组成是HEADER+DATAPAYLOAD,而且是通过AXI 的一组接口来给到我们的。
三.TLP(HEADER+DATAPAYLOAD)
这里提到的TLP局限于这几种类型:MEMORY WRITE(写存储器)、MEMORY READ(读存储器)、COMPLETION WITH DATA(返回读取数据,针对于MEMORY READ)、COMPLETION WITHOUT DATA(返回命令)。前两者是由主设备下发给从设备的,后两个是由从设备返回给主设备的,当主设备发出MEMORY READ命令时,我们就需要返回
就像上面说的,虽然我们不需要进行最底层的接收和解析,但是接收并解析TLP,是需要我们USER去做的,举个很简单的例子,A发送一条命令给B,A先将信息加密,然后传给B,B的任务就是先解密这个信息,然后再执行解密以后的命令,其中USER with IP核 就是B,IP核负责接收并解析出TLP,我们USER负责接收和执行TLP,那么我们先来看看一个基本的TLP命令是怎么样的吧,看图一。(这里需要知道一个数据单位DW,DW是一个数据单位,也就是DOUBLE WRODS-双字,1DW=32bits)。
图一.3DW Memory Write TLP
这个图怎么看呢,首先每一行都是1DW的数据,一共有七行,也就是7DW,最后一行的TLP Digest是CRC校验码,暂时不用管,可以不选择,因为对于USER来说,这是一个可选项,那我就先不选。
接下来我们来看最右边的红色标识,H开头的表示是HEADER,D开头的表示是DATA PAYLOAD。前三行是TLP的HEARDER部分,紧接着的三行Data是DATA PAYLOAD,也就是数据部分。我们注意到这里的HEADER一共有3DW,实际上HEADER的长度也可以是4DW,一般来说4DW的HEADER就是在3DW的基础上把图中的Address从[31:2]拓展为[63:2]。HEADER的长度是由HEADER的类型决定,也就是H0最左边的那一个字节{R,Fmt,Type},这里,我举六种TLP类型。
{R,Fmt,Type}=8’b0_00_00000,这是3DW的Memory Read 命令;
{R,Fmt,Type}=8’b0_01_00000,这是4DW的Memory Read 命令;
{R,Fmt,Type}=8’b0_10_00000,这是3DW的Memory Write 命令;
{R,Fmt,Type}=8’b0_11_00000,这是4DW的Memory Write 命令;
{R,Fmt,Type}=8’b0_10_01010,这是3DW的Completion With Data 命令;
{R,Fmt,Type}=8’b0_00_01010,这是3DW的Completion Without Data 命令;
而且这六种类型也是我用到的所有类型,至于其他类型我这里就不提了,你们如果有需要的话可以去看相关的文档。我们来讲讲除了{R,Fmt,Type}以外HEADER的其他数据位,例如TC、TD、EP等等,基本都用不到,对于这些暂时用不到的信号,IP核传输过来以后,我们寄存一下就可以,后续如果需要PCIE主设备需要我们从设备反馈的话再用。接下来说说用到的几个重要的数据位:
Length[9:0]:对于WRITE命令来说,Length表示DATA PAYLOAD的长度(单位:DW),也就是图二中没有加深的Data部分,图二的Length为3;
Last DW BE、1st DW BE:1st DW BE是DATA PAYLOAD的第一个DW数据的字节使能,Last DW BE是DATA PAYLOAD的最后一个DW数据的字节使能;
Address[31:2]:读写的基准地址。
基本用到的就是这几个部分,其实不管是3DW的HEADER还是4DW的HEADER,IP核都会用两个时钟周期发送完,IP核给我们发这些数据的时候是从上往下发的,也就是从Byte0->Byte27,而且是两行两行发的,因为AXI接口是64位的,图一中TLP发送的前两个时钟周期如图二Clock0、Clock1。所以说我们对于HEADER的解析,也需要用两个时钟周期来解析,第一个时钟周期先通过{R,Fmt,Type}确定TLP的类型和DATA_PAYLOAD的长度,第二个时钟周期获取读写命令的基准地址Address[31:2]。
只要是IP核发送过来的TLP有DATA PAYLOAD的,那就说明一定是WRITE命令。
图二
四.IP核相关信号解析
4.1 m_axis_rx
我们可以看图三7 Series Integrated Block for PCI Express IP核的配置页面,其中右边的m_axis_rx的六根信号线,就是IP核解析上层(Root Complex 或者其他PCIE主设备)加密后的数据得到的TLP数据, 这几组信号也是对于我们USER来说需要处理的所有信号,注意是所有信号。
图三
4.1.1 m_axis_rx_tdata[63:0]
先来说说m_axis_rx_tdata[63:0](数据信号),这个位宽可以在AXI Interface Width那里设置,一般就是64bits/128bits,我之后说的一切代码以及仿真都是基于64bits,IP核输出的数据都是每一个时钟周期输出2DW(64bits)。
4.1.2 m_axis_rx_tvalid、m_axis_rx_tlast、m_axis_rx_tkeep
但是什么时候这个数据有效呢?什么时候这个数据结束呢?数据有效时,数据的哪几个字节有效呢?要知道这三个问题的答案,就需要借助另外三个信号。首先,对于问题一,数据什么时候有效,当m_axis_rx_tvalid=1时m_axis_rx_tdata有效;对于问题二,当m_axis_rx_tlast=1时,表示这是TLP的最后一笔数据;对于问题三,m_axis_rx_tkeep=8’bxxxx_xxxx,每一bit都对应于m_axis_rx_tdata的8bits,也就是说keep信号是data的字节使能信号。
4.1.3 m_axis_rx_tuser[21:0]
还有一个输出信号是m_axis_rx_tuser[21:0],我详细来说一说,可以看下表。它的一些bit位都是只针对于128bits的AXI接口的,所以这也是我为什么选择64bits的AXI接口,相对来说简单一些。
[21:17] | 5bits | 128 AXI Interface Only,End of a packet(eof) |
[16:15] | 2bits | 保留位 |
[14:10] | 5bits | 128 AXI Interface Only,Start of a packet(sof) |
[9:2] | 8bits | [7:2]对应于BAR5-BAR0,[8]表示Expansion ROM |
[1] | 1bit | 64 AXI Interface Only,=rx_err_forward,提前表示这是一笔错误的数据(err_poisoned) |
[0] | 1bit | =rx_ecrc_err,表示packet的CRC校验出错 |
表一.m_axis_rx_tuser[21:0]详解
4.1.4 m_axis_rx_tready
m_axis_rx的最后一个信号,同时也是一个输入信号,m_axis_rx_tready信号,是有我们USER来驱动的,ready信号也很好理解,当我们ready好了以后,IP核才会把前面提到的五个信号给到我们USER,所以,记得,在每次接收完一个TLP后一定要先把ready信号给拉低,不然的话,连续接收TLP,我们可能会处理不过来。
4.1.5 m_axis_rx时序图(非常重要!!!)
为了方便理解m_axis_rx的信号时序,这里给出一个HEADER长度为3DW的MEMORY WRITE,携带4DW的DATAPAYLOAD,如图四。从图中可以看出IP核是如何将TLP按照顺序分解成一份份64bits的数据的,这个是需要我们知道的,因为我们得用这些数据呀,就得知道IP核发送的第一笔数据是啥,第二笔数据是啥,…最后一笔数据是啥,每一笔数据我们都需要知道它对应在TLP中是什么位置。另外,需要注意的一点,当ready信号拉高时,IP核才会传输一笔有效数据,所以在图中的红圈部分可以看到第一笔数据是保持了两个周期。最后一笔数据就可以通过last信号知道。
图四 Memory Write TLP with 3DW Header and 4DW Data Payload
这个时序是非常非常重要的,因为知道了TLP的时序,我们就能接收和解析TLP了,而且同样地,如果主设备下发一个READ TLP,我们需要返还一个Completion TLP,也是通过AXI 接口来给给到IP核,也就是图三中最左边的那组信号线s_axis_tx,s_axis_tx的六根信号线其中除了s_axis_tx_tready以外,其他的五个信号都需要我们USER来驱动,就如同IP核驱动m_axis_rx的五个信号线一样,所以这里我就先不说了。
五.IP核的使用
那么怎么把上述说的这些落实到verilog文件上呢,怎么围绕IP核搭建我们的FPGA PCIE DEALER呢,最直接的方式就是在配置完IP核以后,右击Open IP Example Design,如图五,IP Example Design,顾名思义,就是Xilinx官方给的一个示例教我们如何使用这个IP核,而且这个示例是一个具体的工程,里面除了IP核以外所有的Verilog文件都是可读可写的。
图五
Example打开如图六,这个Example可以帮我们节省很多很多时间,我们只需要根据我们的工程或者项目需求来编辑图中的PIO.v(包括里面的小模块),这个PIO.v就对应于我们USER,你想实现什么,就去改PIO.v就可以。
图六.PCIE IP Example Design
这里我就把我们USER需要写的verilog文件的输入输出端口给出来,知道输入输出以后,就知道大方向了,不至于摸黑前行了。有啥不懂的欢迎留言,因为我写这些东西很随性,想到啥写啥,会有很多错误和漏洞,有啥不对或者不理解的地方尽管指出来,希望和大家一起交流进步。
图七
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。