基于Ultrascale+系列GTY收发器8b/10b编码方式的数据传输(一)——GTY IP核介绍及配置 简单介绍了GTY收发器使用8B/10B编码所需的配置,本文继续利用前文配置的IP核进行数据收发。前文配置的GTY IP核引脚如下。
复位逻辑
如前文所述,GTY使用前必须经过复位,GTY中TX、RX的复位可通过复位状态机进行。用户逻辑需要在时钟复位完成后(gtpowergood拉高)向TX、RX复位信号(gtwiz_userclk_tx_reset_in、gtwiz_userclk_rx_reset_in)提供使能。以TX复位为例,相关控制逻辑如下:
logic gtpowergood_meta_r, gtpowergood_gtwiz_reset_clk_freerun_r;
always_ff @(posedge gtwiz_reset_clk_freerun_in) begin // cdc async gtpowergood
gtpowergood_meta_r <= gtpowergood_out;
gtpowergood_gtwiz_reset_clk_freerun_r <= gtpowergood_meta_r;
end
enum logic [2:0] {
RESETTX,
IDLETX
} txreset_fsm_r = RESETTX, txreset_fsm_s;
always_ff @(posedge gtwiz_reset_clk_freerun_in) begin // async reset
txreset_fsm_r <= txreset_fsm_s;
end
always_comb begin
case (txreset_fsm_r)
RESETTX: begin
if (gtpowergood_gtwiz_reset_clk_freerun_r) begin
txreset_fsm_s = IDLETX;
end else begin
txreset_fsm_s = RESETTX;
end
end
IDLETX: begin
txreset_fsm_s = IDLETX;
end
default: txreset_fsm_s = RESETTX;
endcase
end
always_ff @(posedge gtwiz_reset_clk_freerun_in) begin
case (txreset_fsm_s)
RESETTX: begin
gtwiz_userclk_tx_reset_in <= 1'b1;
end
IDLETX: begin
gtwiz_userclk_tx_reset_in <= 1'b0;
end
default: begin
gtwiz_userclk_tx_reset_in <= 1'b1;
end
endcase
end
8B/10B数据帧格式
本文采用的8B/10B数据帧采用K29.7作为数据帧起始位,K27.7作为数据帧停止位,数据帧传输前需传输4个字节的时钟纠正序列。
K28.5 | D16.2 | K28.5 | D16.2 | K29.7 | DATA… | K27.7 | … |
---|
用户逻辑
在使用GTY的8B/10B编码时,8B/10B对应关系表已固化在GTY硬核中,用户不需要编写进行8B/10B转换的逻辑,只需要将需要的极性、数据字节值、是否为控制字符送到硬核进行发送,以及从硬核读取接收到的数据字节即可。
下图展示了TX发送及RX接口的8B/10B转化过程,GTY硬核采用小端的方式,TX位于低位(LSB)的字节为优先发送的数据,RX位于低位(LSB)的字节为最早接收的数据。
发送逻辑
GTY的8B/10B发送主要包含gtwiz_userdata_tx_in、txctrl0、txctrl1、txctrl2接口。
gtwiz_userdata_tx_in为发送的原始数据,txctrl2用于指定发送的原始数据对应8bit字节是否为控制字符。
txctrl0、txctrl1用于指定待发送的原始数据采用正极性还是负极性编码,当设置为0时,由GTY硬核自动计算编码。
发送8B/10B的数据帧的方式如下,在gtwiz_reset_tx_done_out信号拉高后,tx部分结束复位状态,通过SEND_HDR发送纠正序列、SEND_DATA发送帧起始位及三个数据字符、SEND_EOF发送三个数据字符及帧结束位,依次往复。
assign txctrl1_in = 16'h0; // 5bit disparity
assign txctrl0_in = 16'h0; // 3bit disparity
enum logic [3:0] {
SEND_RESET,
SEND_LFSR,
SEND_HDR,
SEND_DATA,
SEND_EOF
} send_fsm_r, send_fsm_s;
always_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begin
if (gtwiz_reset_tx_done_out) begin
send_fsm_r <= send_fsm_s;
end else begin
send_fsm_r <= SEND_RESET;
end
end
always_comb begin
case (send_fsm_r)
SEND_RESET: begin
if (gtwiz_reset_tx_done_out) begin
send_fsm_s = SEND_LFSR;
end else begin
send_fsm_s = SEND_RESET;
end
end
SEND_LFSR: send_fsm_s = SEND_HDR;
SEND_HDR: send_fsm_s = SEND_DATA;
SEND_DATA: send_fsm_s = SEND_EOF;
SEND_EOF: send_fsm_s = SEND_LFSR;
default: send_fsm_s = SEND_RESET;
endcase
end
always_ff @(posedge gtwiz_userclk_tx_usrclk2_out) begin
case (send_fsm_s)
SEND_RESET, SEND_LFSR: begin
gtwiz_userdata_tx_in <= 32'h0;
txctrl2_in <= 4'b0000;
end
SEND_HDR: begin
gtwiz_userdata_tx_in <= {8'h50, 8'hbc, 8'h50, 8'hbc}; // bc50bc50
txctrl2_in <= 4'b0101;
end
SEND_DATA: begin // sof + 3 data
gtwiz_userdata_tx_in <= {8'h03, 8'h02, 8'h01, FRAME_SOF};
txctrl2_in <= 4'b0001;
end
SEND_EOF: begin // eof + 3 data / LFSR
gtwiz_userdata_tx_in <= {FRAME_EOF, 8'h06, 8'h05, 8'h04};
txctrl2_in <= 4'b1000;
end
endcase
end
接收逻辑
GTY的8B/10B接收主要包含gtwiz_userdata_rx_out、rxctrl0、rxctrl1、txctrl2、rxctrl3接口。
gtwiz_userdata_rx_out为接收到的原始数据,rxctrl0用于表明接收的对应8bit数据是否为控制字符。rxctrl1用于表明对应的8bit字节极性错误、rxctrl2用于表明对应8bit字节为逗号标志、rxctrl3用于表明接收的10bit不对应任何8bit数据,即这里对应的8bit数据无效。
在接收逻辑部分,帧起始位与帧结束位可能出现在4字节gtwiz_userdata_rx_out的任意一个字节,因此状态机需要对任何一个字节作为帧起始位或结束位的情况进行处理。
enum logic [3:0] {
RECV_RESET,
RECV_DET,
RECV_HDR,
RECV_DATA
} recv_fsm_r, recv_fsm_s;
always_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begin
if (gtwiz_reset_rx_done_out) begin
recv_fsm_r <= recv_fsm_r;
end else begin
recv_fsm_r <= RECV_RESET;
end
end
always_comb begin
case (recv_fsm_r)
RECV_RESET: begin
if (gtwiz_reset_rx_done_out) begin
recv_fsm_s = RECV_DET;
end else begin
recv_fsm_s = RECV_RESET;
end
end
RECV_DET: begin
recv_fsm_s = RECV_DET;
end
default: recv_fsm_s = RECV_RESET;
endcase
end
(* MARK_DEBUG="true" *) logic [31:0] rx_data;
(* MARK_DEBUG="true" *) logic [3:0] rx_keep;
(* MARK_DEBUG="true" *) logic rx_valid;
logic rx_valid_next, rx_valid_next_next;
always_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begin
case (recv_fsm_s)
RECV_RESET: begin
rx_valid <= 1'b0;
end
RECV_DET: begin
// clock correction need 4byte, sof must before than eof in 32bit
if (rxframe_eof_flag_rr && rxframe_eof_rest_cnt_r + rxframe_sof_rest_cnt_r > 4) begin
rx_valid <= 1;
end else begin
rx_valid <= rx_valid_next;
end
if (rxframe_eof_flag_r) begin
case ({1'b0, rxframe_eof_rest_cnt_r[1:0]} + {1'b0, rxframe_sof_rest_cnt_r[1:0]})
default: rx_keep <= 4'b1111;
3'd3: rx_keep <= 4'b0111;
3'd2: rx_keep <= 4'b0011;
3'd1: rx_keep <= 4'b0001;
3'd0: rx_keep <= 4'b0000;
endcase
end
else if (rxframe_eof_flag_rr) begin
case (rxframe_eof_rest_cnt_r[1:0] + rxframe_sof_rest_cnt_r[1:0])
2'd3: rx_keep <= 4'b0111;
2'd2: rx_keep <= 4'b0011;
2'd1: rx_keep <= 4'b0001;
2'd0: rx_keep <= 4'b0000;
endcase
end else if (rx_valid_next) begin
rx_keep <= 4'b1111;
end
case (rxframe_sof_rest_cnt_s)
2'd3: rx_data <= {gtwiz_userdata_rx_out_r[7:0], gtwiz_userdata_rx_out_rr[31:8]};
2'd2: rx_data <= {gtwiz_userdata_rx_out_r[15:0], gtwiz_userdata_rx_out_rr[31:16]};
2'd1: rx_data <= {gtwiz_userdata_rx_out_r[23:0], gtwiz_userdata_rx_out_rr[31:24]};
2'd0: rx_data <= gtwiz_userdata_rx_out_r; end
endcase
end
endcase
end
仿真测试
本工程对发送端发送帧长(不包含帧开始结束位)为0-6位进行了测试,这里以帧长为6的仿真结果举例。
上板测试
工程代码
本文所涉及的工程代码可于同名公众号回复GTY_8B10B_SIMPLE下载。