【高速接口-RapidIO】6、Xilinx RapidIO核仿真与包时序分析

原文:https://www.cnblogs.com/liujinggang/p/10123498.html

提示:本文的所有图片如果不清晰,请在浏览器的新建标签中打开或保存到本地打开

一、软件平台与硬件平台

  软件平台:

         操作系统:Windows 8.1 64-bit

         开发套件:Vivado2015.4.2

  硬件平台:

         评估板:ZYNQ-7 ZC706 Evaluation Board

二、介绍

  上篇文章的最后一小节已经对例子工程进行仿真并通过命令 log_wave –r /* 记录了所有信号的波形,这篇文章主要介绍RapidIO核的仿真以及包时序的分析。

       调试SRIO核时必须对包在不同接口的传输过程有一个清晰的了解,能够识别出不同接口上包的类型并正确的解析出包的内容。

       本文详细的介绍了SRIO包(控制符号与数据字符)在不同接口上的组成与传输过程,并深入到逻辑层、传输层以及物理层来观察RapidIO串行物理层包的传输细节。整个包与信号分析的过程完全基于RapidIO提供的例子工程,例子工程的产生与源代码的分析已经在上一篇文章《Xilinx RapidIO核例子工程源码分析》(链接:https://www.cnblogs.com/liujinggang/p/10091216.html)提到过,这里不再赘述。最后,本文会利用RapidIO核做一个回环测试(Loopback Test)的工程在ZC706上运行,由于RapidIO是一个付费的IP核,所以生成bit文件需要License,没有License的可以在官网(https://www.xilinx.com/products/intellectual-property/ef-di-srio-gen2.html#overview)申请一个30天的评估版License试用,评估版的License生成的bit文件运行一段时间以后会自动失效,要想永久使用必须购买官方的License。

三、例子工程结构

       下图整个例子工程的结构层次

 

       它由一个仿真顶层的testbench和两个SRIO核顶层组成。其中顶层的testbench文件srio_sim.v连接了两个srio例子设计顶层,其中一个例子设计顶层叫做srio_example_top_primary,它代表请求方的RapidIO设备;另一个例子设计顶层叫做srio_example_top_mirror,它代表响应方的RapidIO设备。

       SRIO例子工程顶层文件srio_example_top.v例化了SRIO核的所有组件以及需要在硬件上执行的必要模块。这些模块包括:

       1、时钟域复位模块(srio_clk.v和srio_rst.v)

       2、配置结构(cfg_fabric.v)

       3、请求事务与响应事务生成模块(srio_resquest_gen.v和srio_response_gen.v)

       4、维护事务生成模块(srio_quick_start.v)

       顶层模块srio_example_top中例化了srio_quick_start模块,它与SRIO的维护端口相连,用来生成维护事务(Maintenance Transactions)。这个模块用来向本地(Local)或远程(Remote)的配置寄存器空间发送一组固定的指令集,用户可以编辑maintenance_list.v来添加、修改或移除维护事务。

srio_request_gen在顶层模块srio_example_top进行例化,它用来产生I/O事务或消息(MESSAGE)事务,但仅仅SRIO核支持的事务类型能被产生,这个模块也存储了期望的响应事务并与实际接收到的响应事务进行对比用来确定整个事务交互过程的正确性。

srio_response_gen也在顶层模块srio_example_top进行例化,它用来产生请求事务对应的响应事务。

  整个例子工程结构层次的软件框架如下图所示,其中左边的srio_example_top模块表示请求方的RapidIO设备,而右边的DUT Mirror表示响应方的RapidIO设备,它们的内部结构完全相同,区别仅仅在于一个作为请求方而另一个为响应方。

 

       SRIO核的原理框图以及接口如下图所示

 

       为了方便说明,上图每一个接口都用相应的数字标注出来。它们分别为

       Initiator/Target IO Port(接口1)

       例子工程中SRIO核全部为默认参数,所以端口类型默认被配置为Initiator/Target,在Initiator/Target接口类型中请求事务与响应事务在不同的AXI4-Stream通道上进行传输。SRIO核的端口类型也能被配置为Condensed I/O类型,在Condensed I/O接口类型中请求事务与响应事务在同一AXI4-Stream通道上进行传输,所以Condensed I/O相比于Initiator/Target类型来说接口更加精简。本文仍然采用默认的Initiator/Target接口类型来分析每个包的传输过程。

       接口1的数据传输协议为AXI4-Stream协议,它的接口定义如下:

       s_axis_ireq_* 表示Initiator请求事务的传输通道(i = initiator ,req = request)

  m_axis_iresp_* 表示Initiator响应事务的传输通道(i = initiator ,resp = response)

  m_axis_treq_* 表示Target请求事务的传输通道(t = target ,req = request)

  s_axis_iresp_* 表示Target响应事务的传输通道(t = target , resp = response)

       Maintenance Port(接口2)

       接口2的数据传输协议为AXI4-Lite协议,用来传输维护事务。它的接口定义如下:

       s_axi_maintr_* 表示维护事务的传输端口(maintr = maintenance)

       LOG Configuration Fabric(接口3)

       接口3的数据传输协议为AXI4-Lite协议,它是逻辑层的配置结构端口,包括本地(Local)配置端口和远程(Remote)配置端口。它的接口定义如下:

       s_axi_cfgl_* 表示本地配置端口(cfg = configuration,l = local)

  m_axi_cfgr_* 表示远程配置端口(cfg = configuration,r = remote)

  LOG Transport Interface(接口4)

       接口4的数据传输协议为AXI4-Stream协议,它是逻辑层与Buffer的数据传输接口,包括发送和接收两个通道。它的接口定义如下:

       m_axis_buft_* 表示发送端口(buf = buffer,t = transmit)

  s_axis_ bufr_* 表示接收端口(buf = buffer,r = receive)

  BUF Link Interface(接口5)

       接口5的数据传输协议为AXI4-Stream协议,它是Buffer层与物理层的数据传输接口,包括发送和接收两个通道。它的接口定义如下:

       m_axis_phyt_* 表示发送端口(phy= physical,t = transmit)

  s_axis_ phyr_* 表示接收端口(phy = physical,r = receive)

  BUF Configuration Fabric(接口6)

       接口6的数据传输协议为AXI4-Lite协议,它是Buffer层的配置端口。它的接口定义如下:

       s_axi_bcfg_* 表示Buffer层配置端口(b = buffer,cfg = configuration)

  PHY Serial Interface(接口7)

       接口7为物理层串行链路接口,它是物理层数据与串行收发器(Serial Transceivers)数据交换通道,它的接口定义如下所示:

信号

方向

功能

gttx_data[32*LW-1 : 0]

Output

发送给串行收发器(Serial Transceivers)的数据

gttx_charisk[4*LW-1 : 0]

Output

gttx_data信号中有效字节指示信号。当这个信号某一位为0时,gttx_data中对应的字节为包的有效字节。

gttx_inhibit[LW-1:0]

Output

串行收发器的通道使能位。如果最低位(bit-0)为1,表示发送通道0(Lane0)不使能,其余依次类推

gtrx_data[32*LW-1:0]

Input

从串行收发器(Serial Transceivers)接收的数据

gtrx_charisk[4*LW-1:0]

Input

gtrx_data信号中有效字节指示信号。当这个信号某一位为0时,gttx_data中对应的字节为包的有效字节。

gtrx_chariscomma[4*LW-1:0]

Input

gtrx_data信号中comma指示信号。如果最低位(bit-0)为1,表示gtrx_data[7:0]是包含comma的字符,其余依次类推

gtrx_disperr[4*LW-1:0]

Input

gtrx_data信号中不一致错误(Disparity Error)指示信号。如果最低位(bit-0)为1,表示gtrx_data[7:0]中存在不一致错误,其余依次类推

gtrx_notintable[4*LW-1:0]

Input

gtrx_data信号中not-in-table错误指示信号。Table指的是8b/10b编码解码表。如果最低位(bit-0)为1,表示gtrx_data[7:0]中8b/10b解码错误,其余依次类推

gtrx_chanbondseq[LW-1:0]

Input

串行收发器每个链路的通道绑定序列(Channel Bonding Sequence)指示信号,如果最低位(bit-0)为1,表示链路0(Lane0)收到了一串通道绑定序列,其余依次类推

gtrx_chanisaligned[LW-1:0]

Input

串行收发器每个链路的通道对齐(Channel Alignment)指示信号,如果最低位(bit-0)为1,表示链路0(Lane0)已经实现了通道对齐,其余依次类推

gtrx_chanbonden

Output

串行收发器通道绑定使能信号

gtrx_reset_req

Input

串行请求复位信号。例如,由于串行收发器接收通路弹性FIFO的上溢(overflow)或下溢(underflow),

gtrx_reset

Output

串行收发器的复位信号

gtrx_reset_done[LW-1:0]

Input

串行收发器每个链路的复位完成指示信号,如果最低位(bit-0)为1,表示链路0(Lane0)已经复位完成,其余依次类推

  PHY Configuration Fabric(接口8)

       接口8的数据传输协议为AXI4-Lite协议,它是物理层(Physical)的配置端口。它的接口定义如下:

       s_axi_cfgp_* 表示物理层配置端口(cfg = configuration,p = physical)

  Transceiver Interface(接口9)

       接口9为串行收发器高速数据传输接口,每条串行数据传输线均为一对差分信号。它的接口定义如下:

       srio_rxpN ,srio_rxnN:N为通道号,接收链路差分对,N的值为1、2或4。

       srio_txpN ,srio_txnN:N为通道号,发送链路差分对,N的值为1、2或4。

四、SRIO核包时序分析

       上篇文章《Xilinx RapidIO核例子工程源码分析》(链接:https://www.cnblogs.com/liujinggang/p/10091216.html)的最后一小节已经详细介绍了仿真的全部流程以及利用log_wave –r /*命令记录所有信号波形的方法,这里不再赘述。这一节默认大家已经仿真完毕(仿真结束大约需要20min左右时间,仿真完毕记得保存波形),并得到了仿真的波形,下面就对其中重要的波形进行分析。

       在分析之前,在重新回顾一下RapidIO串行物理层的包与控制符号的格式

       串行物理层的包:

 

  控制符号:

4.1 链路初始化与控制符号

  调试SRIO的第一步是去检测SRIO顶层模块(srio_example_top_primary)中的各个关键的控制信号是否正确切换。这些信号包括:复位信号、时钟锁定信号(clk_lock)、端口初始化信号(port_initialized)、链路初始化信号(link_initialized),端口错误信号(port_error),mode_1x信号(在2x和4x模式下,这个信号为高表示SRIO核已经被训练为1x模式,在1x模式下,这个信号一直为高,当port_initialized为高时,这个信号才有效)与端口解码错误信号(port_decode_error)等(除了这几个信号以外,其他信号也可以观察一下)。

  Step1、把srio_example_top_primary中的所有信号全部选中,然后直接拖到右边的波形窗口

 

  Step2、找到上面提到的几个关键控制信号,观察它们的波形

 

       由上图可以看出,控制信号的波形均切换正确,其中最关键的两个信号是port_initialized信号与link_initialized信号,当它们为高时,分别表示端口和链路被成功初始化。

       下图是时钟信号和复位信号的时序细节,显然,时钟信号与复位信号的时序均正确。

 

  Step3、pg007_srio_gen2.pdf第119页提到,当7个连续的error free控制符号被接收,并且15个连续的符号被发送的时候,link_initialized信号才被拉高,所以接下来看看link_initialized信号拉高之前物理层是否接收了7个控制符号并发送了15个控制符号。

首先选中最左边的srio_gen2_0_block_inst,然后把中间列出的以gt开头的接口7的所有信号拖到最右边的波形窗口中,如下图所示

 

       在link_initialized拉高之前,观察gttx_data,gttx_charisk与gtrx_data,gtrx_charisk总线上的数据,建议把gttx_charisk与gtrx_charisk用二进制显示,当gttx_charisk与gtrx_charisk对应的位为0时,表明gttx_data与gtrx_data上的数据为有效数据(控制符号与包属于有效数据)。当gttx_charisk与gtrx_charisk对应的位为1时,gttx_data与gtrx_data上的数据为空闲序列。如下图所示,当link_initialized拉高之前gttx_data上发送了15个连续的控制符号,gtrx_data上接收了7个连续的控制符号。

 

       下面把控制符号波形放大观察控制符号各个字段的细节,发送与接收总线上的控制符号分别如下图所示(gttx_charisk与gtrx_charisk对应的位为0时, gttx_data与gtrx_data上的数据为控制符号)

 

 

       上图表明在link_initialized拉高之前,发送与接收的控制符号为80f713,控制符号80f713前面的1c是/K28.0/,表示控制符号的起始位置。由于SRIO核默认使用的是短控制符号,所以这里控制符号为24-bit。

  把80f713转化为二进制:80f713 = 1000_0000_1111_0111_0001_0011,各个字段的对应关系如下图所示

  当gttx_charisk与gtrx_charisk对应的位为1时,gttx_data与gtrx_data上的数据为/K/,/R/,/A/组成的空闲随机序列(前面几篇文章解释过这个知识点),它们分别为特殊字符/K28.5/,/K29.7/,/K27.7/,转化为16进制为bc,fd,fb,下图是它们的波形

 

  整个初始化的过程着重需要关注的两个信号就是port_initialized和link_initialized,如果初始化失败(port_initialized和link_initialized没有被拉高),那么首先必须检查gttx_data与gtrx_data上是否收到了空闲序列/K28.5/,/K29.7/,/K27.7/,同时需要检查是否存在编解码错误,编解码错误的判断标志是gtrx_notintable信号,当它为1时表明存在编解码错误。

4.2 SWRITE事务

  上篇文章已经分析过,例子工程会把instruction_list.vh中定义的事务按顺序依次发出去。其中最先发送的是37个SWRITE事务,然后是19个NWRITE_R事务、 19个NWRITE事务、26个NREAD事务,2个DOORBELL事务,最后是17个MESSAGE事务。其中第一个发送的事务是instruction_list.vh中第50行定义的SWRITE事务。如下图所示

 

  下面以上图第50行的SWRITE事务为例来说明整个SWRITE事务的传输过程。这个事务表示的是利用SWRITE事务往地址36’hCD0000600发送16个字节的数据。

       Step1、选中srio_example_top_primary,把中间列出的所有信号全部拖到波形窗口中(拖到波形窗口前可以把之前波形窗口中的信号全部删掉)

 

       Step2、找到请求事务的传输通道ireq,并抓出事务的波形如下图所示

 

  由于仅当tvalid和tready同时为高时,tdata上的数据才为有效数据,所以这个SWRITE一共消耗了三个有效时钟周期,其中第一个时钟周期发送的是HELLO包头,后面两个时钟周期分别发送8个字节的数据(第一个时钟发送的数据是0000000000000000,第二个时钟发送的数据是0101010101010101),一共16个字节的数据,和instruction_list.vh中第50行定义完全一致,整个时序也与HELLO格式的时序完全吻合。

       Step3、对照HELLO格式解析包头。包头为006020fcd0000600,转化为二进制后与HELLO格式各个字段对应关系如下所示:

 

  由上图可知FTYPE字段的值为6,表明确实是一个SWRITE事务

       Step4、SWRITE事务通道ireq通道(接口1)传输给SRIO核以后进入SRIO的逻辑层,逻辑层会给包添加传输层的信息发送给Buffer(接口3),然后Buffer会把数据发送给物理层(接口5)。

       选中srio_gen2_0_block_inst,把中间的buft_*通道、phyt_*通道与gttx_*通道的信号拖到右边的波形窗口中,如下图所示

 

       整个从逻辑层到传输层到物理层到吉比特收发器(Gigabit Transceiver)的波形如下图所示,波形的细节这里不再展开,大家可以自己抓出来观察。

 

       Step5、ireq通道的SWRITE请求事务经过逻辑层,传输层和物理层到达吉比特收发器(Gigabit Transceiver),吉比特收发器的数据通道gttx_data[31:0](接口7)波形如下图所示

 

  由上图可知,整个串行物理层的包为:7c96f004_b04600ad_d0000600_00000000_00000000_01010101_01010101_e8d30000_7c96f203。(00000000和01010101的宽度为两个有效时钟)这个包的含义如下:

       7c96f004中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),96f004转化为二进制为:

  96f004 = 1001_0110_1111_0000_0000_0100

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  b04600ad_d0000600_00000000_00000000_01010101_01010101_e8d30000是SWRITE事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

  上图中data字段是传输的00000000_00000000_01010101_01010101这16个字节数据的二进制码,因为它的二进制码太长了所以我直接用data替代。由于本次传输的字节小于80个字节,所以SWRITE事务的最后面的三个字段不存在,大家可以抓一下数据量为256个字节的SWRITE包,当数据量大于了80字节,后面的三个字段也会有数据。

       包最后面的7c96f203中7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),96f203转化为二进制为:

  96f203= 1001_0110_1111_0010_0000_0011

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

  至此,SWRITE事务全部分析完毕。

4.3 NWRITE_R事务

  本小节以instruction_list.vh中第72行定义的NWRITE_R事务为例来说明整个NWRITE_R事务的传输过程。如下图所示,这个事务表示的是利用NWRITE_R事务往地址36’ h004550002发送6(size+1)个字节的数据。

 

       Step1、为了方便快速的找到上图的NWRITE_R事务,建议选中srio_request_gen模块,并把request_address变量拖到波形窗口中,并把这个变量用Unsigned Decimal(无符号10进制)格式显示。看过上篇《Xilinx RapidIO核例子工程源码分析》文章的应该知道这个变量是instruction的索引值,当这个变量为37的时候就表示37(0~36)个SWRITE事务全部发送完毕,下个事务就是instruction_list.vh中第72行定义的NWRITE_R事务。

 

  Step2、锁定request_address为37的位置,找到请求事务的传输通道ireq,并观察事务的波形如下图所示

 

  由上图可知第一个有效时钟传输的HELLO格式包头数据为:2555205004550002。发送的数据是afafafafafafafaf。包头与HELLO包格式的对应关系如下图所示

 

  由上图可知FTYPE = 5,TTYPE = 5,这两个字段唯一的确定了这是一个NWRITE_R事务。

  Step3、ireq通道的NWRITE_R请求事务经过逻辑层,传输层和物理层到达吉比特收发器(Gigabit Transceiver),吉比特收发器的数据通道gttx_data[31:0](接口7)波形如下图所示

 

  由上图可知,整个串行物理层的包为:7c98f009_d84500ad_59250455_0000afaf_afafafaf_afafad15_7c17f21e。这个包的含义如下:

       7c98f009中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),98f009转化为二进制为:

  98f009= 1001_1000_1111_0000_0000_1001

  它是一个包起始控制符号,各个字段的对应关系如下图所示

  d84500ad_59250455_0000afaf_afafafaf_afafad15是NWRITE_R事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

  上图中data字段是传输的afafafaf_afafafaf这16个字节数据的二进制码,因为它的二进制码太长了所以我直接用data替代。由于本次传输的总字节数为8字节的整数倍,所以NWRITE_R事务的后面可选的logical 0 pad(opt)没有数据。

       细心的人在这里可能发现了一个奇怪的现象:在HELLO格式中,address字段为36’ h004550002,其中高两位为保留位,所以address一共只有34-bit有效位,size字段为5,表示往36’ h004550002地址中写6(size+1)个字节的数据。但是上面串行物理层的包中address字段的值为0000_0100_0101_0101_0000_0000_0000_0,发送的数据个数为8个字节(afafafaf_afafafaf)。出现这种现象的原因为:

       HELLO格式address字段指向的存储空间的最小单元是1个字节,而串行物理层中的address字段指向的存储空间最小单元实际上是8个字节,address后面的xambsb字段是串行物理层的最高两位地址扩展字段,所以串行物理层的包可访问的存储空间大小为2^34=16G,这也是HELLO格式中address字段位宽为34-bit的原因(关于这部分的内容我在《RapidIO协议概述》也提到过)。正因为HELLO格式address字段与串行物理层address字段所指向的存储空间最小单元不同,所以pg007_srio_gen2.pdf中第78页才给出了一个HELLO格式size,addr与有效字节的对应关系表,如下所示

 

  本例中size=5,addr[2:0] = 2,对应于上图中红框圈出来的情况。所以往36’ h004550002地址中写6(size+1)个字节的数据对串行物理层来说就是往36’ h004550000地址中写8个字节的数据,高6个字节(上图中灰色区域)为有效数据。

  包最后面的7c17f21e中7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),17f21e转化为二进制为:

  17f21e = 0001_0111_1111_0010_0001_1110

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

  Step4、例子工程中例化了srio_example_top_primary与srio_example_top_mirror两个实体,srio_example_top_primary实体的srio_txp0和srio_txn0连接到srio_example_top_mirror实体的srio_rxp0和srio_rxn0。因此,srio_example_top_mirror的gtrx_data上的数据应该和上一步分析的srio_example_top_primary实体的gttx_data完全相同。

  选中srio_example_top_mirror的srio_gen2_0_block_inst,把gtrx_data与gtrx_charisk两个信号拖到右边的窗口中,如下图所示

 

       观察srio_example_top_primary的gttx_data与srio_example_top_mirror的gtrx_data,如下图所示,可以看到两者完全相同,仅仅存在一个延时。

 

  Step5、srio_example_top_mirror模块的grrx_data接收到数据以后,将会把grrx_data的数据按照与发送过程完全相反的操作传到逻辑层,最终逻辑层的数据将会通过srio_example_top_mirror模块的treq接口输出。

  选中srio_example_top_mirror,把treq通道的所有信号拖到右边的波形窗口中

 

  下图是srio_example_top_mirror模块treq通道的波形

 

  可知treq通道的包头数据为2555205004550002,与srio_example_top_primary模块ireq通道发送的包头数据完全一样。这也证明整个链路工作正常。

4.4 NWRITE_R的响应事务

  由于NWRITE_R事务是一个有响应的写事务,所以当发起方(Initiator)往目标方(Target)发送一个NWRITE_R事务以后,发起方(Initiator)还要接收目标方(Target)的发回响应事务。响应包的数据会出现在srio_example_top_primary模块的tresp通道,下图是srio_example_top_primary模块的tresp通道的时序图

 

  由上图可知iresp_tdata的数据为:25d0400000000000。与HELLO包格式的对应关系如下图所示

 

  由上图可知FTYPE = 13,所以这是一个响应事务,prio字段变成了2,而NWRITE_R字段的prio字段为1,这是因为响应事务的prio为请求事务的prio+1,(这个知识点前两篇文章都提到过)

       事实上,响应事务的一整套传输流程为:目标方(Target)发回的响应事务被srio_example_top_primary模块的串行差分信号线接收到达Serial Transceivers,Serial Transceivers在把接收的数据通过gtrx_data通道(接口7)传到物理层,物理层把接收的包经过处理以后通过phyr_*通道(接口5)把数据发给Buffer层,Buffer层对数据进行二次处理以后把数据通过bufr_*通道(接口4)传给逻辑层,逻辑层再把数据传输给I/O端口(接口1),这样就得到了上图HELLO格式的响应包。大家可以把gtrx_data、phyr_*通道、bufr_*通道和I/O端口的波形全部抓出来观察一下,方法和上节介绍发送流程的抓取过程完全一样。这里我只抓一下gtrx_data通道的数据,并分析响应事务串行物理层包格式各个字段的含义。

  gtrx_data通道的数据如下图所示

 

  由上图可知,整个响应事务串行物理层的包为:7c83f00f_388dadad_00255540_7c83f208

       7c83f00f中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),83f00f转化为二进制为:

  83f00f = 1000_0011_1111_0000_0000_1111

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  388dadad_00255540是NWRITE_R响应事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

  由于NWRITE_R的响应事务不带数据,所以没有data字段。target TID字段的值为16进制的25,也就是10进制的37,与发送的NWRITE_R请求事务target TID值完全相同。FTPYE字段的值为13,说明这是一个响应事务,整个响应事务的包正是NWRITE_R事务的响应包。

       7c83f208中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),83f208转化为二进制为:

  83f208= 1000_0011_1111_0010_0000_1000

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

4.5 NWRITE事务

  本小节以instruction_list.vh中第94行定义的NWRITE事务为例来说明整个NWRITE事务的传输过程。如下图所示,这个事务表示的是利用NWRITE事务往地址36’ hDE0000600发送16(size+1)个字节的数据。

 

  Step1、为了方便快速的找到上图的NWRITE事务,建议选中srio_request_gen模块,并把request_address变量拖到波形窗口中,并把这个变量用Unsigned Decimal(无符号10进制)格式显示。看过上篇《Xilinx RapidIO核例子工程源码分析》文章的应该知道这个变量是instruction的索引值,当这个变量为56的时候就表示37(0~36)个SWRITE事务全部发送完毕,19个NWRITE_R事务也全部发送完毕,下个事务就是instruction_list.vh中第94行定义的NWRITE事务。锁定request_address为56的位置,找到请求事务的传输通道ireq,并观察事务的波形如下图所示

 

  由上图可知第一个有效时钟传输的HELLO格式包头数据为:385420fde0000600。后两个有效时钟发送的数据分别是c2c2c2c2c2c2c2c2和c3c3c3c3c3c3c3c3。包头与HELLO包格式的对应关系如下图所示

 

  由上图可知FTYPE = 5,TTYPE = 4,这两个字段唯一的确定了这是一个NWRITE_R事务。srcTID的值为16进制的38,也就是10进制的56,与request_address的值相等,因为代码里面就是直接把request_address的值赋给了srcTID。

  Step2、ireq通道的NWRITE请求事务经过逻辑层,传输层和物理层到达吉比特收发器(Gigabit Transceiver),吉比特收发器的数据通道gttx_data[31:0](接口7)波形如下图所示

 

  由上图可知,NWRITE串行物理层包的数据为:

  7c93f010_c84500ad_4b38e000_0605c2c2_c2c2c2c2_c2c2c3c3_c3c3c3c3_c3c362a2_7c13f20e。包的各个字段解释如下:

       7c93f010中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),93f010转化为二进制为:

  93f010= 1001_0011_1111_0000_0001_0000

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  c84500ad_4b38e000_0605c2c2_c2c2c2c2_c2c2c3c3_c3c3c3c3_c3c362a2是NWRITE事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

  细心的同学马上会发现wrsize字段的值居然为11(2进制1011,16进制b),address字段的值为e000_0600。而instruction_list.vh中第94行定义的size字段的值为15,address字段的值为36’hDE0000600。似乎逻辑层的包到达物理层以后size字段和address两个字段都出现了错误。出现这种现象的原因如下:

       前面几篇文章也多次提到过,address后面的两个字段wdptr和xamsbs两个字段是有作用的,xamsbs字段是地址字段的高两位扩展位。由于HELLO格式address字段的有效位数是34-bit,所以在当address字段的值为36’hDE0000600,有效的address字段的值为34’h 1E0000600,当我们把串行物理层xamsbs字段的01拼接在串行物理层address字段前面得到的地址就和先前定义的地址是一致的了。

       至于wrsize字段的值为11,这是因为后面的wdptr字段的值变成了1,RapidIO_Rev_2.2_Specification的第35页表4-4已经列出了所有wrsize与wdptr字段的组合,当wdptr=1,wrsize=11是,字节的总个数是16,这也和我们之前在instruction_list.vh中的定义是一致的。

 

       7c13f201中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),13f201转化为二进制为:

  13f201= 0001_0011_1111_0010_0000_0001

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

4.6 NREAD事务

  本小节以instruction_list.vh中第120行定义的NREAD事务为例来说明整个NREAD事务的传输过程。如下图所示,这个事务表示的是利用NREAD事务往地址36’ h0000023F0发送8(size+1)个字节的数据。

 

  Step1、为了方便快速的找到上图的NREAD事务,建议选中srio_request_gen模块,并把request_address变量拖到波形窗口中,并把这个变量用Unsigned Decimal(无符号10进制)格式显示。看过上篇《Xilinx RapidIO核例子工程源码分析》文章的应该知道这个变量是instruction的索引值,当这个变量为78(37+19+19+3=78)的时候就表示发送的是上图第120行的NREAD事务(之所以不选择第123行的读事务是因为它读的数据量太大了,截图的时候不方便)。锁定request_address为78的位置,找到请求事务的传输通道ireq,并观察事务的波形如下图所示

 

       NREAD请求事务不带任何数据,只包含一个HELLO格式的包头,包头的数据为:4e242070000023f0。各个字段的对应关系如下图所示

 

  FTYPE=2,TTYPE=4,这两个字段唯一的确定了这是一个NREAD事务包。其他字段也与之前在instruction_list.vh中第120行定义的完全相同。

       Step2、接下来再看看NREAD事务串行物理层的包格式,这个包在155610ns的位置,下图是NREAD事务串行物理层包格式的时序图

 

  由上图可知,整个串行物理层的包为:7c92f014_b84200ad_4b4e0000_23f09c5a_7c92f213。这个包的含义如下:

       7c92f014中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),92f014转化为二进制为:

  92f014= 1001_0010_1111_0000_0001_0100

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  b84200ad_4b4e0000_23f09c5a是NREAD事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

       FTYPE = 2,TTYPE = 4,这两个值确定了这个包是一个NREAD事务包。rdsize=11(二进制的1011),wdptr=0,通过查RapidIO_Rev_2.2_Specification第34页的表可知数据量为8个字节,与instruction_list.vh中第120行定义的完全相同。wdptr与rdsize的对应关系表如下所示

 

  7c92f213中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),92f213转化为二进制为:

  92f213= 1001_0010_1111_0010_0001_0011

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

4.7 NREAD响应事务

  由于NREAD事务是一个有响应的事务,且响应事务中携带读到的数据。所以当发起方(Initiator)往目标方(Target)发送一个NREAD事务以后,发起方(Initiator)还要接收目标方(Target)的发回响应事务。响应事务通过gtrx_data通道接收。响应事务串行物理层包时序如下图所示,这个响应包在157370ns的位置

 

  由上图可知,00000000这个数据传输了2个时钟周期,所以整个响应事务串行物理层的包为:7c8af01e_708dadad_804e0000_00000000_0000469c_7c8af219

       7c83f00f中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),83f00f转化为二进制为:

  83f00f = 1000_0011_1111_0000_0000_1111

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  708dadad_804e0000_00000000_0000469c是NREAD响应事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

       FTYPE=13表示这是一个响应事务,TTYPE=8表示这个响应事务携带数据,target TID的值为16进制的4e(10进制的78),与请求事务刚好对应上,data字段是8个字节的00,由于并没有存储器,所以读出来的数据全部是0。

       7c8af219中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),8af219转化为二进制为:

  8af219= 1000_1001_1111_0010_0001_1001

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

       响应事务串行物理层的包经过物理层、传输层和逻辑层到达iresp通道,iresp通道的时序如下图所示

 

  iresp通道一共有两个有效数据,分别为HELLO格式包头4ed8400000000000和0000000000000000。HELLO格式包头4ed8400000000000各个字段的对应关系如下图所示

 

       FTYPE = 13,TTYPE = 8表示这是一个携带数据的响应事务,响应事务的prio字段的值为请求事务prio字段的值加1。

4.8 MAINTENANCE事务

  顶层模块srio_example_top.v中例化的srio_quick_start模块与SRIO IP核的维护端口相连用来产生维护事务。维护事务在maintenance_list.vh头文件中定义,用户可以通过编辑maintenance_list.vh头文件来添加、修改或移除维护事务。下图是例子工程中定义的所有维护事务

 

       维护事务有本地(Local)和远程(Remote)两种类型,区分这两种维护事务是通过maintr_araddr信号的高八位的值来确定的。如下图所示

 

  由上图可知,maintr_araddr的[31:24]位用来区分本地维护事务和远程维护事务,

  当 maintr_araddr=01xxxxxx,表示的是远程(Remote)维护事务。

  当 maintr_araddr=00xxxxxx,表示的是本地(Local)维护事务。

  maintr_araddr的[23:0]位是读操作的偏移地址。

       下图是一个维护事务的时序图

 

  由上图可知,红色框出来的部分是一个读维护事务,由于maintr_araddr的高8位[31:24]为8’h00,所以这是一个本地(Local)读维护事务。maintr_araddr的[23:0]位为24’h000000,所以这个本地(Local)读维护事务访问的是逻辑层的能力寄存器(Capability Register Space)空间,且寄存器的偏移地址为24’h000000。

  SRIO核寄存器空间的分布如下图所示

 

       下图是维护端口(接口2)和逻辑层配置端口(接口3)的时序图

 

 

  当 maintr_araddr=01000000,表示的是逻辑层的远程(Remote)维护事务。逻辑层I/O端口发起的维护事务会通过逻辑层、传输层到物理层转化为串行物理层的包通过高速串行收发器(Serial Transceiver)发出去。下图是一个远程维护事务串行物理层包的时序,这个包在96680ns的位置

 

  由上图可知,维护事务串行物理层的包为:7c82f00b_104800ff_18010000_0060dead_beefdead_beefbe6e_7c82f20c

       7c82f00b中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),82f00b转化为二进制为:

  82f00b = 1000_0010_1111_0000_0000_1011

  它是一个包起始控制符号,各个字段的对应关系如下图所示

 

  104800ff_18010000_0060dead_beefdead_beefbe6e是维护事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示

 

  FTYPE = 8,TTYPE = 1,表明这是一个写请求的维护事务。上图中data字段表示的是dead_beefdead_beef这8个字节的数据。

       7c82f20c中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),82f20c转化为二进制为:

  82f20c = 1000_0010_1111_0010_0000_1100

  它是一个包结束控制符号,各个字段的对应关系如下图所示

 

4.9 DOORBELL事务与MESSAGE事务

       门铃(DOORBELL)事务与消息(MESSAGE)事务的分析方法与之前几种方法完全一样,大家可以自己按照上面的流程先找到HELLO格式的包,对照HELLO格式各个字段的定义进行分析,然后找到串行物理层的包对照串行物理层的包格式再次分析就能明白整个事务的交互过程了。其实对于用户来说,串行物理层是SRIO IP核帮我们设计好的,所以在实际项目中使用的时候只需要关注HELLO格式的包与时序就可以了。

五、(选读)SRIO核在ZC706上回环(Loopback)测试

       通过Vivado仿真以后大家应该对使用SRIO核有了一个基本了解。如果你手头有自己做的开发板并且有SRIO的License的话你可以利用SRIO在硬件上做一个回环测试。

       所谓SRIO的回环测试就是把SRIO的srio_txp0和srio_rxp0在硬件上连接起来,把srio_txn0和srio_rxn0在硬件上连接起来,让SRIO的包自发自收。如下图所示

 

       由于我手头有一块Xilinx的ZC706评估板,所以这个回环测试我会在ZC706上完成。

       ZC706上的FPGA型号为XC7Z045,它的上面BANK109、BANK110、BANK111和BANK112为MGT BANK,如下图所示

  其中BANK112与PCIe接口相连(后面有空会写PCIe接口),所以RapidIO不能使用这个BANK。BANK109与BANK110与FMC接口相连,无法使用同轴线或光纤环回,所以这两个BANK也不能使用。因此RapidIO只剩下BANK111可用,而且BANK111有一个通道已经通过C653和C652环回上了,这样就省去了自己用光纤或同轴线去环回。接下来最重要的就是给BANK111输入一个125MHz的参考时钟。

  这个125MHz的时钟可以从临近的BANK“借”一个,比如可以通过软件配置SI5324产生一个125MHz时钟,尽管SI5324输出的时钟并不在BANK111上,但是这个125MHz仍然可以被BANK111“借”用。但是这种方法需要写软件配置SI5324,比较麻烦,所以不推荐。

  下面介绍另外一种得到这个125MHz时钟的方法:由于BANK111上有一路时钟是连接到SMA接口上的,所以这个125MHz时钟可以用外部的信号源接入,但是如果你没有信号源的话也没事,这个125MHz时钟可以通过FPGA内部的Clocking Wizard产生。

       ZC706评估板的结构图如下图所示

 

  可以看到上图用红色椭圆圈出来的9号和10号两个SMA接口对,10号SMA接口就是连接到BANK111上的一个参考时钟,所以我们只需要用FPGA中的Clocking Wizard IP核用ZC706的200MHz系统时钟得到125MHz的时钟输出到9号SMA接口对,然后用同轴线把9号SMA接口对和10号接口对相连就可以了。由于Clocking Wizard IP核输出的时钟是单端时钟,所以还必须用OBUFDS原语把这个125MHz单端时钟变成差分时钟输出到9号SMA接口对。

  有了125MHz的参考时钟以后,接下来就只需要修改例子工程的顶层srio_example_top_srio_gen2_0代码,添加9号SMA接口对的引脚定义,修改例子工程的物理约束就可以了。还有一个信号就是srio_example_top_srio_gen2_0顶层代码中的sim_train_en在硬件上执行时必须置0。修改完成以后就可以生成bit文件下载到ZC706上观察现象了,还可以用ILA抓一下I/O通道的波形,没有问题的话抓出来的波形和之前仿真的波形是完全一样的。

六、总结

       整个RapidIO系列博客到此就全部写完了,最后提供两个仿真的建议:

       1、上文我抓的包传输数据量都比较少,主要是方便我截图,传输的数据量比较大的时候,整个包的总字节数会超过80个字节,在数据量超过80字节的情况下包中会出来两个循环冗余校验码(CRC码),这个在《RapidIO串行物理层的包与控制符号》提到过,大家可以自己把包的数据量改的大一点观察一下数据量大于80字节的情况。

       2、由于例子工程中测试的比较全面,所以一共发了很多包,这样导致找包的时候非常难找,这里提供一个小技巧,你只需要把srio_request_gen_srio_gen2_0.v模块中的第359行instruction的索引值request_address改成一个固定的数,那么就只会连续不断的发一种包,看波形的时候就会非常方便,缺点是每修改一次就需要重新仿真,所以比较耗费时间。

 

七、参考资料

       1、Xilinx_Answer_50166。下载链接:https://china.xilinx.com/Attachment/Xilinx_Answer_50166_SRIO_Debugging_Packet_Analysis_Guide_ver1.pdf

  2、RapidIO™ Interconnect Specification,下载链接 https://pan.baidu.com/s/1ek-3AAhetLAcxTuOE2IyMg

  3、pg007_srio_gen2,下载地址 https://china.xilinx.com/support/documentation/ip_documentation/srio_gen2/v4_0/pg007_srio_gen2.pdf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值