目的是实现Mwr和Mrd包的解析;
PCIE IP核:

IP核信号:
Axi_stream接口,用于构建和解析TLP包;

配置接口和电源管理接口:

流控信号:比如给RC发数据,RC侧buffer没有空余空间,那么在发送侧不能发包,可以通过流控来监测,保证不出现堵塞,以及监测buffer空间;(pg213_p50)
流控接口:用于标识在buffer 中TLP包剩余数量;


中断接口:

状态接口:

动态配置接口和参考时钟复位接口:

关键信号:

例化时,将IP输出信号加入ILA,输入信号加入VIO,以保证PCIE硬核不被综合优化掉,就可以生成工程,识别pcie设备,搭建工程;
XILINX PCIE IP 的硬核接口为 AXI STREAM 接口;
实现从PCIE 核 RX stream 接口出来的数据先去解析与BAR相关的TLP包;
当前接收包路由模块的时钟和复位来自PCIE模块的输出;
AXI STREAM 接口:
TDATA:表示PCIE 传输层输出的包结构;
TVALID:谁提供数据,谁提供valid;在一个包开始和结束之间valid不会拉低;
TREADY:反压信号,当不想接收数据的时候拉低tready信号;
TKEEP:每bit指示对应数据字节有效;
TLAST:指示最后一次的传输;
TUSER: UG477 P29,包含了 sof, eof,sof_index,eof_index,bar_hit,err_fwd,err_ecrc;
err_fwd=1,表示该包需要丢弃;
TUSER的对应关系:

传输的数据位宽为128bit;
128bit的数据包的构成:3DW头 + 1DW 数据
3个DW,即3DW头,用于32位bit地址的寻址;3 x 32bit
4DW,用于64位bit地址的寻址;4 x 32bit
AXI Byte(XILINX) 与 PCIe Byte 存在字节反序关系:

4DW包结构,128位数据呈现在接口上的形式如下,xilinx IP核接口与PCIE 对应字节的顺序是反序;(64位为一个时钟周期,此时4个DW占用两个时钟周期;如果128位为一个时钟周期,此时4个DW占用1个时钟周期)
Clock0的0~31:第一个DW;
Clock0的32~63:第二个DW;
Clock1的Address:第3个DW;
Clock1的Data:第4个DW;

AXI Stream接口时序模式:(三种) ug477
- 单周期模式,一个周期发送传输的头数据;ready只会拉高一个周期;
128位数据包含了sof(开始)和eof(结束)完整包,且sof_index < eof_index,对于3DW,128位数据有32位为无效数据;

SOF=1 0000,表示 SOF在第0字节拉高;
EOF = 1 1011,表示 EOF 在第11字节拉高;
假如32bit的数据为:'hABCD,4个字节,0~3,4~7,8~11,12~15;
SOF开始的字节位置可以在:5'b1 0000 (DWORD 0)或者 5'b1 1000 (DWORD 2);
EOF结束的字节位置可以在:5'b1 0011 (DWORD 0) 或者 5'b1 0111 (DWORD 1)
或者 5'b1 1011 (DWORD 2) 或者 5'b1 1111 (DWORD 3) ;


SOF:10000,根据tuser字段含义,1表示起始头sof,后面0000表示字节,也就是开始字节在第0个字节;
EOF:11011,最高位1表示为结束字节,后面1011表示结束的字节数,即结束字节在第11个字节;
根据tdata为 -H2H1H0说明为3DW,即12个字节(0~11字节);最高位-为无效数据,即12~15为无效字节;

M_AXIS_RX_TUSER:[21:0]


- 多周期包,sof和eof不在一个周期中产生;





EOF和SOF均是指示开始和结束的位置以及第几个字节是有效数据;
比如4DW结构中SOF为10000,表明第0字节为开始字节,EOF为10011表明第3字节为结束字节,即D4(占4个字节,0~3)为有效数据,其余字节(4~15字节)为无效数据;对比rx_tdata看,EOF时,只有D4有效,其余为无效数据;
- 交错包结构,只存在128位的数据包结构中;
上一个包的eof和当前包的sof放在同一个128位数据中(eof和sof同时拉高),且此时sof_index > eof_index,通过index的对比就可以查看多周期包的时候是否是交错包,index通过信号 tuser可识别到;

产生交错包的时候需要把ready信号拉低,以将新的包头和上一个包尾数据分开;


根据新的 sof 标志拉高交错包的包头;
表5-7,通过sof_index 和 eof_index 判断出开始和结束的字节位置;
H1H0DnDn-1 : Dn和Dn-1是上一包的数据,结束位在Dn;H1H0指示新包的包头;
H1H0--Dn:结束位在Dn;


对比SOF=11000b 和 EOF=10011b可知,sof的index=8 是大于eof的index=3,由此就可以判断出eof是为上一个数据的eof,此sof对应的是下一个包;只是它们同时放在了一个128位的数据中;
根据以上3种包结构,得到bar 的控制信号,将数据传给bar;
对于交错包,目的是需要将SOF H0 和 EOF D1进行拆分,将SOF H0放在下一拍的头位置,以形成连续的数据流;
代码设计需要考虑到支持单周期,多周期,交错包三种情况;
思路:
分包检测:单周期,多周期,交错包
对于交错包,要把新的包头和上一包的包尾数据分开
拆分包头和数据,利用tready信号,将其拉低一拍,拉低tready后,数据不会进行传输,空出一拍用于进行分包处理;
通过拉高新的 sof 信号,作为分包后,新的包头new_sof标志
传输的3DW 结构:H0H1H2为头,X为无效数据,ABCD为有效数据;
128位: H1H0XX ------ CBAH2 ------ XXXD
在H1H0XX这一拍同时会存在上一拍数据的结束标志EOF以及当前包的SOF,目的是不让 SOF 和 EOF 在同一拍拉高,所以将tready信号拉低一拍,用来拆分这里的SOF和EOF;data占用两拍,第一拍是EOF拉高,第二拍是SOF拉高;
单周期:

多周期:

交错包:根据sof和eof可以看出分出了sof和eof在同一个数据下,但是不在同一拍,拆分成了两个包;

对传输的数据包进行了分包检测后,需要将包头对齐到0字节的位置;
需要明确 sof_index 和 eof_index 字段含义,可见IP协议,UG477;
对齐前:H1H0XX;对齐后:BAH1H0;
XILINX PCIE IP 的字段含义与PCIE协议字段存在反序问题;


将包头重新对齐到0字节位置,代码设计思路:
关键点:
传输的数据每一拍是128位,即16字节,当EOF为第3字节或者第7字节时,在进行数据的重新对齐,和排序的时候会将数据与上一拍的数据进行拼接成一拍数据(16字节),会由最开始接收的3拍数据缩减为2拍数据;当字节为第11字节和第15字节时,最后重新排序后的数据不会出现缩减;
传输的3DW 结构:
128位: H1H0XX ------ CBAH2 ------ XXXD; X 表示无效数据
根据 输入的 rx_in_sof_index 不为0,就表示包头不在字节0的位置,就需要重新对齐;
根据eof_Index 值的情况分两种:(值 指示的是字节数)
- 值为 3 或者 7,意味着 最后一拍数据是 XXXD 或者 XXDF
那么在对 H1H0XX 与CBAH2 进行数据拼接后,得到的数据为
AH2H1H0 ------ CBDX 或者 AH2H1H0 ------ CBDF
意味着 3拍数据 变为 2拍;eof_index 变为成 11 或者 15
- 值为 11 或者 15,意味着 输入3拍,输出依旧是3拍数据;只是结束位置 eof_index变了;
变成了3或者7;
H1H0XX ------ CBAH2 ------ XEFD 或者 H1H0XX ------ CBAH2 ------ GEFD
拼接后
AH2H1H0 ------ CBDF ------ XXXE 或者 AH2H1H0 ------ CBDF ------ XXGE
关键点:
看输入数据的eof_index是多少,从而可以判断出输出数据是会减少一拍,还是保持原来输入数据的拍数;

Sof_index = 8;说明同拍的4个DW中,有2个DW有效;
Eof_index = 7;说明同拍的4个DW中,有2个DW有效;
这样就可以将这4个DW 拼接到同一拍,即sof 和 eof 在同一个周期有效;
在将数据包对齐到0字节后,需要将包头剔除,只保留有效数据;
TLP包结构:发送从左到右

Fmt & Type字段:决定包的类型

Fmt:


根据Fmt[0]字段的值就可以判断是3DW还是4DW结构;
根据Fmt字段和Type字段可以判断 Mwr 还是 Mrd包;
解析Mwr和Mrd代码设计思路:
解析TLP 包的包头字段,剔除包头,保留数据;
输入进来的数据分两种:
AH2H1H0 ------ EDCB ------ XXXF 或者 AH2H1H0 ------ EDCB ------ KHGF
这两种情况在去除H2H1H0后会产生两种情况:
DCBA ------ XXFE 或者 DCBA ------ HGFE ------ XXXK
三拍数据变为两拍 , 或者 三拍数据剔除包头还是三拍数据;
也就是说当 eof_index == 'd15 的这种情况,三拍的输入数据在剔除包头后,依旧还剩下三拍数据,只是eof_index 的值发生了改变;
而其余 eof_index == 'd3,'d7,'d11 这三种情况,均是输入三拍数据,在剔除包头后还剩下两拍数据;

