Ultrascale+ 系列 GTY 收发器基于 64b/66b 编码模式的数据传输 (II) - 同步齿轮箱的使用和板载测试
基于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; // 31
always_comb begin
case (tx_fsm_r)
TX_RESET: begin
if (gtwiz_reset_tx_done_out) begin
tx_fsm_s = TX_IDLE;
end else begin
tx_fsm_s = TX_RESET;
end
end
TX_IDLE: begin
if (txsend_stop_s) begin
tx_fsm_s = TX_IDLE;
end else begin
tx_fsm_s = TX_SEND_MIX_DATA;
end
end
TX_SEND_MIX_DATA: begin
if (txsend_stop_s) begin
tx_fsm_s = TX_SEND_MIX_DATA;
end else begin
tx_fsm_s = TX_SEND_DATA;
end
end
TX_SEND_DATA: begin
if (txsend_stop_s) begin
tx_fsm_s = TX_SEND_DATA;
end else begin
tx_fsm_s = TX_IDLE;
end
end
default: tx_fsm_s = TX_RESET;
endcase
end
always_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begin
case (tx_fsm_s)
TX_RESET: begin
txsequence_in <= 7'b0;
txsequence_in_r <= 7'b0;
end
default: begin
txsequence_in <= txsequence_in_r;
txsequence_in_r[6:6] <= 1'b0;
if (txsequence_in_r[5] == 1'b1) begin
txsequence_in_r[5:0] <= 6'd0;
end else begin
txsequence_in_r[5:0] <= txsequence_in_r[5:0] + 'd1;
end
end
endcase
end
always_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begin
case (tx_fsm_s)
TX_RESET: begin
txheader_in_r <= 6'b0;
gtwiz_userdata_tx_in_r <= 64'h0;
end
TX_IDLE: begin
txheader_in_r[1:0] <= 2'b10;
gtwiz_userdata_tx_in_r[63:0] <= {{7{XGMII_IDLE}}, 8'h1e};
end
TX_SEND_MIX_DATA: begin
txheader_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};
end
TX_SEND_DATA: begin
txheader_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};
end
endcase
end
always_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begin
if (~txsend_stop_s) begin
txheader_in <= txheader_in_r;
end
end
接收部分
接收主要用到rxgearboxslip_in、rxdatavalid_out、rxheader_out、rxheadervalid_out,其中rxdatavalid_out与rxheadervalid_out为不同于Async Gearbox的信号,他们用于指示fifo是否读空,即此时输出的数据要当做无效数据处理。
帧同步过程与接收部分与Async Gearbox时用到的方法类似,只是需要在header_valid为无效状态时暂停同步相关计数器计数。
always_comb begin
case (rx_fsm_r)
RX_RESET: begin
if (rx_reset_flag_rr) begin
rx_fsm_s = RX_RESET;
end else begin
rx_fsm_s = RX_RECV;
end
end
RX_RECV: begin
rx_fsm_s = RX_RECV;
end
default: rx_fsm_s = RX_RESET;
endcase
end
always_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begin
case (rx_fsm_s)
RX_RESET: begin
rx_data <= 64'h0;
rx_keep <= 8'h0;
rx_strb <= 8'h0;
rx_valid <= 1'b0;
rx_last <= 1'b0;
end
RX_RECV: begin
if (rxheadervalid_out[0]) begin
if (rxheader_out_r[1:0] == 2'b10) begin
case (gtwiz_userdata_rx_out_r[7:0])
8'h78: begin // S0D1D2D3/D4D5D6D7
rx_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;
end
8'hff: begin // D0D1D2D3/D4D5D6T7
rx_data <= {8'h0, gtwiz_userdata_rx_out_r[63:8]};
rx_keep <= 8'hff;
rx_strb <= 8'h7f;
rx_last <= 1'b1;
end
8'h1e: begin
rx_valid <= 1'b0;
end
endcase
end else if (rxheader_out_r[1:0] == 2'b01) begin
rx_data <= gtwiz_userdata_rx_out_r[63:0];
rx_keep <= 8'hff;
rx_strb <= 8'hff;
rx_last <= 1'b0;
end
end else begin
rx_keep <= 8'h00;
rx_strb <= 8'h00;
end
end
endcase
end
仿真结果
上板测试
完整代码
本文所涉及代码可于同名公众号回复GTY_64B66B_SYNC获取。