于20世纪80年代左右由IBM提出的传统8B/10B编码方式在编码效率上较低(仅为80%),为了提升编码效率,Dgilent Techologies公司于2000年左右提出了64b/66b编码并应用于10G以太网中。Xilinx GT手册中没有过多64b/66b编码介绍,这里本人主要参考(https://www.ieee802.org/3/10GEPON_study/public/july06/thaler_1_0706.pdf、https://grouper.ieee.org/groups/802/3/ae/public/mar00/walker_1_0300.pdf、https://www.ieee802.org/3/bn/public/mar13/hajduczenia_3bn_04_0313.pdf)三篇文献。本文对64B/66B编码方式、GTY IP核Aync Gearbox 64B/66B配置及使用方法进行介绍并进行仿真及上板测试。
64B/66B编码简介
64B/66B仍采用突发数据传输的方式传输数据,一个完整的数据传输过程包含S(起始位)、D(数据位)、T(停止位)三种类型的字符,在空闲时刻,可以发送C / Z(控制类字符)。不同于8B/10B的是,64B/66B会对一个完整的数据流进行分割,变成几个64bit的蓝色小段。
几个蓝色小段的格式需要满足如下表格中的某一模式,64B/66B会对这些64bit的小段编码成66bit(加上2bit Sync字段)的数据。
如上图,64B/66B仍包括控制字符和数据字符两种字符,不同于8B/10B的是,数据传输的起始停止控制字符通过块类型字段隐形确定其类型及位置。其中起始控制字符只有位与第0字节和第5字节两种情况。
完整的控制字符列表如下,其中不同协议所规定的控制字符标识有所不同,本文使用XGMII协议的控制字符:
字节对齐(帧同步算法): 8B/10B的字节对齐通过划窗检测逗号K码进行,64B/66B的字节对齐方式与之类似,通过划窗检测有效Sync header同步头进行,有效同步头仅包含01和10两种类型,当识别到11或00无效同步头后,划窗进行下次判定。
-
在连续识别到64个有效同步头后,确定帧同步完成,字节对齐
-
在64个同步头中识别到16个无效同步头后,确定帧同步失效,重新进行同步
-
在125us中出现任意16个错误后,认为帧同步无法实现,禁止帧同步。
防止字节对齐误判: 当TX发送的66bit报文过于特殊时,如{{8’h01, 8’h02, 8’h03, 8’h04, 8’h05, 8’h06, 8’h07, 8’h78, {8’h08, 8’h09, 8’h0a, 8’h0b, 8’h0c, 8’h0d, 8’h0e, 8’hff}},64B/66B字节对齐可能会出现在数据中位置,如下图所示,此时检测的同步始终为01和10,但得到的同步后的数据是错误的。
幸运的是,64/66bit报文通常需要进行加扰解扰操作(Scramble/Descramble),即在发送的数据中添加白噪声,当接收后去掉白噪声得到原始数据。
** 64B/66B加扰解扰:** 64B/66B加扰解扰的表达式为 X58 + X19 + 1 = 0,其具体实现方式可参考Xilinx GT示例工程。
GTY的64B/66B配置方式
对于64B/66B编码,GTY支持采用Async Gearbox和Sync Gearbox两种方式,两种方式的区别在于异步变速箱提供的用户时钟能够完美匹配64B的发送速率,不会出现每隔一段时间停发一次数据的情况,本文采用Async Gearbox方式进行实现。此外,由于64B/66B对64B数据进行编码,因此本文选择使用64bit的用户数据位宽。
64B/66B的字节对齐由用户逻辑进行判断,因此无法选择。在其他配置上,本文使用的配置与8B/10B配置相同,如仍选用QSFP1所在GT。
GTY 64B/66B的使用方法:
发送模块
发送主要包含txheader_in_r、txsequence_in_r、gtwiz_userdata_tx_in_r三个信号,txheader_in_r用于填入同步头,gtwiz_userdata_tx_in_r用于填入待传输块数据,txsequence_in_r用于填入一个累加计数器,TX Async Gearbox相同于一个66bit转64bit的异步FIFO,txsequence_in_r用于TX Async Gearbox FIFO的写入数据计数。
发送一个14字节数据包的代码如下:
enum logic [3:0] {TX_RESET,TX_IDLE,TX_SEND_MIX_DATA,TX_SEND_DATA} tx_fsm_r, tx_fsm_s;always_comb begincase (tx_fsm_r)TX_RESET: beginif (gtwiz_reset_tx_done_out) begintx_fsm_s = TX_IDLE;end else begintx_fsm_s = TX_RESET;endendTX_IDLE: begintx_fsm_s = TX_SEND_MIX_DATA;endTX_SEND_MIX_DATA: begintx_fsm_s = TX_SEND_DATA;endTX_SEND_DATA: begintx_fsm_s = TX_IDLE;enddefault: tx_fsm_s = TX_RESET;endcaseendalways_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begincase (tx_fsm_s)TX_RESET: begintxheader_in_r <= 6'b0;gtwiz_userdata_tx_in_r <= 64'h0;endTX_IDLE: begin // C0C1C2C3/C4C5C6C7txheader_in_r[1:0] <= 2'b10;gtwiz_userdata_tx_in_r[63:0] <= {{7{XGMII_IDLE}}, 8'h1e};endTX_SEND_MIX_DATA: begin // S0D1D2D3/D4D5D6D7txheader_in_r[1:0] <= 2'b10;gtwiz_userdata_tx_in_r[63:0] <= {8'h01, 8'h02, 8'h03, 8'h04, 8'h05, 8'h06, 8'h07, 8'h78}; endTX_SEND_DATA: begin // D0D1D2D3/D4D5D6T7txheader_in_r[1:0] <= 2'b10;gtwiz_userdata_tx_in_r[63:0] <= {8'h08, 8'h09, 8'h0a, 8'h0b, 8'h0c, 8'h0d, 8'h0e, 8'hff}; endendcaseend
接收同步模块
接收同步模块按照前文所说同步算法进行实现,包含SYNC_OUT未同步和SYNC_IN同步完成两个状态。主要利用rxgearboxslip_in进行单比特划窗,以及rxheader_out检测同步头。
enum logic [3:0] {RX_SYNC_RESET,RX_SYNC_OUT,RX_SYNC_IN} rx_sync_fsm_r, rx_sync_fsm_s;always_comb begincase (rx_sync_fsm_r)RX_SYNC_RESET: beginif (gtwiz_reset_rx_done_out) beginrx_sync_fsm_s = RX_SYNC_OUT;end else beginrx_sync_fsm_s = RX_SYNC_RESET;endendRX_SYNC_OUT: begin if (rxheadervalid_out & ^rxheader_out[1:0] && valid_sync_headers_cnt_r == 6'd63) beginrx_sync_fsm_s = RX_SYNC_IN;end else beginrx_sync_fsm_s = RX_SYNC_OUT;endendRX_SYNC_IN: beginif (rxheadervalid_out & ~(^rxheader_out[1:0]) && invalid_sync_headers_cnt_r == 5'rx_sync_fsm_s = RX_SYNC_OUT;end else beginrx_sync_fsm_s = RX_SYNC_IN;endenddefault: rx_sync_fsm_s = RX_SYNC_RESET;endcaseendalways_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begincase (rx_sync_fsm_s)RX_SYNC_RESET: beginvalid_sync_headers_cnt_r <= 6'd0;invalid_sync_headers_cnt_r <= 4'd0;headers_cnt_r <= 6'd0;rxgearboxslip_in <= 1'b0;endRX_SYNC_OUT: beginif (rxheadervalid_out) beginif (^rxheader_out[1:0]) beginvalid_sync_headers_cnt_r <= valid_sync_headers_cnt_r + 6'd1;end else beginvalid_sync_headers_cnt_r <= 6'd0;headers_cnt_r <= headers_cnt_r + 6'd1;endendif (rxheadervalid_out && headers_cnt_r == 6'd63) beginrxgearboxslip_in <= 1'b1;end else beginrxgearboxslip_in <= 1'b0;endendRX_SYNC_IN: beginvalid_sync_headers_cnt_r <= 6'd0;if (rxheadervalid_out) beginif (~(^rxheader_out[1:0])) begininvalid_sync_headers_cnt_r <= invalid_sync_headers_cnt_r + 6'd1;end else if (headers_cnt_r == 6'd63) begininvalid_sync_headers_cnt_r <= 6'd0;endheaders_cnt_r <= headers_cnt_r + 6'd1; endrxgearboxslip_in <= 1'b0;endendcaseend
接收模块
接收同步模块输出采用AXI-Stream接口,主要根据rxheader_out_r、gtwiz_userdata_rx_out_r[7:0]进行查表,得出tkeep、tstrb、tlast、tvalid、tdata的相应值。
enum logic [3:0] {RX_RESET,RX_RECV} rx_fsm_r, rx_fsm_s;always_comb begincase (rx_fsm_r)RX_RESET: beginif (rx_reset_flag_rr) beginrx_fsm_s = RX_RESET;end else beginrx_fsm_s = RX_RECV;endendRX_RECV: begin rx_fsm_s = RX_RECV;enddefault: rx_fsm_s = RX_RESET;endcaseend(* MARK_DEBUG= "true" *) logic [63:0] rx_data;(* MARK_DEBUG= "true" *) logic [7:0] rx_keep;(* MARK_DEBUG= "true" *) logic [7:0] rx_strb;(* MARK_DEBUG= "true" *) logic rx_valid;(* MARK_DEBUG= "true" *) logic rx_last;always_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begincase (rx_fsm_s)RX_RESET: beginrx_data <= 64'h0;rx_keep <= 8'h0;rx_strb <= 8'h0;rx_valid <= 1'b0;rx_last <= 1'b0;endRX_RECV: beginif (rxheader_out_r[1:0] == 2'b10) begincase (gtwiz_userdata_rx_out_r[7:0])8'h78: begin // S0D1D2D3/D4D5D6D7rx_valid <= 1'b1;rx_data <= {gtwiz_userdata_rx_out_r[63:8], 8'h0};rx_keep <= 8'hff;rx_strb <= 8'hfe;rx_last <= 1'b0;end8'hff: begin // D0D1D2D3/D4D5D6T7rx_data <= {8'h0, gtwiz_userdata_rx_out_r[63:8]};rx_keep <= 8'hff;rx_strb <= 8'h7f;rx_last <= 1'b1;end8'h1e: beginrx_valid <= 1'b0;endendcaseend else if (rxheader_out_r[1:0] == 2'b01) beginrx_data <= gtwiz_userdata_rx_out_r[63:0];rx_keep <= 8'hff;rx_strb <= 8'hff;rx_last <= 1'b0;endendendcaseend
仿真测试
上板测试
完整代码
完整代码可于同名公众号回复GTY_64B66B_SIMPLE下载。