GT收发器64B66B协议(2)自定义PHY设计

前言

有了对64B66B协议的认识以及我们之前设计8B10B自定义PHY的经验,本文开始对64B66B自定义PHY的设计

一、设计框图

在这里插入图片描述

二、GT_module

该模块整体设计与8B10B几乎一致,只有一些端口的区别;再就是将QPLL复位产生模块gtwizard_0_common_resetGT_channel模块放到了GT_module模块,但其实本质没有任何区别。

主要还是IP核配置变为64B66B之后输入输出的接口有一些变化,包括帧头信号,对齐信号以及发送队列计数器信号等。

同理,用户需要多个channel的时候只需要在GT_module模块当中例化多个GT_channel模块即可。

module GT_channel(
    input                   i_sysclk                    ,
    input                   i_gtrefclk                  ,
    input                   i_rx_rst                    ,
    input                   i_tx_rst                    ,
    output                  o_tx_done                   ,
    output                  o_rx_done                   ,
    input                   i_tx_polarity               ,
    input  [3 :0]           i_tx_diffctrl               ,
    input  [4 :0]           i_txpostcursor              ,
    input  [4 :0]           i_txpercursor               ,     
    input                   i_rx_polarity               ,
    input  [2 :0]           i_loopback                  ,
    input  [8 :0]           i_drpaddr                   , 
    input                   i_drpclk                    ,
    input  [15:0]           i_drpdi                     , 
    output [15:0]           o_drpdo                     , 
    input                   i_drpen                     ,
    output                  o_drprdy                    , 
    input                   i_drpwe                     ,
    input                   i_qplllock                  , 
    input                   i_qpllrefclklost            , 
    output                  o_qpllreset                 ,
    input                   i_qplloutclk                , 
    input                   i_qplloutrefclk             , 
    input                   i_data_valid                ,

    output                  o_rx_clk                    ,
    output [63:0]           o_rx_data                   ,
    output                  o_rx_valid                  ,
    output [1 :0]           o_rx_header                 ,
    output                  o_rx_header_valid           ,
    input                   i_rx_slipbit                ,

    output                  o_tx_clk                    ,
    input  [63:0]           i_tx_data                   ,
    input  [1 :0]           i_tx_header                 ,
    input  [6 :0]           i_tx_sequence               ,      

    output                  o_gt_tx_p                   ,
    output                  o_gt_tx_n                   ,
    input                   i_gt_rx_p                   ,
    input                   i_gt_rx_n                   
);

三、PHY_module

PHY层对数据进行组包和对齐的处理是难点所在
设计思路及代码思路参考了FPGA奇哥系列网课

3.1、PHY_tx模块

发送端工作流程:

  • 空闲时期拉高READY,用户数据进入FIFO,s_axis_last断言后拉低READY
  • FIFO不为空的时候从FIFO当中读出数据进行组帧
  • 当前数据帧发送完毕重新拉高READY
  • 大小端处理

发送数据时需要注意:每发送32个64bit数据之后用户需要暂停发送一拍数据,因为此时Gearbox需要将自己缓存的64bit数据吐出去。 从下图波形上看,sequence计数到31后,第32拍的用户数据是没办法被正常发送的,所以我们需要将该数据延迟到下一拍发送,所以图中的32和0时候的数据是一样的。
这个逻辑通过信号w_gt_send_valid 实现,达到30的时候拉低w_gt_send_valid ,这是因为还要考虑组帧时候的FIFO读潜伏期。

assign          w_gt_send_valid = ro_tx_sequence == 30 ? 0 : 1  ;

在这里插入图片描述
以上情况很好处理,但是如果刚刚好是在FIFO读使能拉高的时候w_gt_send_valid被拉低(下图所示),组帧逻辑就会混乱,主要是数据不会在ro_tx_sequence为32和0的时候保持不变,因此加入一个r_invalid用来处理这种情况,这里有点过于复杂了,还是需要多看看波形图进行分析,应该有比较简单的办法的。
不过思想是很简单的:就是保证在ro_tx_sequence == 32和ro_tx_sequence == 0的时候输出数据要连续保持,才能使得数据不会丢失。
在这里插入图片描述
最后一点就是大小端处理,我个人习惯处理数据按照大端处理,在最后发送的时候一次性转为小端模式。

assign o_tx_data = { ro_tx_data[7 : 0],ro_tx_data[15: 8],ro_tx_data[23:16],ro_tx_data[31:24],
                     ro_tx_data[39:32],ro_tx_data[47:40],ro_tx_data[55:48],ro_tx_data[63:56]};

3.2、PHY_rx_bitsync模块

该模块实现接收端字节对齐的功能
整体思路很简单:下图为xilinx手册ug476当中对示例文件的介绍。
大致思维:

  • 在64B66B当中,只有2;b10和2’b01俩种帧头是有效的,所以我们只需要判断帧头是否是有效的,就可以判断当前字节是否对齐。
  • 当检测到错误帧头时,拉高一个slipbit脉冲信号,那么Gearbox会自动将对齐窗口向后滑动一个比特,注意:每次拉高slipbit脉冲信号的时候至少要隔32个RXUSRCLK2时钟周期
  • 为了防止误判,只有当连续收到64个正确头的时候,才会判定为当前成功对齐,随后释放PHY_rx的复位,进行正常数据接收。
  • 在xilinx文档当中的状态机还增加了重新复位接受模块的状态,就是判定对齐之后,当连续收到16个错误头后判断对齐出现了错误,重新进行对齐(本工程当中没有这个状态,出现一个错误头立马复位,然后重新进行同步)。

在这里插入图片描述
下图为仿真波形,第一条黄线之前是进行不断同步的过程,每次同步之间相隔32时钟周期,俩条黄线之间是发生了错误判断的情况,但在收到一个错误帧头后立马重新开始了同步,第二条黄线(有点看不清,可以看下面黄色框框位置)后是正常同步。
在这里插入图片描述

3.3、PHY_rx模块

接收端处理流程:

  • 先将GT输入数据进行大小端转换
  • 识别到SOF之后开始恢复数据
  • 识别EOF以及EOF位置
  • 根据EOF位置处理最后一拍数据以及KEEP信号

同样的,在接收数据的时候,每隔32时钟周期就有一个无效数据,进行VALID信号处理的时候需要考虑该情况。这里还有一点很重要,那就是识别到SOF后紧接着这个无效数据就来了,这种情况也是需要单独讨论的,接收端的r_invalid信号就是用来处理这种情况的。
在这里插入图片描述
主要代码:

always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        rm_axis_data <= 'd0;
    else if(r_eof && (r_eof_local < 7 && r_eof_local > 0))
        rm_axis_data <= {ri_rx_data_1d[47:0],16'd0};  
    else if(w_eof && (w_eof_local == 0))
        rm_axis_data <= {ri_rx_data_1d[55:0],8'd0};
    else if(w_eof && (w_eof_local <= 7))
        rm_axis_data <= {ri_rx_data_1d[55:0],ri_rx_data[55:48]};  
    else if(r_receiving && ri_rx_valid)
        rm_axis_data <= {ri_rx_data_1d[55:0],ri_rx_data[63:56]};
    else 
        rm_axis_data <= 'd0;
end


always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        rm_axis_keep <= 8'b1111_1111;
    else if(r_eof && (r_eof_local < 7 && r_eof_local > 0))
        case(r_eof_local)
            1           :rm_axis_keep <= 8'b1111_1100;
            2           :rm_axis_keep <= 8'b1111_1000;
            3           :rm_axis_keep <= 8'b1111_0000;
            4           :rm_axis_keep <= 8'b1110_0000;
            5           :rm_axis_keep <= 8'b1100_0000;
            6           :rm_axis_keep <= 8'b1000_0000;           
            default     :rm_axis_keep <= 8'b1111_1111;
        endcase
    else if(w_eof && (w_eof_local == 0 || w_eof_local == 7))
        case(w_eof_local)
            0           :rm_axis_keep <= 8'b1111_1110;
            7           :rm_axis_keep <= 8'b1111_1111;            
            default     :rm_axis_keep <= 8'b1111_1111;
        endcase
    else 
        rm_axis_keep <= 8'b1111_1111;
end


always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        rm_axis_last <= 'd0;
    else if(rm_axis_last && rm_axis_valid)
        rm_axis_last <= 'd0;
    else if(rm_axis_valid && r_eof && (r_eof_local < 7 && r_eof_local > 0))
        rm_axis_last <= 'd1;
    else if(rm_axis_valid && w_eof && (w_eof_local == 7 || w_eof_local == 0))
        rm_axis_last <= 'd1;
    else 
        rm_axis_last <= rm_axis_last;
end

always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        rm_axis_valid <= 'd0;
    else if(r_sof)
        rm_axis_valid <= 'd1;
    else if(rm_axis_last && rm_axis_valid)
        rm_axis_valid <= 'd0;
    else if((!ri_rx_valid && ri_rx_header != 2'b10) || r_invalid)
        rm_axis_valid <= 'd0;
    else if(r_revalid)
        rm_axis_valid <= 'd1;
    else 
        rm_axis_valid <= rm_axis_valid;
end

四、上板测试

暂时还没有加扰和解扰,所以直接光纤连接通信有点问题,这里是开启回环模式下上板测试结果,收发是正常的。
在这里插入图片描述

总结

完整工程参考:https://github.com/shun6-6/GT64B66B_PHY_design

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

顺子学不会FPGA

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

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

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

打赏作者

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

抵扣说明:

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

余额充值