基于Ultrascale+系列GTY收发器64b/66b编码方式的数据传输(一)——Async Gearbox使用及上板测试 一文介绍了64B/66B编码方式及如何使用GTY IP核提供的Async Gearbox进行64B/66B数据传输,由于Async Gearbox方式下无法使用buffer bypass方式提供的低延时,因此本文介绍另一种64B/66B实现方式Sync Gearbox的使用方法。
Sync Gearbox原理
Sync Gearbox相当于一个不同位宽的同步FIFO,TX端的Sync Gearbox用于将输入的66bit数据(2bit同步头+64bit数据(TX_DATA_WIDTH))转换为64bit位宽(TX_INT_DATAWIDTH)的输出数据。为了带宽匹配,每输入32个周期的66bit到Sync Gearbox,都需要33个周期通过64bit从Sync Gearbox输出。因此Sync Gearbox每隔33个周期都会有一个周期不存储输入的数据。
同样的,在RX端的Sync Gearbox用于将输入的64bit位宽(RX_INT_DATAWIDTH)转换为66bit数据(2bit同步头+64bit数据(RX_DATA_WIDTH))的输出数据,为了带宽匹配,每输入33个周期的64bit到Sync Gearbox,都需要32个周期通过66bit从Sync Gearbox输出。因此Sync Gearbox每隔33个周期都会有一个周期不输出有效的数据。
在具体实现上,Sync Gearbox的输入及输出位宽存在多种选择,不同方式在相隔多少个周期停顿一个周期、以及每隔多少周期向FIFO/从FIFO中读取一个数据两个方面存在区别。以外部数据位宽与内部数据位宽均为64情况为例,发送数据每两个TXDEQUENCE时钟周期变化一次,每发送32个数据后都需要暂停一次发送新的数据。
GTY IP核配置
GTY的配置方式与Async Gearbox类似,这里为了便于逻辑实现,采用外部数据位宽为64,内部数据位宽为32的方式。
代码编写
发送部分
发送主要用到txheader_in_r、txsequence_in_r、gtwiz_userdata_tx_in_r三个变量,不同点在于txheader_in_r需要在txsequence_in_r计数到32时的数据无效,即令TX发送端不认为txheader_in_r此时发送了数据。
assign txsend_stop_s = (&txsequence_in_r[4:0]) == 1'b1 ? 1'b1 : 1'b0; // 31always_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: beginif (txsend_stop_s) begintx_fsm_s = TX_IDLE;end else begintx_fsm_s = TX_SEND_MIX_DATA;endendTX_SEND_MIX_DATA: beginif (txsend_stop_s) begintx_fsm_s = TX_SEND_MIX_DATA;end else begintx_fsm_s = TX_SEND_DATA;endendTX_SEND_DATA: beginif (txsend_stop_s) begintx_fsm_s = TX_SEND_DATA;end else begintx_fsm_s = TX_IDLE;endenddefault: tx_fsm_s = TX_RESET;endcaseendalways_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begincase (tx_fsm_s)TX_RESET: begintxsequence_in <= 7'b0;txsequence_in_r <= 7'b0;enddefault: begintxsequence_in <= txsequence_in_r;txsequence_in_r[6:6] <= 1'b0;if (txsequence_in_r[5] == 1'b1) begintxsequence_in_r[5:0] <= 6'd0;end else begintxsequence_in_r[5:0] <= txsequence_in_r[5:0] + 'd1;endendendcaseendalways_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: begintxheader_in_r[1:0] <= 2'b10;gtwiz_userdata_tx_in_r[63:0] <= {{7{XGMII_IDLE}}, 8'h1e};endTX_SEND_MIX_DATA: begintxheader_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: begintxheader_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}; endendcaseendalways_ff @(posedge gtwiz_userclk_tx_usrclk2_out) beginif (~txsend_stop_s) begintxheader_in <= txheader_in_r;endend
接收部分
接收主要用到rxgearboxslip_in、rxdatavalid_out、rxheader_out、rxheadervalid_out,其中rxdatavalid_out与rxheadervalid_out为不同于Async Gearbox的信号,他们用于指示fifo是否读空,即此时输出的数据要当做无效数据处理。
帧同步过程与接收部分与Async Gearbox时用到的方法类似,只是需要在header_valid为无效状态时暂停同步相关计数器计数。
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;endcaseendalways_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 (rxheadervalid_out[0]) 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;endend else beginrx_keep <= 8'h00;rx_strb <= 8'h00;endendendcaseend
仿真结果
上板测试
完整代码
本文所涉及代码可于同名公众号回复GTY_64B66B_SYNC获取。