FPGA实战操作(2) -- PCIe总线(例程设计分析)

1.框架总览

平台:vivado 2016.4

FPGA:A7

在实际应用中,我们几乎不可能自己去编写接口协议,所以在IP核的例程上进行修改来适用于项目是个不错的选择。

通过vivado 中有关PCIe的IP核,生成相应的例程,综合之后可以得到如下图的工程结构。


如果在自己的项目中直接使用IP核的话,生成的只有pcie_7x_0这个模块,在应用层面还需要编写相应的解析和组装模块。好在该例程已经帮我们把这部分模块编写好了。例程简单的工作流程图如下图所示。

关于PCIe入门的简单协议介绍,可以参考博文 FPGA实战操作(2) -- PCIe总线(协议简述)

2.应用层模块设计分析(pcie_app_7x)

例程在PCIe核的基础上,已经为用户设计好了应用层模块。用户在使用的过程中只需要在应用层上稍加修改(例程是个闭环系统,需要将收发模块的部分接口对接到自己项目中),就可以将整个例程移植到自己的项目中了。

下面主要分析应用层模块中的PIO_RX_ENGINE、PIO_TX_ENGINE这两个核心模块。

2.1 PIO_RX_ENGINE

PIO_RX_ENGINE接口层面主要实现三个功能:将PCIe IP核传递过来的TLP包解析,之后将结果一部分用于控制存储器读取数据,一部分解析结果(协议有效字段)发送给PIO_TX_ENGINE,在需要反馈报文时用。

有关数据的解析,主要由下图状态机控制完成。程序中支持64位宽和128位宽,通过C_DATA_WIDTH来判断执行不同部分。

状态机状态state首先进入PIO_RX_RST_STATE,在PIO_RX_RST_STATE中完成数据关键字段的解析,根据解析的结果来执行中间几个状态(红线),这几个执行状态主要根据命令来完成相应的操作,执行完毕后进入PIO_RX_WAIT_STATE。

下面对几个关键状态里的内容进行简单分析。

2.1.1 PIO_RX_RST_STATE

程序首先进入PIO_RX_RST_START 状态,这是一个复位状态。在复位状态中,首先判断sop 信号是否有效,sop 信号是TLP开始的信号,若这个信号无效,则程序会一直在复位状态中直到sop 信号有效;若sop 信号有效,则执行嵌套的一段case语句,case的条件是m_axis_rx_tdata[30:24],研究TLP协议包会发现,该字段对应的是Fmt+Type字段,代表TLP确定的事务类型,实际上就是命令操作,让你干什么。

事务类型的case中,只介绍PIO_RX_MEM_RD32_FMT_TYPE,实际即32位寻址的读事务。在PIO_RX_MEM_RD32_FMT_TYPE状态中,按照TLP协议包格式,将各字段数据锁存入相应的寄存器中,可以参见后面的注释。其它的事务类型的操作都大同小异,就是锁存所需字段,执行相应的操作。

case (m_axis_rx_tdata[30:24])   // TLP中 Fmt Type的判断
 // 00000001_10100000_00001001_00001111_01000000_00000000_00000000_00000001
 // 00000001_10100000_00001010_00001111_00000000_00000000_00000000_00000001
 // m_axis_rx_tdata[30:24] = 1000000 ,执行 PIO_RX_MEM_WR32_FMT_TYPE

    PIO_RX_MEM_RD32_FMT_TYPE : begin                    // 存储器读请求,3个DW,不带数据
        tlp_type     <= #TCQ m_axis_rx_tdata[31:24];    // 锁存TLP类型,即Fmt+Type
        req_len      <= #TCQ m_axis_rx_tdata[9:0];      // 锁存TLP数据包长度,单位是DW
        m_axis_rx_tready <= #TCQ 1'b0;                  // 未准备好
        if (m_axis_rx_tdata[9:0] == 10'b1) begin        // 若数据长度为1DW
            req_tc   <= #TCQ m_axis_rx_tdata[22:20];
            req_td   <= #TCQ m_axis_rx_tdata[15];
            req_ep   <= #TCQ m_axis_rx_tdata[14];
            req_attr <= #TCQ m_axis_rx_tdata[13:12];
            req_len  <= #TCQ m_axis_rx_tdata[9:0];
            req_rid  <= #TCQ m_axis_rx_tdata[63:48];  // Reverse ID
            req_tag  <= #TCQ m_axis_rx_tdata[47:40];  // Tag字段的长度决定发送端能够暂存多少
            req_be   <= #TCQ m_axis_rx_tdata[39:32];  // TLP使用 last DW BE和first DW BE这两个字段
            state    <= #TCQ PIO_RX_MEM_RD32_DW1DW2;  // 表示从存储器中读取DW1和DW2

         end // if (m_axis_rx_tdata[9:0] == 10'b1)
         else  begin
            state   <= #TCQ PIO_RX_RST_STATE;
         end // if !(m_axis_rx_tdata[9:0] == 10'b1)
     end // PIO_RX_MEM_RD32_FMT_TYPE

注意:在介绍协议的时候,都是基于DW(32位)介绍,但在通过AXI4总线进行数据交换时,采用的是64位宽或者128位宽,所以要注意一下,数据大小端拼接。

2.1.2 PIO_RX_MEM_RD32_DW1DW2

在执行完成PIO_RX_MEM_RD32_FMT_TYPE状态之后,主状态机跳转至PIO_RX_MEM_RD32_DW1DW2状态,表示要执行读操作的配置工作。

由PCIe通信机制可知,存储器读请求是需要反馈完成报文的,而且这个完成报文反馈包括两方面:第一,TLP协议有些固定字段,要反馈;第二,从存储器指定地址下的数据,要反馈。

req_addr 表示需要读取的存储器的地址,req_compl 表示需要发送完成报文,req_compl_wd 表示完成报文中包含数据,然后跳转到PIO_RX_WAIT_STATE 状态。

PIO_RX_WAIT_STATE 状态没什么好说的。

2.2 PIO_TX_ENGINE

PIO_TX_ENGINE结构与PIO_RX_ENGINE类似,也是由状态机完成,主要执行组装封包功能。

着重看一下PIO_TX_CPLD_QW1_FIRST和PIO_TX_CPLD_QW1两个状态。

2.2.1 PIO_TX_CPLD_QW1_FIRST

PIO_TX_CPLD_QW1_FIRST : begin   // 完成报文头标的第一个DW
    if (s_axis_tx_tready) begin
        s_axis_tx_tlast  <= #TCQ 1'b0;
        s_axis_tx_tdata  <= #TCQ {    // Bits
            completer_id,             // 16
            {3'b0},                   // 3  完成状态,000--成功完成
            {1'b0},                   // 1
            byte_count,               // 12
            {1'b0},                   // 1
            (req_compl_wd_q ?         // 看此包带不带数据
            PIO_CPLD_FMT_TYPE :
            PIO_CPL_FMT_TYPE),        // 7
            {1'b0},                   // 1
            req_tc,                   // 3
            {4'b0},                   // 4
            req_td,                   // 1
            req_ep,                   // 1
            req_attr,                 // 2
            {2'b0},                   // 2
            req_len                   // 10
         };
         s_axis_tx_tkeep   <= #TCQ 8'hFF;
         state             <= #TCQ PIO_TX_CPLD_QW1_TEMP;
      end
      else
         state             <= #TCQ PIO_TX_RST_STATE;
  end //PIO_TX_CPLD_QW1_FIRST

这个状态中传输第一帧(64bit)数据,由TLP协议可知,第一帧数据主要反馈的Head信息,即头标的前2DW数据,其中通过req_compl_wd_q 信号判定这个完成包是否带有数据,同时因为这一帧信号都是有效的信号,所以s_axis_tx_tkeep 为FF。

2.2.2 PIO_TX_CPLD_QW1

PIO_TX_CPLD_QW1 : begin
    if (s_axis_tx_tready) begin
        s_axis_tx_tlast  <= #TCQ 1'b1;
        s_axis_tx_tvalid <= #TCQ 1'b1;
        // Swap DWORDS for AXI
        s_axis_tx_tdata  <= #TCQ {        // Bits
            rd_data,    // 32
            req_rid,    // 16
            req_tag,    //  8
            {1'b0},     //  1
            lower_addr  //  7
        };
        // Here we select if the packet has data or
        // not.  The strobe signal will mask data
        // when it is not needed.  No reason to change
        // the data bus.
        if (req_compl_wd_q)
           s_axis_tx_tkeep <= #TCQ 8'hFF;
        else
           s_axis_tx_tkeep <= #TCQ 8'h0F;

        compl_done        <= #TCQ 1'b1;
        compl_busy_i      <= #TCQ 1'b0;
        state             <= #TCQ PIO_TX_RST_STATE;
     end // if (s_axis_tx_tready)
     else
        state             <= #TCQ PIO_TX_CPLD_QW1;
end // PIO_TX_CPLD_QW1

在这个状态中,首先通过s_axis_tx_tready 信号判断从设备是否准备好接受信号;由于完成包由3DW标头和1DW的数据构成,总共2帧,所以这一帧是最后一帧,因此此时设置s_axis_tx_tlast为1表明这是最后一帧;然后设置s_axis_tx_tvalid为1表明此时主设备准备好发送数据;接着就根据完成包格式拼接发送数据。拼接完成后通过req_compl_wd_q设置s_axis_tx_tkeep信号,由于一次传输64bit,所以第二帧刚好1DW标头+1DW数据,这一帧都有效,所以s_axis_tx_tkeep为FF,如果这个完成包不带数据,即req_compl_wd_q无效,则最后一帧数据中只有1DW标头,那么s_axis_tx_tkeep就为0F。
至此这个带数据的完成包就发送完成了,所以设置compl_done有效,这个信号返回到接收引擎中,使得接收引擎准备接收下一个TLP,设置compl_busy_i无效,说明又可以发送完成包了,同时状态机跳转至PIO_TX_RST_STATE状态。

参考文献

  1. PCIe学习(一):PCIe基础及生成PIO例程分析——judyzhong
  2. 《LogiCORE? IP Endpoint for PCI Express? v3.7》(UG185)

原文地址:https://www.cnblogs.com/rouwawa/p/10815178.html

时间: 2024-08-02 00:14:04

FPGA实战操作(2) -- PCIe总线(例程设计分析)的相关文章

linux PMBus总线驱动设计分析

PMBus协议规范介绍 PMBus是一套对电源进行配置.控制和监控的通讯协议标准.其最新版本为1.3,该规范还在不断演进中,比如新标准中新增的zone PMBus.AVSBus等特性.在其官网上有详细的规范文档,本节不尝试翻译规范文档,重点记录作者在了解PMBus过程中的疑问和解答. PMBus与I2C.SMBus的区别? PMBus在SMBus(System Management Bus)基础上增加了一套电源配置.控制和监控规范.SMBus最初是为电池智能管理而开发的一套标准,其基于I2C协议

PCIe闪存控制器技术解析

一.PCIe-SSD架构解析 PCIe作为CPU的局部总线,最大的特点在于数据传输吞吐量大和延迟低.对于NandFlash固态存储而言,传统磁盘存储领域存在的随机读写问题将不复存在,因此,整个存储系统的瓶颈从存储介质转移到了传输接口上来了.为存储而生的SATA/SAS接口在SSD上的表现不是那么理想了,非常影响IO的传输延迟.为此,显而易见,存储接口应该从传统的SATA/SAS往离CPU更近的系统总线PCIe或者DIMM方向发展. 大家其实很早就认识到了这一点,当年Fusion-io推出基于PC

PCIe to AXI Translation——PCIe 内存空间到AXI内存空间的转换

UltraScale系列芯片包含PCIe的Gen3 Integrated Block IP核在内的多种不同功能的IP核都会有一页设置为PCIe:BARs,设置IP核的Base address register 的相关参数,如图1所示: 图1 PCIe:BARs 配置图 一般来说在FPGA中使用PCIe核都是Endpoint mode,我们的PC主机端是Rootpoint mode,一般会有一个Root Complex的混合管理器,来管理接入PCIe总线的端点设备.对于PC机来说,当PC机识别该P

PCIe调试心得_DMA part2

作者:East  FPGA那点事儿 上一章讲述了PCIe总线DMA的原理和XAPP1052存在的问题. 本章以服务器常用的4通道1000M以太网卡为例讲述如何提高DMA的效率. 1.内存重分配Windows操作系统会划分一部分硬盘空间作为虚拟内存,将长时间不用得应用程序或内存交换到硬盘中,而释放出一部分内存空间供其他应用程序使用,提高计算机的性能. 或者操作系统会定进行内存碎片整理,将应用程序中零散的内存收集起来重新分配,减少内存碎片. 但是如果被交换或整理的是DMA使用的内存就麻烦了.操作系统

PCIe调试心得_DMA part3

作者: East  FPGA那点事儿 上一章讲述了PCIe总线如何提高DMA的效率. 本章以服务器常用的4通道1000M以太网卡为例讲述如何实现多个虚拟DMA通道. 1.多通道DMA发 4通道以太网卡的数据相互独立,需要4个虚拟DMA发通道实现4路数据独立传输.4个虚拟DMA发通道如下: 多通道DMA发比较简单,因为TLP包中已经包含了具体的物理地址,4个虚拟通道可以向4个不同的物理内存位置写数据.所以DMA发逻辑与单通道DMA发逻辑没有什么不同,关键点在增加的总线仲裁逻辑. 4个网口都有数据要

怎样訪问pcie整个4k的配置空间

眼下用于訪问PCIe配置空间寄存器的方法须要追溯到原始的PCI规范. 为了发起PCI总线配置周期,Intel实现的PCI规范使用IO空间的CF8h和CFCh来分别作为索引和数据寄存器,这样的方法能够訪问全部PCI设备的255 bytes配置寄存器.Intel Chipsets眼下仍然支持这样的訪问PCI配置空间的方法. PCIe规范在PCI规范的基础上,将配置空间扩展到4K bytes,至于为什么扩展到4K,详细能够參考PCIe规范,这些功能都须要配置空间.原来的CF8/CFC方法仍然能够訪问全

多功能PCIE交换机之九:单NT系统中需要注意的问题

多功能PCIE交换机之九:单NT系统中需要注意的问题 1.单NT与双NT系统差异 NTB通常用在双控或者多控的系统上,用来实现跨节点的数据传输.在由多个节点构成的系统上,通常每个节点上都有一个NTB芯片,以实现全系统地址空间划分和路由.顾名思义,单NT是指用一个PCIE非透明桥来实现节点间数据传输的方案,通常用在两个节点之间.和多NT的系统相比,这种方法实现相对比较简单,成本较低,开发周期较短,能够缩短整个系统的关键功能和性能的验证周期. 2.单NT系统的实现 单NT的实现需要结合整个系统的设计

VC709E 增强版 基于FMC接口的Xilinx Vertex-7 FPGA V7 XC7VX690T PCIeX8 接口卡

VC709E 增强版 基于FMC接口的Xilinx Vertex-7 FPGA V7 XC7VX690T PCIeX8 接口卡 一.板卡概述       本板卡基于Xilinx公司的FPGA XC7VX690T-FFG1761 芯片,支持PCIeX8.64bit DDR3容量2GByte,HPC的FMC连接器,板卡支持各种接口输入,软件支持windows. 二.功能和技术指标:     1.标准PCI-E接口,支持PCI-E 8x,支持PCI-E 3.0.    2.标准FMC-HPC接口,VA

PCIe 基础(一)操作配置空间

PCI配置空间 PCI有三种地址空间:I/O空间,内存地址空间,PCI配置空间.在启动时bootloader 或者内核会遍历PCI总线并分配资源,如中断和内存,设备驱动程序通过PCI配置空间 找到资源分配.大小为256字节. 配置空间图: (1) Device ID和Vendor ID寄存器 这两个寄存器的值由PCISIG分配,只读.其中Vendor ID代表PCI设备的生产厂商, 而Device ID代表这个厂商所生产的具体设备.如Intel公司的基于82571EB芯片的 系列网卡,其Vend