64B/66B编码 自定义PHY层设计

news2024/12/24 2:45:28

一、前言

之前的一篇文章讲解了64B/66B的基本原理,本篇在基于64B/66B GT Transceiver的基础之上设计自定义PHY。基本框图如下。

二、GT Mdule

GT Module就按照4个GT CHannel共享一个GT COMMON进行设置,如下图。要将例子工程中的GT COMMON取出,使其控制多个通道。如果按照例子工程的架构,当例化多个通道时,工程会出错,原因就是一个GT QARD只有一个GT COMMON。

GT Channel包括一个时钟模块,通过IP核给出来的TXOUTCLK生成TXUSERCLK2、RXUSERCLK2等时钟。GT IP就是例化的一个64B/66B编码的7系列GT Transceiver/

 例子工程结构如下:

 正确的结构如下:

GT Module主体结构代码如下:

IBUFDS_GTE2 #(
    .CLKCM_CFG      ("TRUE"             ),
    .CLKRCV_TRST    ("TRUE"             ),
    .CLKSWING_CFG   (2'b11              ) 
)
IBUFDS_GTE2_inst (
    .O              (w_gtrefclk         ),
    .ODIV2          (                   ),
    .CEB            (0                  ),
    .I              (i_gtrefclk_p       ),
    .IB             (i_gtrefclk_n       ) 
   );

gtwizard_0_common #
(
    .WRAPPER_SIM_GTRESET_SPEEDUP        ("TRUE"                         ),
    .SIM_QPLLREFCLK_SEL                 (QPLLREFCLKSEL_IN               )
)
common0_i
(
    .QPLLREFCLKSEL_IN                   (QPLLREFCLKSEL_IN               ),
    .GTREFCLK0_IN                       (w_gtrefclk                     ),
    .GTREFCLK1_IN                       (0                              ),
    .QPLLLOCK_OUT                       (w_qplllock                     ),
    .QPLLLOCKDETCLK_IN                  (i_sysclk                       ),
    .QPLLOUTCLK_OUT                     (w_qplloutclk                   ),
    .QPLLOUTREFCLK_OUT                  (w_qplloutrefclk                ),
    .QPLLREFCLKLOST_OUT                 (w_qpllrefclklost               ),    
    .QPLLRESET_IN                       (w_qpllreset|w_common_rst       )

);

gtwizard_0_common_reset # 
(
    .STABLE_CLOCK_PERIOD                (50                             )    
)                       
common_reset_i                      
(                           
    .STABLE_CLOCK                       (i_sysclk                       ),   
    .SOFT_RESET                         (i_tx_rst                       ),   
    .COMMON_RESET                       (w_common_rst                   )    
);

GT_channel GT_channel_u0(
    .i_sysclk                           (i_sysclk                       ),
    .i_gtrefclk                         (w_gtrefclk                     ),
    .i_rx_rst                           (i_rx_rst                       ),
    .i_tx_rst                           (i_tx_rst                       ),
    .o_tx_done                          (o_tx_done                      ),
    .o_rx_done                          (o_rx_done                      ),
    .i_tx_polarity                      (i_tx_polarity                  ),
    .i_tx_diffctrl                      (i_tx_diffctrl                  ),
    .i_txpostcursor                     (i_txpostcursor                 ),
    .i_txpercursor                      (i_txpercursor                  ),     
    .i_rx_polarity                      (i_rx_polarity                  ),
    .i_loopback                         (i_loopback                     ),
    .i_drpaddr                          (i_drpaddr                      ), 
    .i_drpclk                           (i_drpclk                       ),
    .i_drpdi                            (i_drpdi                        ), 
    .o_drpdo                            (o_drpdo                        ), 
    .i_drpen                            (i_drpen                        ),
    .o_drprdy                           (o_drprdy                       ), 
    .i_drpwe                            (i_drpwe                        ),
    .i_qplllock                         (w_qplllock                     ), 
    .i_qpllrefclklost                   (w_qpllrefclklost               ), 
    .o_qpllreset                        (w_qpllreset                    ),
    .i_qplloutclk                       (w_qplloutclk                   ), 
    .i_qplloutrefclk                    (w_qplloutrefclk                ), 
    .i_data_valid                       (i_data_valid                   ),
    .o_rx_clk                           (o_rx_clk                       ),
    .o_rx_data                          (o_rx_data                      ),
    .o_rx_valid                         (o_rx_valid                     ),
    .o_rx_header                        (o_rx_header                    ),
    .o_rx_header_valid                  (o_rx_header_valid              ),
    .i_rx_slipbit                       (i_rx_slipbit                   ),

    .o_tx_clk                           (o_tx_clk                       ),
    .i_tx_data                          (i_tx_data                      ),
    .i_tx_header                        (i_tx_header                    ),
    .i_tx_sequence                      (i_tx_sequence                  ),      

    .o_gt_tx_p                          (o_gt_tx_p                      ),
    .o_gt_tx_n                          (o_gt_tx_n                      ),
    .i_gt_rx_p                          (i_gt_rx_p                      ),
    .i_gt_rx_n                          (i_gt_rx_n                      )
);

GT_channel GT_channel_u1(
    .i_sysclk                           (i_sysclk                       ),
    .i_gtrefclk                         (w_gtrefclk                     ),
    .i_rx_rst                           (i_rx_rst_2                     ),
    .i_tx_rst                           (i_tx_rst_2                     ),
    .o_tx_done                          (o_tx_done_2                    ),
    .o_rx_done                          (o_rx_done_2                    ),
    .i_tx_polarity                      (i_tx_polarity_2                ),
    .i_tx_diffctrl                      (i_tx_diffctrl_2                ),
    .i_txpostcursor                     (i_txpostcursor_2               ),
    .i_txpercursor                      (i_txpercursor_2                ),     
    .i_rx_polarity                      (i_rx_polarity_2                ),
    .i_loopback                         (i_loopback_2                   ),
    .i_drpaddr                          (i_drpaddr_2                    ), 
    .i_drpclk                           (i_drpclk_2                     ),
    .i_drpdi                            (i_drpdi_2                      ), 
    .o_drpdo                            (o_drpdo_2                      ), 
    .i_drpen                            (i_drpen_2                      ),
    .o_drprdy                           (o_drprdy_2                     ), 
    .i_drpwe                            (i_drpwe_2                      ),
    .i_qplllock                         (w_qplllock                     ), 
    .i_qpllrefclklost                   (w_qpllrefclklost               ), 
    .o_qpllreset                        (                               ),
    .i_qplloutclk                       (w_qplloutclk                   ), 
    .i_qplloutrefclk                    (w_qplloutrefclk                ), 
    .i_data_valid                       (i_data_valid_2                 ),
    .o_rx_clk                           (o_rx_clk_2                     ),
    .o_rx_data                          (o_rx_data_2                    ),
    .o_rx_valid                         (o_rx_valid_2                   ),
    .o_rx_header                        (o_rx_header_2                  ),
    .o_rx_header_valid                  (o_rx_header_valid_2            ),
    .i_rx_slipbit                       (i_rx_slipbit_2                 ),
                
    .o_tx_clk                           (o_tx_clk_2                     ),
    .i_tx_data                          (i_tx_data_2                    ),
    .i_tx_header                        (i_tx_header_2                  ),
    .i_tx_sequence                      (i_tx_sequence_2                ),      
                
    .o_gt_tx_p                          (o_gt_tx_p_2                    ),
    .o_gt_tx_n                          (o_gt_tx_n_2                    ),
    .i_gt_rx_p                          (i_gt_rx_p_2                    ),
    .i_gt_rx_n                          (i_gt_rx_n_2                    )
);

三、PHY TX模块

PHY TX模块的主要功能就是封装帧以及大小端转换,以及暂停控制。

  • 由于64B/66B编码判定传输开始和传输结束是通过不同的数据帧进行的,所以就要对发送的数据进行封帧处理。
  • 在此过程中需要注意将数据由大端模式转换为小端的数据(GT IP核使用的是小端数据)。
  • 暂停控制:UG476上指出在使用外部计数器时,当Sequence Counter计数到32时,需要暂停以下,使Gearbox中积累的数据吐出去。

接下来具体说明变速箱GearBox的实现过程,以10GBase-R的物理层为例,若Serdes的位宽要求为32bit,PCS层采用64B/66B的编解码方式,在与Serdes进行数据传输过程中,需要GearBox实现66bit到32bit的转换、32bit到66bit的转换。

继续以上图为例子,XGMII层每拍输出32bit数据,每2拍组合成64bit报文,并且需要编码出2bit的同步头,为了简单化,假设待匹配的Serdes只有1个lane,且位宽为32bit,即GearBox输出是每拍32bit。

显然,输入带宽是大于输出带宽,属于带宽膨胀,因此输入必须暂停,什么时候停呢,见下图波形所示,每32拍停一拍,即待发送的buffer数据积攒够了32bit,此时,产生暂停输入标志位,也就是“反压”住输入信号,让GearBox可以完成数据完整输出。

(引自:详解GearBox设计原理 (qq.com))

基本思想如下:也就是要让Sequence Counter等于32和0的时候输出的数据不变,因为发送数据过程采用的时流水线拼接处理,所以要在Sequence Counter即将等于32的时候去截断数据流(处理过程挺复杂的)。

这个逻辑通过信号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 =0的时刻到来,这时候需要特殊处理,因为再组帧的过程中第一帧是需要特殊处理的,如果处理不过会影响到后面的处理过程,时序图可以自己画以下。当检测w_gt_send_valid =0时需要使得读FIFO使能无效一个时钟周期(截流),并使得send_cnt在此时刻的数据保持两个时钟周期,需要使得输出保持。

总之最基本的思想就是:也就是要让Sequence Counter等于32和0的时候输出的数据不变

仿真图如下:

主要代码如下:

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        ro_tx_sequence <= 'd0;
    else if(ro_tx_sequence == 32)
        ro_tx_sequence <= 'd0;
    else 
        ro_tx_sequence <= ro_tx_sequence + 1;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_input_end <= 'd0;
    else if(s_axis_last)
        r_input_end <= 'd1;
    else if(s_axis_valid)
        r_input_end <= 'd0;
    else 
        r_input_end <= r_input_end;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_send_cnt <= 'd0;
    else if(r_input_end && r_send_cnt == r_len - 0)
        r_send_cnt <= 'd0;
    else if(r_invalid && r_send_cnt)
        r_send_cnt <= r_send_cnt;
    else if(r_invalid && r_fifo_rden_2d && !r_fifo_rden_3d)
        r_send_cnt <= r_send_cnt + 1;
    else if((!r_invalid && r_fifo_rden_1d && !r_fifo_rden_2d) || (r_send_cnt&& w_gt_send_valid))
        r_send_cnt <= r_send_cnt + 1;
    else 
        r_send_cnt <= r_send_cnt;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_dout_little <= 'd0;
    else if(r_fifo_rden)
        r_fifo_dout_little <= w_fifo_dout_little;
    else 
        r_fifo_dout_little <= r_fifo_dout_little;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_axis_keep <= 'd0;
    else if(s_axis_last)
        r_axis_keep <= s_axis_keep;
    else 
        r_axis_keep <= r_axis_keep;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        ro_tx_data <= 'd0;
    else if(r_send_cnt && r_input_end && ((r_axis_keep > 8'b1111_1100 && r_send_cnt == r_len - 0) 
            || (r_axis_keep <= 8'b1111_1100 && r_send_cnt == r_len - 1)))
        case(r_axis_keep)
            8'b1111_1111:ro_tx_data <= {7'h16,7'h16,7'h16,7'h16,7'h16,7'h16,6'd0,r_fifo_dout_little[63:56],8'h99};//灏剧鍙戦��1涓�
            8'b1111_1110:ro_tx_data <= {7'h16,7'h16,7'h16,7'h16,7'h16,7'h16,7'h16,7'h16,8'h8e};//灏剧鍙戦��8涓�
            8'b1111_1100:ro_tx_data <= {w_fifo_dout_little[47:0],r_fifo_dout_little[63:56],8'hFF};//灏剧鍙戦��7涓�
            8'b1111_1000:ro_tx_data <= {7'h16,1'd0,w_fifo_dout_little[39:0],r_fifo_dout_little[63:56],8'he8};//灏剧鍙戦��6涓�
            8'b1111_0000:ro_tx_data <= {7'h16,7'h16,2'd0,w_fifo_dout_little[31:0],r_fifo_dout_little[63:56],8'hD4};
            8'b1110_0000:ro_tx_data <= {7'h16,7'h16,7'h16,3'd0,w_fifo_dout_little[23:0],r_fifo_dout_little[63:56],8'hc3};
            8'b1100_0000:ro_tx_data <= {7'h16,7'h16,7'h16,7'h16,4'd0,w_fifo_dout_little[15:0],r_fifo_dout_little[63:56],8'hB2};
            8'b1000_0000:ro_tx_data <= {7'h16,7'h16,7'h16,7'h16,7'h16,5'd0,w_fifo_dout_little[7:0],r_fifo_dout_little[63:56],8'hA5};
        endcase
    else case(r_send_cnt)
        0       :ro_tx_data <= {w_fifo_dout_little[55:0],8'h71};
        default :ro_tx_data <= {w_fifo_dout_little[55:0],r_fifo_dout_little[63:56]};
    endcase
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        ro_tx_header <= 'd0;
    else if(r_send_cnt && r_input_end && ((r_axis_keep > 8'b1111_1100 && r_send_cnt == r_len - 0) 
            || (r_axis_keep <= 8'b1111_1100 && r_send_cnt == r_len - 1)))
        ro_tx_header <= 2'b10;
        
    else if(r_send_cnt == 0 && r_fifo_rden_2d && r_invalid)
        ro_tx_header <= 2'b10;
    else if(r_send_cnt == 0 && r_fifo_rden_1d)
        ro_tx_header <= 2'b10;
    else
        ro_tx_header <= 2'b01;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_rden <= 'd0;
    else if(w_fifo_empty || !w_gt_send_valid)   
        r_fifo_rden <= 'd0;
    else if(!w_fifo_empty)
        r_fifo_rden <= 'd1;
    else 
        r_fifo_rden <= r_fifo_rden;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_rden_1d <= 'd0;
    else 
        r_fifo_rden_1d <= r_fifo_rden;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_rden_2d <= 'd0;
    else 
        r_fifo_rden_2d <= r_fifo_rden_1d;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_rden_3d <= 'd0;
    else 
        r_fifo_rden_3d <= r_fifo_rden_2d;
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_fifo_empty <= 'd0;
    else 
        r_fifo_empty <= {r_fifo_empty[0],w_fifo_empty};
end

always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        rs_axis_ready <= 'd1;
    else if(s_axis_last)
        rs_axis_ready <= 'd0;
    else if(r_input_end && r_send_cnt == r_len - 0)
        rs_axis_ready <= 'd1;
    else 
        rs_axis_ready <= rs_axis_ready;
end


always@(posedge i_tx_clk,posedge i_tx_rst)
begin
    if(i_tx_rst)
        r_invalid <= 'd0;
    else if(r_invalid && r_send_cnt)
        r_invalid <= 'd0;
    else if(r_fifo_rden && !w_gt_send_valid && r_send_cnt == 0)
        r_invalid <= 'd1;
    else 
        r_invalid <= r_invalid;
end

四、PHY RX

1、PHY RX Bitslip模块

该模块的主要作用是实现字节对齐功能。

这个模块的主要思想如下:

  • 在64B/66B编码当中,只有2‘b10和2’b01代表有效的数据头,因此在字节对齐的过程中一直检测输入进来的数据头是否有效。
  • 当检测到错误数据头时,通过计数器进行计数加一进行记录,当间隔一定时钟周期之后便会检测这些计数器,如果计数器不为0,则发送滑动信号,使对齐窗口滑动1个bit。
  • 注意,间隔周期一定要大于32RXUSERCLK2(Xilinx文档 UG476指定的最小间隔周期为32个RXUSERCLK2)
  • 为了防止误判,可以设置只有当连续检测到64(如果出现误判可以再次翻倍)个正确的数据头部时,才会判定数据头已经对齐。
  • 在Xilinx 例子工程的Block_syn模块中,在对其之后也会一直检测是否有错误的数据头,并对计数器进行复位,而本模块没有对计数器进行复位。

本模块字节对齐过程:

可以看到当字节对齐之后,无效头计数器的数值应该都为0,只有有效数据头计数器在一直增加。

挡在同步过程中检测到一个无效的数据头(黄色数据线的地方)便会重新启动字节同步

例子工程的块对齐模块:

可以看到在对其之后,begin信号会一直对计数器进行复位。

2、PHY RX模块

PHY RX模块的主要功能就是解帧以及大小端转换、字节对齐。

  • 由于64B/66B编码判定传输开始和传输结束是通过不同的数据帧进行的,所以就要对接收到的数据帧进行解帧
  • 在此过程中需要注意将GT IP传输过来的阿小端的数据转换为我们经常使用的大端的接口数据。
  • 字节对齐,也就是在解帧的过程中要去除控制字符,并将接口的形式转换为AXI-Streaming接口的形式。在这里要特别注意EOF帧的在转换过程中Keep信号的处理。

在接收数据的时候需要注意,每隔32个时钟周期就有一个无效的数据发送过来,在设计的过程中需要考虑垓情况。尤其在刚接收到SOF帧后紧接着后面的无效数据,这种情况,要单独讨论,接收端的r_invalid便是用来处理此种情况。(这个需要后期在仔细思考)。

主要代码:

assign w_sof         = ri_rx_header_valid & ri_rx_header == 2'b10 & ri_rx_data[7 :0] == 8'h71 & ri_rx_valid;
assign w_eof         = ri_rx_header_valid & ri_rx_header == 2'b10 & 
                       (ri_rx_data[7 :0] == 8'h99 ||
                        ri_rx_data[7 :0] == 8'h8e ||
                        ri_rx_data[7 :0] == 8'hff ||
                        ri_rx_data[7 :0] == 8'he8 ||
                        ri_rx_data[7 :0] == 8'hd4 ||
                        ri_rx_data[7 :0] == 8'hc3 ||
                        ri_rx_data[7 :0] == 8'hb2 ||
                        ri_rx_data[7 :0] == 8'ha5 
                       ) 
                       & ri_rx_valid;
assign w_eof_s1     = i_rx_header_valid & i_rx_header == 2'b10 & 
                       (i_rx_data[7 :0] == 8'h99 ||
                        i_rx_data[7 :0] == 8'h8e ||
                        i_rx_data[7 :0] == 8'hff ||
                        i_rx_data[7 :0] == 8'he8 ||
                        i_rx_data[7 :0] == 8'hd4 ||
                        i_rx_data[7 :0] == 8'hc3 ||
                        i_rx_data[7 :0] == 8'hb2 ||
                        i_rx_data[7 :0] == 8'ha5 
                       ) 
                       & i_rx_valid;
assign w_eof_local = ri_rx_data[7 :0] == 8'h99 ? 1 : 
                     ri_rx_data[7 :0] == 8'h8e ? 8 :
                     ri_rx_data[7 :0] == 8'hff ? 7 :
                     ri_rx_data[7 :0] == 8'he8 ? 6 :
                     ri_rx_data[7 :0] == 8'hd4 ? 5 :
                     ri_rx_data[7 :0] == 8'hc3 ? 4 :
                     ri_rx_data[7 :0] == 8'hb2 ? 3 :
                     ri_rx_data[7 :0] == 8'ha5 ? 2 :
                     'd0;
assign w_eof_local_s1 = i_rx_data[7 :0] == 8'h99 ? 1 : 
                        i_rx_data[7 :0] == 8'h8e ? 8 :
                        i_rx_data[7 :0] == 8'hff ? 7 :
                        i_rx_data[7 :0] == 8'he8 ? 6 :
                        i_rx_data[7 :0] == 8'hd4 ? 5 :
                        i_rx_data[7 :0] == 8'hc3 ? 4 :
                        i_rx_data[7 :0] == 8'hb2 ? 3 :
                        i_rx_data[7 :0] == 8'ha5 ? 2 :
                     'd0;
always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst) begin
        ri_rx_data          <= 'd0;
        ri_rx_valid         <= 'd0;
        ri_rx_valid_1d      <= 'd0;
        ri_rx_header        <= 'd0;
        ri_rx_header_valid  <= 'd0;
        
    end else begin
        ri_rx_data          <= i_rx_data            ;
        ri_rx_valid         <= i_rx_valid           ;
        ri_rx_valid_1d      <= ri_rx_valid          ;
        ri_rx_header        <= i_rx_header          ;
        ri_rx_header_valid  <= i_rx_header_valid    ;
        
    end 
end

always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        ri_rx_data_1d       <= 'd0;
    else if(ri_rx_valid)
        ri_rx_data_1d       <= ri_rx_data           ;
    else 
        ri_rx_data_1d       <= ri_rx_data_1d        ;
end
always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst) begin
        r_sof <= 'd0;
        r_eof <= 'd0;
        r_eof_local <= 'd0;
    end else begin
        r_sof <= w_sof;
        r_eof <= w_eof;
        r_eof_local <= w_eof_local;
    end
end

always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        r_receiving <= 'd0;
    else if(r_eof)
        r_receiving <= 'd0;
    else if(w_sof)
        r_receiving <= 'd1;
    else 
        r_receiving <= r_receiving;
end

// always@(posedge i_rx_clk,posedge i_rx_rst)
// begin
//     if(i_rx_rst)
//         rm_axis_data <= 'd0;
//     else if(r_receiving)
//         s
//     else 
//         rm_axis_data <= rm_axis_data;
// end

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 < 8)
        rm_axis_data <= {ri_rx_data_1d[63:16]};
    else if(w_eof && w_eof_local < 8)
        rm_axis_data <= {ri_rx_data[15:8],ri_rx_data_1d[63:8]};
    else if(w_eof && (w_eof_local == 8 || w_eof_local == 1))
        rm_axis_data <= {ri_rx_data[7 :0],ri_rx_data_1d[63:8]};
    else if(r_receiving && ri_rx_valid)
        rm_axis_data <= {ri_rx_data[7 :0],ri_rx_data_1d[63:8]};
    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 >1 && r_eof_local < 8))
        case(r_eof_local)
            1           :rm_axis_keep <= 8'b1111_1111;
            2           :rm_axis_keep <= 8'b1000_0000;
            3           :rm_axis_keep <= 8'b1100_0000;
            4           :rm_axis_keep <= 8'b1110_0000;
            5           :rm_axis_keep <= 8'b1111_0000;
            6           :rm_axis_keep <= 8'b1111_1000;
            7           :rm_axis_keep <= 8'b1111_1100;
            8           :rm_axis_keep <= 8'b1111_1110;
            default     :rm_axis_keep <= 8'b1111_1111;
        endcase
    else if(w_eof && (w_eof_local == 8 || w_eof_local == 1))
        case(w_eof_local)
            1           :rm_axis_keep <= 8'b1111_1111;
            2           :rm_axis_keep <= 8'b1000_0000;
            3           :rm_axis_keep <= 8'b1100_0000;
            4           :rm_axis_keep <= 8'b1110_0000;
            5           :rm_axis_keep <= 8'b1111_0000;
            6           :rm_axis_keep <= 8'b1111_1000;
            7           :rm_axis_keep <= 8'b1111_1100;
            8           :rm_axis_keep <= 8'b1111_1110;
            default     :rm_axis_keep <= 8'b1111_1111;
        endcase
    // else if(w_eof_s1 && w_eof_local_s1 == 8)   
    //         rm_axis_keep <= 8'b1111_1111;
    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 >1 && r_eof_local < 8))
        rm_axis_last <= 'd1;
    else if(rm_axis_valid && w_eof && (w_eof_local == 8 || w_eof_local == 1))
        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

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

always@(posedge i_rx_clk,posedge i_rx_rst)
begin
    if(i_rx_rst)
        r_invalid <= 'd0;
    else if(r_sof & !ri_rx_valid)
        r_invalid <= 'd1;
    else 
        r_invalid <= 'd0;
end

 五、上板测试

上板测试如下,GT 放置两个通道,两个通道之间互相发送和接收数据。

六、总结 

商用的PHY芯片肯定比这些要复杂的多,我们在这边只要了解64B/66B编码的原因,以及PHY的原理和处理过程、思想就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1607866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10 鼠标箭头自己乱动解决方案

我这里只说我碰到的然后我的解决方案&#xff0c;不一定对其他问题有效&#xff1b; 1. 首先拔掉鼠标线查看鼠标箭头是否仍然在乱动&#xff0c;如果是则非鼠标问题&#xff0c;如果不再乱动则是鼠标的问题&#xff1b;验证非鼠标问题&#xff1b; 2. 因为鼠标乱动跟鼠标无关…

Transformer杀疯了!王炸成果荣登Nature,实现无限上下文长度

继DeepMind的新设计MoD大幅提升了 Transformer 效率后&#xff0c;谷歌又双叒开始爆改了&#xff01; 与之前荣登Nature子刊的life2vec不同&#xff0c;谷歌的新成果Infini-attention机制&#xff08;无限注意力&#xff09;将压缩内存引入到传统的注意机制中&#xff0c;并在…

python--4函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、递归练习

学习目标&#xff1a; 函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、 递归练习 学习内容&#xff1a; 函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、 递归练习 …

CSS中position属性总结

CSS中position属性的总结 如果我的文章看不懂&#xff0c;不要犹豫&#xff0c;请直接看阮一峰大佬写的文章 https://www.ruanyifeng.com/blog/2019/11/css-position.html 1 干嘛用的 用来定位HTML元素位置的&#xff0c;通过top、bottom、right、left定位元素 分别有这些值&a…

3D模型格式转换工具HOOPS Exchange:3D CAD数据的快速导入与导出

在当今的工程设计领域中&#xff0c;快速且可靠地处理3D CAD数据是至关重要的。HOOPS Exchange SDK通过提供一组C软件库&#xff0c;为开发团队提供了实现这一目标的有效工具。 什么是HOOPS Exchange&#xff1f; HOOPS Exchange是一组C软件库&#xff0c;旨在为开发团队提供…

DNS服务器的管理与配置

目录 一、相关知识 域名空间 DNS服务器分类 域名解析过程 资源记录 二、安装DNS服务 安装bind软件包 DNS服务的启动与停止 配置主要名称服务器 主配置文件 从例子学起&#xff1a; &#xff08;1&#xff09;建立主配置文件named.conf &#xff08;2&#xff09;…

OpenHarmony网络协议通信c-ares [交叉编译]异步解析器库

简介 c-ares是异步解析器库&#xff0c;适用于需要无阻塞地执行 DNS 查询或需要并行执行多个 DNS 查询的应用程序。 下载安装 直接在OpenHarmony-SIG仓中搜索c-ares并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的c-ares库代码存在以下路径&#xff1a;…

上位机图像处理和嵌入式模块部署(树莓派4b实现固件主流程)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 软件开发一般有软件需求、架构设计和详细设计、软件测试这四个部分。软件需求和软件测试都比较好理解&#xff0c;前者是说要实现哪些功能&#xf…

【SpringBoot+VUE+ELEMENT 】前后端分离的管理系统的实现——基础功能(记录向)

一个前后端分离的实现。后端使用SpringBoot&#xff0c;前端使用Vue&#xff0c;后端标准的四层结构&#xff0c;前端是用的Element。 一、环境准备 1.安装node.js Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 成功后cmd中运行 node -v npm -v 出现 对应的版本…

活动 | 华院计算与数学家一起走进世界轨道交通之都-中国株洲

4月17日&#xff0c;由株洲市人民政府主办、株洲高新区管委会承办&#xff0c;华院计算技术&#xff08;上海&#xff09;股份有限公司&#xff08;以下简称“华院计算”&#xff09;协办的“制造名城、院士同行&#xff0c;数学家走进株洲”活动在湖南株洲举行。 来自中国数学…

匿名函数与gorm中的Transaction事务方法

整理下go中的匿名函数&#xff0c;项目中很多地方都在用。 1、函数类型的变量 Go中&#xff0c;函数也是一种数据类型。定义一个函数&#xff0c;把这个函数赋值给一个变量&#xff0c;这个变量就是函数类型的变量&#xff0c;用这个变量等价于直接调函数&#xff1a; packa…

算法刷题记录2

4.图 4.1.被围绕的区域 思路&#xff1a;图中只有与边界上联通的O才不算是被X包围。因此本题就是从边界上的O开始递归&#xff0c;找与边界O联通的O&#xff0c;并标记为#&#xff08;代表已遍历&#xff09;&#xff0c;最后图中剩下的O就是&#xff1a;被X包围的O。图中所有…

使用LVGL提升交互效率:基于启明智显Model3A方案的7寸智能屏用户界面(UI)设计介绍

项目概述&#xff1a; 【启明智显】&#xff0c;作为一家专注于HMI和AIoT解决方案的公司&#xff0c;我们致力于为用户提供创新、可靠且高效的产品和解决方案。近日我们推出了高性能及高性价比的HMI芯片——Model3A。芯片搭载了强大的2D图形加速引擎&#xff0c;能够提供高达7…

RNN知识体系构筑:详尽阐述其理论基础、技术架构及其在处理序列数据挑战中的创新应用

一、为什么需要RNN 尽管神经网络被视为一种强大且理论上能够近似任何连续函数的模型&#xff0c;尤其当训练数据充足时&#xff0c;它们能够在输入空间中的某个点( x )映射到输出空间的特定值( y )&#xff0c;然而&#xff0c;这并不能完全解释为何在众多应用场景中&#xff…

基于Spring Boot的新生宿舍管理系统设计与开发

基于Spring Boot的新生宿舍管理系统设计与开发 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 报修处理管理界面图&#xff0c;在报修处理管理页面…

QA测试开发工程师面试题满分问答16: 微信输入框如何设计测试用例?

可以涵盖基础功能、用户交互、编辑撤回、权限相关、网络信号、异常、并发性能和安全性等方面的测试用例&#xff1a; 基础功能&#xff1a; 验证输入框是否能够接收用户输入&#xff0c;并显示输入的文字。检查输入框是否支持常见的字符输入&#xff0c;如字母、数字、标点符号…

Unity Shader 流光 边缘光

前言 Unity2021.3.23 一、实现原理 Time控制UV的变化,再采样一张流光贴图.即可实现流光效果。 二、效果及源码展示 1.流光效果 效果描述: 1.边缘光(菲尼尔), 2.从上到下扫描光. 效果图如下: 代码如下&#xff1a; Shader "Unlit/ScanCode" {Properties{_MainTe…

【数据结构】树与二叉树、树与森林部分习题与算法设计例题

目录 【数据结构】树与二叉树部分习题与算法设计例题一、单选题二、算法设计题判断二叉树是否为完全二叉树求二叉树的最小深度 以及 二叉树树高 树与二叉树知识点文章: 【数据结构】树与二叉树&#xff08;递归法先序、中序、后序、层次遍历二叉树、二叉树的建立以及求树高的方…

必看——通配符SSL证书在线免费申请方法!

申请通配符SSL证书&#xff0c;就相当于给你的网站及所有子域名都戴上同一顶加密“帽子”&#xff0c;保护它们的安全通信。以下是三步搞定的方法&#xff1a; 第一步&#xff1a;找权威机构 就像你要找个官方认证的地方办证明一样&#xff0c;先选一家靠谱的证书颁发机构&…

软考中级网络工程师-2024上岸宝典

1.软考是什么 简单说就是计算机技术 相关的国家级证书考试&#xff0c;想听专业点给大家截一张官网的图&#xff0c;不想听废话直接往下。 同为国家级证书的&#xff1a;注册会计师、法律职业资格证、一级建筑师&#xff0c;证书的价值是比较高的。 很多人都是在求职前或者大…