本原创教程由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(http://www.meyesemi.com)

一:PIO内存读写操作TLP解析

PCIE有三种空间——内存空间、IO空间、配置空间,其中内存空间是目前PCIE设备常用的空间,IO空间是为了兼容以前的PCI设备(PCIE设备几乎不用IO空间了),配置空间是PCIE设备的信息空间(ID、BAR、等等都写在里面,主机内核程序初始化会读PCIE的配置空间信息,从而给Endpoint分配PICE总线域空间等一系列操作)。

PIO并不是说读写IO空间,原理上还是读写内存空间,PIO读写类似读写寄存器一样,每次对内存特定地址写一个数据(数据大小一般为32bit)。使用官方驱动指令读写PIO的操作,实质和使用WinDriver操作Read/Write Memory无异,不过官方驱动把每次的数据长度限制在了1DW(32bit)内,大于1DW的数据,会分多次发送。

图片

写1DW数据。

图片

写2DW数据。

图片

写3DW数据。

图片

读1DW数据。

图片

读2DW数据。

图片

读3DW数据。

注意的是,根据PCIE协议的Mwr,一次Mwr/Mrd数据大小最大可以是4096Byte,上面大于4Byte分了多次Mwr发送是驱动程序的做法。看到时序图的信号都是满足要求的,但是具体信号的数据是怎样的呢?现在以读写12Byte Memory为例来分析这些数据。

Write/Read Memory 使用到了三种类型的报文—Mwr/Mrd/CplD。在使用PCIE IP时,底层的东西可以不需要太关心,但是解析接收到的TLP解析和发送合乎要求的TLP是重点。

对于Mwr/Cpld,他们携带的数据就是数据,没什么需要分析的,需要分析的是TLP中的Header,Mrd报文只有Header,分析Header才是重点。

注意的是,Mwr/Mrd是地址路由,而CplD是ID(Bus/Device/Function)路由,这是协议规定的,所谓路由简单理解就是RC根据地址/ID,能够在众多的PCIE传输路径中把数据送到目标设备,因为内核程序初始化给给每个BAR分配了PCIE总线域空间,每个BAR空间地址都是独立映射的,而ID根据(Bus/Device/Function)唯一确定。

对于Mwr/Mrd的Header格式如下图:

图片

对于CplD的Header格式如下图:

图片

Mwr:
Header:0x0000_0000_df20_2000_0000_000f_4000_0001
Data: 0x0000_0000_0000_0000_0000_0000_0102_0304
Header:0x0000_0000_df20_2004_0000_000f_4000_0001
Data:0x0000_0000_000_0000_0000_0000_0506_0708
Header:0x0000_0000_df20_2008_0000_000f_4000_0001
Data:0x0000_0000_0000_0000_0000_0000_090a_0b0c

对于Mwr的Header,对着协议格式分析,很容易知道第一个Header地址(32bit)是df20_2000,携带数据长度Length(以DW为单位)为1,报文类型[Fmt,Type]=0x40(表明为3DW Mwr),字节使能[last DW BE,first DW BE]=0x0f,其他信息对座入号就行了,特别注意的是TLP是大端格式,[Fmt,Type]=axis_master_tdata[31:24],实际代表的是0Byte的位置,其他DW数据亦如此。

Mrd:
Header:0x0000_0000_df20_2000_0000_000f_0000_0001
Header:0x0000_0000_df20_2004_0000_000f_0000_0001
Header:0x0000_0000_df20_2008_0000_000f_0000_0001

对于Mrd的Header,对着协议格式分析,很容易知道地址(32bit)是df20_2000,请求数据长度Length(以DW为单位)为1,报文类型[Fmt,Type]=0x00(表明为3DW Mrd),字节使能[last DW BE,first DW BE]=0x0f,其他信息对座入号就行了,深入了解可读PCIE协议规范。

CplD:
Header:0x0000_0000_0000_0000_0100_0004_4a00_0001
Data:0x0000_0000_0000_0000_0000_0000_0102_0304
Header:0x0000_0000_0000_0010_0100_0004_4a00_0001
Data:0x0000_0000_0000_0000_0000_0000_0506_0708
Header:0x0000_0000_0000_0020_0100_0004_4a00_0001
Data:0x0000_0000_0000_0000_0000_0000_090a_0b0c

对于Cpld的Header,采用的是ID路由,很容易知道Requester ID为0x0000,Completer ID为0x0100,回复数据长度Length(以DW为单位)为1,报文类型[Fmt,Type]=0x4a(表明为CplD),Byte Count为0x004,TAG为0x00,其他信息对座入号就行了。具体的含义可查询PCIE协议规范。

二:DMA读写操作TLP解析

DMA直接内存访问,内存访问的发起者是FPGA,所以主机要发数据给FPGA,首先是发送DMA读指令和数据在主机内存的首地址给FPGA,FPGA根据内存首地址和数据长度发起一个Mrd,主机再回复CplD,这样就把数据传送到FPGA,称为DMA读操作。与之相反的是,主机发送DMA写指令和数据要放主机内存首地址给FPGA,FPGA根据内存首地址和数据长度发起带数据Mwr,这样就数据传送到主机,称为DMA写操作。

图片

1024Byte DMA读,主机到FPGA。

图片

1024Byte DMA写,FPGA到主机。

图片

2048Byte DMA读,主机到FPGA。

图片

2048Byte DMA读,FPGA到主机。

通过上面的DMA读写时序图不难发现,实现DMA读,主机会首先发3次Mwr TLP给FPGA,FPGA解析MWr TLP后会发起Mrd TLP,主机再回复CplD TLP,这样就数据传输到FPGA了;实现DMA写,主机首先发3次Mwr TLP给FPGA,FPGA解析MWr TLP后会直接上发带数据的MWr TLP,这样就数据传到主机了。

主机的3次MWr TLP是什么呢?通过解读例程的DMA模块下的dma_controller模块,不难发现,BAR1+0x100偏移量的数据是指示FPGA发起带数据的Mwr/不带数据的Mrd(也包含数据长度等),BAR1+0x100偏移量的数据是搬运数据的主机物理内存首地址的低32位,BAR1+0x100偏移量的数据是搬运数据的主机物理内存首地址的高32位。
DMA是直接存储器访问,要直接从主机内存搬数据/写数据,首先要知道主机内存首地址。一定是3次Mwr TLP通信握手吗?肯定不是的,这是生成IP例程的做法,自行设计DMA控制器的话,可以使用更复杂/更有效的握手机制来触发DMA操作。

时序图中Header:

DMA——主机的Mwr (以1024Byte为例)

第一次:
Header:0x0000_0000_df20_4100_0000_000f_4000_0001
Data:0x0000_0000_0000_0000_0000_0000_ff00_0100

第二次:
Header:0x0000_0000_df20_4110_0000_000f_4000_0001
Data:0x0000_0000_0000_0000_0000_0000_00a0_2647

第三次:
Header:0x0000_0000_df20_4120_0000_000f_4000_0001
Data:0x0000_0000_0000_0000_0000_0000_0100_0000

这个Mwr是32bit Address访问,存储器访问都是通过地址路由,Header的意义和上面Mwr分析是一致的。

DMA——主机的CplD(以1024Byte为例)

第1个Header:0x0000_0000_0100_0000_0000_0200_4a00_0020

第2个Header:0x0000_0000_0100_0000_0000_0180_4a00_0020

第3个Header:0x0000_0000_0100_0000_0000_0100_4a00_0020

第4个Header:0x0000_0000_0100_0000_0000_0080_4a00_0020

第5个Header:0x0000_0000_0100_0100_0000_0200_4a00_0020

第6个Header:0x0000_0000_0100_0100_0000_0180_4a00_0020

第7个Header:0x0000_0000_0100_0100_0000_0100_4a00_0020

第8个Header:0x0000_0000_0100_0100_0000_0080_4a00_0020

完成报文使用ID路由(协议规定,简单就是对于每一个BAR,都有自己的ID(Bus/Device/Function),通过这个唯一的ID可以找到接收目标)。

CplD的Header只能是3DW组成,具体和上面CplD分析是一致的。需要注意的是协议规定CplD最大数据长度是1024DW(4096 Byte),但是我们IP配置页面默认设置Max Playload Size其实是128 Byte,所以大于128 Byte的数据需要分多次发送。需要注意的是前4 Header的TAG=0x00,后4 Header的TAG=0x01,为什么这样,因为FPGA发了两次Mrd,TAG就是记录发了Mrd,收到完成报文中TAG和Mrd一致,代表当前Mrd完成了。


可以知道TAG是8bit,一旦Mrd的TAG=0xff,但是0x00的CplD还没回复,Mrd便不可再发送了(对于同一个的BAR的Mrd)。

可以看到Byte Count是变化的,这个很好理解,表示当前传输距离Mrd请求的数据量还有多少(这里不是我们最终的1024 Byte,而是一个Mrd的Byte数)。第一个Header为0x200,表示距离Mrd请求数据量还有512 Byte,第二个Header为0x180,表示距离Mrd请求数据量还有384 Byte,以此类推。一次Max Playload Size是128 Byte,传输一次CplD,距离目标就减少128 Byte。到了第5个Header,为什么回到512 Byte了,因为第5个Header CplD是新的Mrd请求了,同样请求长度为512 Byte。

DMA——FPGA的Mrd(以1024Byte为例)

Header:0x20d5_0400_0000_0000_0000_0001_0100_1c80
Header:0x20d5_0480_0000_0000_0000_0001_0100_3c80

这个Mrd是64bit Address访问,存储器访问都是通过地址路由,Header的意义和上面Mrd分析是一致的。这个64bit的地址是FPGA要读主机的内存的地址,低32bit放在第4DW,高32bit放在了第3个DW,这个地址肯定不是固定的,即使同一台电脑,主机每次读写开辟内存空间放数据的位置也不一样。

这里Mrd为什么需要分两次发送呢,因为PCIE IP设置的Max_rd_req_size为512 Byte,所以大于512 Byte的数据,需要分多次Mrd,例如向主机内存请求2048 Byte的数据,需要4次Mrd,每一个Mrd记录一个Tag,这样就对应上了CplD的Tag。

DMA——FPGA的Mwr(以1024Byte为例)

Mwr已经展开多次了,就不重复了。

盘古50K开发板|紫光同创PGL50H开发平台

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐