当我们去看有关高速串行总线与并行总线相比较的优点,会发现有这么一条描述,说串行总线能实现分割式数据传输,所有的串行总线都使用包括包和分割式数据传输协议进行数据传输。串行总线有包的概念,包可以有包界定符号,包起始控制符,包结束控制符以及中间的数据信息,CRC校验信息等。
这篇博文,我们就通过仿真来理解下这句话的含义,看看我们是如何发送数据以及如何接收到数据的。
这里稍微偏题,总结下串行总线相较于并行总线的好处:
占用引脚数量少;
TX以及RX信号线上采用差分信号传输方式,这种传输方式具有很高的抗噪声能力;
强错误检测能力,串行协议使用了基于包的数据传输方式并带有CRC校验,接收设备能检测出接收数据包中的错误并通知发送端出现了传输错误,发送端可以重新发送出现错误的包;
全双工数据和控制流等。
好了,下面进入正题,我们的仿真程序使用了Vivado提供的例子程序:
新建工程,建立IP核,之后打开例子程序就好了:
可以看看仿真程序的结构:
一个primary,一个mirror,二者之间的关系就是primary发送数据,mirror接收数据,反之也成立。
二者程序都是例化了设计程序,所以内容一致,只不过一个是请求方一个是响应方而已。如下图:
我的IP核采用的是X1模式,也就是只有一对差分发送和接收线TX0_N, TX0_P, RX0_N, RX0_P。
下面是SRIO核的接口示意图:
可以看到,SRIO核协议可以分为三层,逻辑成LOG,传输层Buffer,以及物理层(PHY),数据从物理层出来就到了串行收发器,串行发送数据,或者数据从串行收发器接收串行数据,之后到达物理层,传输层以及逻辑层,用户能够操纵的是逻辑层的数据,我们对用户接口进行操作得到我们需要的数据(解析)。
逻辑层的包采用HELLO格式,关于这个格式可以看博文:【FPGA】SRIO中的关键问题总结(一)SRIO中的关键数据包格式总结
这种格式把包的包头进行标准化,而且把包头和数据在接口上分开传输,这将简化控制逻辑并且允许数据与发送边界对齐,有助于数据管理。
如下图:
下面是携带有数据负载的HELLO格式包在用户接口上传输的时序图,这个时序图传输了4个64位数据,也就是4个双字,加上包头,传输需要5个时钟周期。
当然,也并非必须携带数据负载,并且传输也可以等待,如下:
首先,有两个背靠背(back-to-back)单周期包(包不带数据负载,仅包含一个包头)。包的边界通过拉高tlast信号进行指示。在单周期包传输完毕以后,主机等待了一个时钟周期才开始发送下一个包。在发送第三个包的过程中,主机(Master)和从机(Slave)分别通过拉低tvalid和tready信号一个时钟周期来暂停数据的发送,由于第三个包的数据负载为2个双字,所以传输第三个包一共消耗了3个有效时钟,加上2个无效的时钟周期,一共消耗了5个时钟周期。
数据在逻辑层上传输后到达传输层,组装其他信息得到一个传输层的包,之后在传输到物理层,再次组装并添加信息层位物理层的包,这个包是最终的包,最终到达串行收发器发送出去,最终的包的格式如下:
可见,这里的包包括了各个层的信息。
当然发送出去的也并非都是数据包,也有控制符号包,如下为控制符号包格式:
控制符号通常用于充当包的起始标志,或结束标志,成为包起始控制符号以及包结束控制符号。
这点我们可以通过下面的仿真来理解。
先观察几个关键信号的波形,例如port_initialized和link_initialized,它们有效则表示端口和链路初始化成功。
之后观察发送的第一个发送的事物SWRITE:
登录后复制
localparam [64*37-1:0] swrite_instruction = {
// RSVD, FTYPE, TTYPE, ADDRESS, SIZE
// SWRITEs
{12'h000, SWRITE, 4'h0, 36'h000000777, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000008806, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000125, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000124, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000123, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000122, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000121, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000120, 8'd0},
{12'h000, SWRITE, 4'h0, 36'h000000126, 8'd1},
{12'h000, SWRITE, 4'h0, 36'h000000124, 8'd1},
{12'h000, SWRITE, 4'h0, 36'h000000122, 8'd1},
{12'h000, SWRITE, 4'h0, 36'h000004350, 8'd1},
{12'h000, SWRITE, 4'h0, 36'h000004355, 8'd2},
{12'h000, SWRITE, 4'h0, 36'h000012300, 8'd2},
{12'h000, SWRITE, 4'h0, 36'h000012304, 8'd3},
{12'h000, SWRITE, 4'h0, 36'h000345000, 8'd3},
{12'h000, SWRITE, 4'h0, 36'h000345003, 8'd4},
{12'h000, SWRITE, 4'h0, 36'h004550000, 8'd4},
{12'h000, SWRITE, 4'h0, 36'h004550002, 8'd5},
{12'h000, SWRITE, 4'h0, 36'h198877600, 8'd5},
{12'h000, SWRITE, 4'h0, 36'h198877601, 8'd6},
{12'h000, SWRITE, 4'h0, 36'h2ABBCCDD8, 8'd6},
{12'h000, SWRITE, 4'h0, 36'h2ABBCCDD8, 8'd7},
{12'h000, SWRITE, 4'h0, 36'h2ABBCCDD8, 8'd15},
{12'h000, SWRITE, 4'h0, 36'h2ABBCCDD8, 8'd31},
{12'h000, SWRITE, 4'h0, 36'h120000600, 8'd63},
{12'h000, SWRITE, 4'h0, 36'h230000600, 8'd95},
{12'h000, SWRITE, 4'h0, 36'h340000600, 8'd127},
{12'h000, SWRITE, 4'h0, 36'h450000600, 8'd255},
{12'h000, SWRITE, 4'h0, 36'h560000600, 8'd15},
{12'h000, SWRITE, 4'h0, 36'h670000600, 8'd31},
{12'h000, SWRITE, 4'h0, 36'h780000600, 8'd63},
{12'h000, SWRITE, 4'h0, 36'h780000600, 8'd95},
{12'h000, SWRITE, 4'h0, 36'h890000600, 8'd127},
{12'h000, SWRITE, 4'h0, 36'h9A0000600, 8'd255},
{12'h000, SWRITE, 4'h0, 36'hAB0000600, 8'd15},
{12'h000, SWRITE, 4'h0, 36'hCD0000600, 8'd15}};
下面以上图第50行的SWRITE事务为例来说明整个SWRITE事务的传输过程。这个事务表示的是利用SWRITE事务往地址36’hCD0000600发送16个字节的数据。
由于是一个请求事物,找到ireq开头的波形,如下图:
可以看上述波形中的tvalid,tready,tdata以及tlast可以清楚的看出传输的数据,这个波形和下面的传输时序图一致:
由于仅当tvalid和tready同时为高时,tdata上的数据才为有效数据,所以这个SWRITE一共消耗了三个有效时钟周期,其中第一个时钟周期发送的是HELLO包头,后面两个时钟周期分别发送8个字节的数据(第一个时钟发送的数据是0000000000000000,第二个时钟发送的数据是0101010101010101),一共16个字节的数据,和instruction_list.vh中第50行定义完全一致,整个时序也与HELLO格式的时序完全吻合。
对照HELLO格式解析包头。包头为006020fcd0000600,转化为二进制后与HELLO格式各个字段对应关系如下所示:
由上图可知FTYPE字段的值为6,表明确实是一个SWRITE事务。
SWRITE事务通道ireq通道(接口1)传输给SRIO核以后进入SRIO的逻辑层,逻辑层会给包添加传输层的信息发送给Buffer(接口3),然后Buffer会把数据发送给物理层(接口5),之后在发到SRIO串行收发器,这里直接看看观察SRIO收发器的数据通道gttx_data[31:0]:
7c96f004中的7c是特殊字符/K28.3/,它是一个包界定符(Packet Deliminator Control Symbol),968012是一个包起始控制符,968215是一个包结束控制符号。二者之间是包的内容:
b04600ad_d0000600_00000000_00000000_01010101_01010101_e8d30000是SWRITE事务串行物理层的包,把它转化为二进制后各个字段的对应关系如下图所示
上图中data字段是传输的00000000_00000000_01010101_01010101这16个字节数据的二进制码,因为它的二进制码太长了所以我直接用data替代。由于本次传输的字节小于80个字节,所以SWRITE事务的最后面的三个字段不存在,大家可以抓一下数据量为256个字节的SWRITE包,当数据量大于了80字节,后面的三个字段也会有数据。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删