基于Ultrascale+系列GTY收发器64b/66b编码方式的数据传输(一)——Async Gearbox使用及上板测试

  于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 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
            tx_fsm_s = TX_SEND_MIX_DATA;
        end
        TX_SEND_MIX_DATA: begin
            tx_fsm_s = TX_SEND_DATA;
        end
        TX_SEND_DATA: begin
            tx_fsm_s = TX_IDLE;
        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
            txheader_in_r <= 6'b0;
            gtwiz_userdata_tx_in_r <= 64'h0;
        end
        TX_IDLE: begin // C0C1C2C3/C4C5C6C7
            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 // S0D1D2D3/D4D5D6D7
            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 // D0D1D2D3/D4D5D6T7
            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

接收同步模块

  接收同步模块按照前文所说同步算法进行实现,包含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 begin
        case (rx_sync_fsm_r)
        RX_SYNC_RESET: begin
            if (gtwiz_reset_rx_done_out) begin
                rx_sync_fsm_s = RX_SYNC_OUT;
            end else begin
                rx_sync_fsm_s = RX_SYNC_RESET;
            end
        end
        RX_SYNC_OUT: begin 
            if (rxheadervalid_out & ^rxheader_out[1:0] && valid_sync_headers_cnt_r == 6'd63) begin
                rx_sync_fsm_s = RX_SYNC_IN;
            end else begin
                rx_sync_fsm_s = RX_SYNC_OUT;
            end
        end
        RX_SYNC_IN: begin
            if (rxheadervalid_out & ~(^rxheader_out[1:0]) && invalid_sync_headers_cnt_r == 5'
                rx_sync_fsm_s = RX_SYNC_OUT;
            end else begin
                rx_sync_fsm_s = RX_SYNC_IN;
            end
        end
        default: rx_sync_fsm_s = RX_SYNC_RESET;
        endcase
    end

    always_ff @(posedge gtwiz_userclk_rx_usrclk2_out) begin
        case (rx_sync_fsm_s)
        RX_SYNC_RESET: begin
            valid_sync_headers_cnt_r <= 6'd0;
            invalid_sync_headers_cnt_r <= 4'd0;
            headers_cnt_r <= 6'd0;
            rxgearboxslip_in <= 1'b0;
        end
        RX_SYNC_OUT: begin
            if (rxheadervalid_out) begin
                if (^rxheader_out[1:0]) begin
                    valid_sync_headers_cnt_r <= valid_sync_headers_cnt_r + 6'd1;
                end else begin
                    valid_sync_headers_cnt_r <= 6'd0;
                    headers_cnt_r <= headers_cnt_r + 6'd1;
                end
            end

            if (rxheadervalid_out && headers_cnt_r == 6'd63) begin
                rxgearboxslip_in <= 1'b1;
            end else begin
                rxgearboxslip_in <= 1'b0;
            end
        end
        RX_SYNC_IN: begin
            valid_sync_headers_cnt_r <= 6'd0;
            if (rxheadervalid_out) begin
                if (~(^rxheader_out[1:0])) begin
                    invalid_sync_headers_cnt_r <= invalid_sync_headers_cnt_r + 6'd1;
                end else if (headers_cnt_r == 6'd63) begin
                    invalid_sync_headers_cnt_r <= 6'd0;
                end
                headers_cnt_r <= headers_cnt_r + 6'd1; 
            end

            rxgearboxslip_in <= 1'b0;
        end
        endcase
    end

接收模块

  接收同步模块输出采用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 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

    (* 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) 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 (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
        endcase
    end

仿真测试

图片

上板测试

图片

完整代码

  完整代码可于同名公众号回复GTY_64B66B_SIMPLE下载。

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjh776a68

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值