GT IP核仿真测试


1. 前言

由于关于GT IP的相关博客太多了,所以我就以我自己的仿真调试经验取讲解下GT IP的使用方法。一开始我接触GT的时钟,第一眼望去,打开IP,有几页的配置,特别多的参数勾选,头都要晕掉了,因此我也是先找了一些技术文章先了解了下GT的大致原理以及流程,对GT有了基本的了解后再去配置使用,就轻松多了。不要怕,一开始的路都是崎岖艰辛的,只要坚持学习消化,终会迎来胜利的曙光,加油!好了,废话完毕,我们开始吧!

2. 概述

首先在vivado中,我们打开IP Catalog,在搜索框中搜索GT,就会弹出GT的IP核,可以看到有两个IP,一个叫IBERT 7 Series GTX,一个叫7 Series FPGAs Transceivers Wizard。第一个是眼图,是用来测试误码率以及GTX的硬件链路的。第二个是我们要用的GTx IP核,用来传输传输高速信号的,K7系列芯片的最大线速率可以达到10.3125Gbps。

3. IP核配置

第一页

在这里插入图片描述

因为我的FPGA型号是XC7K325T,所以使用的是GTX。我们要使用官方例程example design,所以勾选Include Shared Logic in example design。

第二页

在这里插入图片描述

  • Protocol:Start from scratch,意思是不使用协议;它支持各种的协议包括SDI/10Gbase/Aurora/PCIE/HDMI/204B/,很多我就不一一列举了,由于我们这里不使用协议,因此默认就行;
  • line Rate:线速率,默认是3.125Gbps;
  • Reference Clock(MHz):156.250MHz,这个是根据你原理图上的时钟来配置的,一般GT的参考时钟为156.250,跟原理图对应;
  • PLL Selection:CPLL。线速率大于6Gbps时必须选择QPLL,我这里选择的是CPLL;
  • Transceiverr Selection:
  • Use GTX X0Y0:勾选,这也是跟你的原理图对应,参考其他博客可以在Implement中查看你的GT bank
  • TX Clock Source:跟你的原理图对应,看你接的是参考时钟0还是参考时钟1
  • RX Clock Source:跟你的原理图对应,看你接的是参考时钟0还是参考时钟1,TX选择后RX自动改变,无需配置;
  • Advanced Clocking Option:默认,没用过;
  • PRBS pattern generator and checker:默认,没用过
  • Vivado Lab Tools:默认不勾选,没用过

第三页

在这里插入图片描述
参数太多了,说下主要配置的部分吧,也就是TX和RX

  1. TX
    External Data width(bits):外部数据宽度,可配置,我配的20bit,这个看个人的;
    Encoding:编码方式,可选择8B/10B,我选择的NONE
    Internal Data with(bits);内部数据宽度,也就是IP核内部的数据宽度
  2. RX
    External Data width(bits):外部数据宽度,可配置,我配的20bit,这个看个人的;
    Encoding:编码方式,可选择8B/10B,我选择的NONE
    Internal Data with(bits);内部数据宽度,也就是IP核内部的数据宽度
  3. Synchronization and Clocking
    勾选Enable TX buffer和Enable RX buffer,勾选后代表增加了一个FIFO去缓存发送的数据,不知道我这样理解对不对,勾选就对了。
  4. Optional Ports
    这些应该就是高级配置了,小白刚开始接触GT时不需要关注,默认即可。

第四页

在这里插入图片描述
这一页配置是逗号对齐检测和K码的设置,K码是28.5,勾选Use comma detection,表示使用逗号检测
Align to:选择Any Byte Boundary或者两字节,我选择两字节;
其他参数默认即可,想了解更多的就去啃手册或者其他技术博客,我暂时还没深入到这里;

第五页

在这里插入图片描述
默认即可,我没使用PCIe协议。

第六页

在这里插入图片描述
默认即可,这页应该是时钟校准配置,我还是默默看手册去吧,不懂。

第七页

总结页,总结了前面的配置信息,可以看看跟自己配置的是否一致。在这里插入图片描述
配置完IP核后生成IP核,如图所示。
在这里插入图片描述
生成完IP核后,右击生成的IP
在这里插入图片描述
点击Open IP Example Design,然后会自动创建一个工程,工程的代码框架如下:
在这里插入图片描述
别看代码文件很多,核心的代码就三部分,gtwizard_exdes.v,gtwizard_0_support,gtwizard_0_GT_FRAME_GEN.v,gtwizard_0_GT_FRAME_CHECK.v。
接下来分析下代码

4. 代码框架分析

4.1 gtwizard_exdes.v

这是顶层模块,例化了其他三个模块,顶层接口其实很少,就一对差分信号TX、差分信号RX、GT差分参考时钟、动态重配置DRP差分时钟、TRACK_DATA_OUT,这是个检测信号。
配置参考就关注下EXAMPLE_SIM_GTRESET_SPEEDUP这个值,它是用于配置仿真和综合实现的参数,我们功能仿真的时候就改成TRUE

module gtwizard_0_exdes #
(
    parameter EXAMPLE_CONFIG_INDEPENDENT_LANES     =   1,//configuration for frame gen and check
    parameter EXAMPLE_LANE_WITH_START_CHAR         =   0,         // specifies lane with unique start frame char
    parameter EXAMPLE_WORDS_IN_BRAM                =   512,       // specifies amount of data in BRAM
    parameter EXAMPLE_SIM_GTRESET_SPEEDUP          =   "TRUE",    // simulation setting for GT SecureIP model
    parameter EXAMPLE_USE_CHIPSCOPE                =   0,         // Set to 1 to use Chipscope to drive resets
    parameter STABLE_CLOCK_PERIOD                  = 10

)
(
    input wire  Q0_CLK1_GTREFCLK_PAD_N_IN,
    input wire  Q0_CLK1_GTREFCLK_PAD_P_IN,
    input wire  DRP_CLK_IN_P,
    input wire  DRP_CLK_IN_N,
    output wire TRACK_DATA_OUT,
    input  wire         RXN_IN,
    input  wire         RXP_IN,
    output wire         TXN_OUT,
    output wire         TXP_OUT
);

接着例化了三个子模块。

  1. support是GT的核心代码,它例化了GTX IP核,一般无需修改。
  2. frame_gen是我们需要发送的数据,在实际应用中,换成自己数据输入源就可以了;
  3. frame_check是用来检测接收的数据和发送的数据是否一致,可以不用或者换成你自己的检测逻辑代码也可以;
gtwizard_0_support #
    (
        .EXAMPLE_SIM_GTRESET_SPEEDUP    (EXAMPLE_SIM_GTRESET_SPEEDUP),
        .STABLE_CLOCK_PERIOD            (STABLE_CLOCK_PERIOD)
    )
    gtwizard_0_support_i
    (
        .soft_reset_tx_in               (soft_reset_i),
        .soft_reset_rx_in               (soft_reset_i),
        .dont_reset_on_data_error_in    (tied_to_ground_i),
    .q0_clk1_gtrefclk_pad_n_in(Q0_CLK1_GTREFCLK_PAD_N_IN),
    .q0_clk1_gtrefclk_pad_p_in(Q0_CLK1_GTREFCLK_PAD_P_IN),
        .gt0_tx_fsm_reset_done_out      (gt0_txfsmresetdone_i),
        .gt0_rx_fsm_reset_done_out      (gt0_rxfsmresetdone_i),
        .gt0_data_valid_in              (gt0_track_data_i),
 
    .gt0_txusrclk_out(gt0_txusrclk_i),
    .gt0_txusrclk2_out(gt0_txusrclk2_i),
    .gt0_rxusrclk_out(gt0_rxusrclk_i),
    .gt0_rxusrclk2_out(gt0_rxusrclk2_i),


        //_____________________________________________________________________
        //_____________________________________________________________________
        //GT0  (X1Y0)

        //------------------------------- CPLL Ports -------------------------------
        .gt0_cpllfbclklost_out          (gt0_cpllfbclklost_i),
        .gt0_cplllock_out               (gt0_cplllock_i),
        .gt0_cpllreset_in               (tied_to_ground_i),
        //-------------------------- Channel - DRP Ports  --------------------------
        .gt0_drpaddr_in                 (gt0_drpaddr_i),
        .gt0_drpdi_in                   (gt0_drpdi_i),
        .gt0_drpdo_out                  (gt0_drpdo_i),
        .gt0_drpen_in                   (gt0_drpen_i),
        .gt0_drprdy_out                 (gt0_drprdy_i),
        .gt0_drpwe_in                   (gt0_drpwe_i),
        //------------------------- Digital Monitor Ports --------------------------
        .gt0_dmonitorout_out            (gt0_dmonitorout_i),
        //------------------- RX Initialization and Reset Ports --------------------
        .gt0_eyescanreset_in            (tied_to_ground_i),
        .gt0_rxuserrdy_in               (tied_to_vcc_i),
        //------------------------ RX Margin Analysis Ports ------------------------
        .gt0_eyescandataerror_out       (gt0_eyescandataerror_i),
        .gt0_eyescantrigger_in          (tied_to_ground_i),
        //---------------- Receive Ports - FPGA RX interface Ports -----------------
        .gt0_rxdata_out                 (gt0_rxdata_i),
        //---------------- Receive Ports - RX 8B/10B Decoder Ports -----------------
        .gt0_rxdisperr_out              (gt0_rxdisperr_i),
        .gt0_rxnotintable_out           (gt0_rxnotintable_i),
        //------------------------- Receive Ports - RX AFE -------------------------
        .gt0_gtxrxp_in                  (RXP_IN),
        //---------------------- Receive Ports - RX AFE Ports ----------------------
        .gt0_gtxrxn_in                  (RXN_IN),
        //------------------- Receive Ports - RX Equalizer Ports -------------------
        .gt0_rxdfelpmreset_in           (tied_to_ground_i),
        .gt0_rxmonitorout_out           (gt0_rxmonitorout_i),
        .gt0_rxmonitorsel_in            (2'b00),
        //------------- Receive Ports - RX Fabric Output Control Ports -------------
        .gt0_rxoutclkfabric_out         (gt0_rxoutclkfabric_i),
        //----------- Receive Ports - RX Initialization and Reset Ports ------------
        .gt0_gtrxreset_in               (tied_to_ground_i),
        .gt0_rxpmareset_in              (gt0_rxpmareset_i),
        //-------------------- Receive Ports - RX gearbox ports --------------------
        .gt0_rxslide_in                 (gt0_rxslide_i),
        //----------------- Receive Ports - RX8B/10B Decoder Ports -----------------
        .gt0_rxcharisk_out              (gt0_rxcharisk_i),
        //------------ Receive Ports -RX Initialization and Reset Ports ------------
        .gt0_rxresetdone_out            (gt0_rxresetdone_i),
        //------------------- TX Initialization and Reset Ports --------------------
        .gt0_gttxreset_in               (tied_to_ground_i),
        .gt0_txuserrdy_in               (tied_to_vcc_i),
        //---------------- Transmit Ports - TX Data Path interface -----------------
        .gt0_txdata_in                  (gt0_txdata_i),
        //-------------- Transmit Ports - TX Driver and OOB signaling --------------
        .gt0_gtxtxn_out                 (TXN_OUT),
        .gt0_gtxtxp_out                 (TXP_OUT),
        //--------- Transmit Ports - TX Fabric Clock Output Control Ports ----------
        .gt0_txoutclkfabric_out         (gt0_txoutclkfabric_i),
        .gt0_txoutclkpcs_out            (gt0_txoutclkpcs_i),
        //------------------- Transmit Ports - TX Gearbox Ports --------------------
        .gt0_txcharisk_in               (gt0_txcharisk_i),
        //----------- Transmit Ports - TX Initialization and Reset Ports -----------
        .gt0_txresetdone_out            (gt0_txresetdone_i),


    //____________________________COMMON PORTS________________________________
    .gt0_qplloutclk_out(),
    .gt0_qplloutrefclk_out(),
    .sysclk_in(drpclk_in_i)
    );
gtwizard_0_GT_FRAME_GEN #
    (
        .WORDS_IN_BRAM(EXAMPLE_WORDS_IN_BRAM)
    )
    gt0_frame_gen
    (
        // User Interface
        .TX_DATA_OUT                    ({gt0_txdata_float_i,gt0_txdata_i,gt0_txdata_float16_i}),
        .TXCTRL_OUT                     ({gt0_txcharisk_float_i,gt0_txcharisk_i}),

        // System Interface
        .USER_CLK                        (gt0_txusrclk2_i),
        .SYSTEM_RESET                   (gt0_tx_system_reset_c)
    );
gtwizard_0_GT_FRAME_CHECK #
    (
.RX_DATA_WIDTH ( 16 ),
.RXCTRL_WIDTH ( 2 ),
.COMMA_DOUBLE ( 16'h02bc ),
        .WORDS_IN_BRAM(EXAMPLE_WORDS_IN_BRAM),
.START_OF_PACKET_CHAR ( 16'h02bc )
    )
    gt0_frame_check
    (
        // GT Interface
        .RX_DATA_IN                     (gt0_rxdata_i),
        .RXCTRL_IN                      (gt0_rxcharisk_i),
        .RXENMCOMMADET_OUT              ( ),
        .RXENPCOMMADET_OUT              ( ),
        .RX_ENCHAN_SYNC_OUT             ( ),
        .RX_CHANBOND_SEQ_IN             (tied_to_ground_i),
        // Control Interface
        .INC_IN                         (gt0_inc_in_i),
        .INC_OUT                        (gt0_inc_out_i),
        .PATTERN_MATCHB_OUT             (gt0_matchn_i),
        .RESET_ON_ERROR_IN              (gt0_frame_check_reset_i),
        // System Interface
        .USER_CLK                       (gt0_rxusrclk2_i),
        .SYSTEM_RESET                   (gt0_rx_system_reset_c),
        .ERROR_COUNT_OUT                (gt0_error_count_i),
        .RX_SLIDE                       (gt0_rxslide_i),
        .TRACK_DATA_OUT                 (gt0_track_data_i)
    );


4.2 gtwizard_0_GT_FRAME_GEN.v

数据生成模块,该模块读取文件中的数据到ROM,将ROM中的512个数据发送出去,注意数据宽度为80bit,进行了扩展,实际上只需要你之前配置的外部数据宽度如20bit就可以啦。

`timescale 1ns / 1ps
`define DLY #1

//***********************************Entity Declaration*******************************
(* DowngradeIPIdentifiedWarnings="yes" *)
module gtwizard_0_GT_FRAME_GEN #
(
    // parameter to set the number of words in the BRAM
    parameter   WORDS_IN_BRAM =   512
)
(
   // User Interface
output reg  [79:0]  TX_DATA_OUT,
output reg  [7:0]   TXCTRL_OUT,

      // System Interface
input  wire         USER_CLK,
input  wire         SYSTEM_RESET 
); 


//********************************* Wire Declarations********************************* 

wire            tied_to_ground_i;
wire             tied_to_vcc_i;
wire    [31:0]  tied_to_ground_vec_i;
wire    [63:0]  tx_data_bram_i;
wire    [7:0]   tx_ctrl_i;

//***************************Internal Register Declarations*************************** 

reg     [8:0]   read_counter_i;
    reg     [79:0] rom [0:511];
reg     [79:0]  tx_data_ram_r;
(* ASYNC_REG = "TRUE" *) (* keep = "true" *)    reg     system_reset_r; 
(* ASYNC_REG = "TRUE" *) (* keep = "true" *)    reg     system_reset_r2; 


//*********************************Main Body of Code**********************************

    assign tied_to_ground_vec_i  =   32'h00000000;
    assign tied_to_ground_i      =   1'b0;
    assign tied_to_vcc_i         =   1'b1;
    
    //___________ synchronizing the async reset for ease of timing simulation ________
    always@(posedge USER_CLK)
        begin
       system_reset_r <= `DLY SYSTEM_RESET;
       system_reset_r2 <= `DLY system_reset_r;
        end

    //____________________________ Counter to read from BRAM __________________________    

    always @(posedge USER_CLK)
        if(system_reset_r2 || (read_counter_i == "111111111"))  
        begin
             read_counter_i   <=  `DLY    9'd0;
        end
        else read_counter_i   <=  `DLY    read_counter_i + 9'd1;

    // Assign TX_DATA_OUT to BRAM output
    always @(posedge USER_CLK)
        if(system_reset_r2) TX_DATA_OUT <= `DLY 80'h0000000000; 
        else             TX_DATA_OUT <= `DLY {tx_data_bram_i,tx_data_ram_r[15:0]};   

    // Assign TXCTRL_OUT to BRAM output
    always @(posedge USER_CLK)
        if(system_reset_r2) TXCTRL_OUT <= `DLY 8'h0; 
        else             TXCTRL_OUT <= `DLY tx_ctrl_i;  


    //________________________________ BRAM Inference Logic _____________________________    

    assign tx_data_bram_i      = tx_data_ram_r[79:16];
    assign tx_ctrl_i           = tx_data_ram_r[15:8];
  
    initial
    begin
           $readmemh("gt_rom_init_tx.dat",rom,0,511);
    end

    always @(posedge USER_CLK)
           tx_data_ram_r <= `DLY rom[read_counter_i];

endmodule 

我们打开gt_rom_init_tx.dat文件,可以发现数据源是连接递增的数据
在这里插入图片描述

4.3 gtwizard_0_GT_FRAME_CHECK.v

`timescale 1ns / 1ps
`define DLY #1

//***********************************Entity Declaration************************
(* DowngradeIPIdentifiedWarnings="yes" *)
module gtwizard_0_GT_FRAME_CHECK #
(
    // parameter to set the number of words in the BRAM
    parameter   RX_DATA_WIDTH            =  64,
    parameter   RXCTRL_WIDTH             =  2,
    parameter   WORDS_IN_BRAM            =  512,
    parameter   CHANBOND_SEQ_LEN         =  1,
    parameter   COMMA_DOUBLE             =  16'hf628,
    parameter   START_OF_PACKET_CHAR     =  64'h00000000000000fb
)                            
(
    // User Interface
    input  wire [(RX_DATA_WIDTH-1):0] RX_DATA_IN,
    input  wire [(RXCTRL_WIDTH-1):0] RXCTRL_IN,

    output reg          RXENPCOMMADET_OUT,
    output reg          RXENMCOMMADET_OUT,
    output reg          RX_ENCHAN_SYNC_OUT,
    input  wire         RX_CHANBOND_SEQ_IN,

    // Control Interface
    input  wire         INC_IN,
    output wire         INC_OUT,
    output wire         PATTERN_MATCHB_OUT,
    input  wire         RESET_ON_ERROR_IN,


    // Error Monitoring
    output wire [7:0]   ERROR_COUNT_OUT,
    
    // Track Data
    output wire         TRACK_DATA_OUT,

    output wire RX_SLIDE,
    // System Interface
    input  wire         USER_CLK,
    input  wire         SYSTEM_RESET 
);


//***************************Internal Register Declarations******************** 

reg             reset_on_error_in_r;
reg             reset_on_error_in_r2;
(* ASYNC_REG = "TRUE" *) (* keep = "true" *)reg             system_reset_r;
(* ASYNC_REG = "TRUE" *) (* keep = "true" *)reg             system_reset_r2;

reg             begin_r;
reg             data_error_detected_r;
reg     [8:0]   error_count_r;
reg             error_detected_r;
reg     [9:0]   read_counter_i;    

    reg     [79:0] rom [0:511];    

    reg     [(RX_DATA_WIDTH-1):0] rx_data_r;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r_track;

reg             start_of_packet_detected_r;    
reg             track_data_r;
reg             track_data_r2;
reg             track_data_r3;
reg     [79:0]  rx_data_ram_r;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r2;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r3;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r4;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r5;
    reg     [(RX_DATA_WIDTH-1):0] rx_data_r6;
    reg     [(RXCTRL_WIDTH-1):0]  rxctrl_r;
    reg     [(RXCTRL_WIDTH-1):0]  rxctrl_r2;
    reg     [(RXCTRL_WIDTH-1):0]  rxctrl_r3;

reg             rx_chanbond_seq_r;
reg             rx_chanbond_seq_r2;
reg             rx_chanbond_seq_r3; 
 
    reg             idle_slip_r;
    reg             slip_assert_r;
    reg             wait_state_r;
    reg             bit_align_r;
    reg     [6:0]   wait_before_slip_r;
    reg     [6:0]   wait_before_init_r;    
 
    reg     [1:0]   sel;
//*********************************Wire Declarations***************************

    wire    [(RX_DATA_WIDTH-1):0] bram_data_r;
wire            error_detected_c;
wire            next_begin_c;
wire            next_data_error_detected_c;
wire            next_track_data_c;
wire            start_of_packet_detected_c;
wire            chanbondseq_in_data;
wire            input_to_chanbond_data_i;
wire            input_to_chanbond_reg_i;
wire    [(CHANBOND_SEQ_LEN-1):0]  rx_chanbond_reg;
wire            rxdata_or;
wire            count_slip_complete_c;
wire            next_idle_slip_c;
wire            next_slip_assert_c;
wire            wait_state_c;
    wire    [(RX_DATA_WIDTH-1):0]  rx_data_aligned;
wire            rx_data_has_start_char_c;
wire            tied_to_ground_i;
wire    [31:0]  tied_to_ground_vec_i;
wire            tied_to_vcc_i;

//*********************************Main Body of Code***************************

    //_______________________  Static signal Assigments _______________________   

    assign tied_to_ground_i             = 1'b0;
    assign tied_to_ground_vec_i         = 32'h0000;
    assign tied_to_vcc_i                = 1'b1;

    //___________ synchronizing the async reset for ease of timing simulation ________
    always@(posedge USER_CLK)
      begin
       system_reset_r <= `DLY SYSTEM_RESET;    
       system_reset_r2 <= `DLY system_reset_r; 
     end   
    always@(posedge USER_CLK)
      begin
       reset_on_error_in_r <= `DLY RESET_ON_ERROR_IN;    
       reset_on_error_in_r2 <= `DLY reset_on_error_in_r;    
     end   

    //______________________ Register RXDATA once to ease timing ______________   

    always @(posedge USER_CLK)
    begin
        rx_data_r  <= `DLY    RX_DATA_IN;
        rx_data_r2 <= `DLY    rx_data_r;
    end 

    always @(posedge USER_CLK)
    begin
        rxctrl_r  <= `DLY    RXCTRL_IN;
    end

    //________________________________ State machine __________________________    
    
    // State registers
    always @(posedge USER_CLK)
        if(system_reset_r2)
            {begin_r,track_data_r,data_error_detected_r}  <=  `DLY    3'b100;
        else
        begin
            begin_r                <=  `DLY    next_begin_c;
            track_data_r           <=  `DLY    next_track_data_c;
            data_error_detected_r  <=  `DLY    next_data_error_detected_c;
        end

    // Next state logic
    assign  next_begin_c                =   (begin_r && !start_of_packet_detected_r)
                                            || data_error_detected_r ;

    assign  next_track_data_c           =   (begin_r && start_of_packet_detected_r)
                                            || (track_data_r && !error_detected_r);
                                      
    assign  next_data_error_detected_c  =   (track_data_r && error_detected_r);                               
        
    assign  start_of_packet_detected_c  =   rx_data_has_start_char_c;

    always @(posedge USER_CLK) 
        start_of_packet_detected_r    <=   `DLY  start_of_packet_detected_c;  

    // Registering for timing
    always @(posedge USER_CLK) 
        track_data_r2    <=   `DLY  track_data_r;  

    always @(posedge USER_CLK) 
        track_data_r3    <=   `DLY  track_data_r2; 

    //______________________________ Capture incoming data ____________________    

    always @(posedge USER_CLK)
    begin
        if(system_reset_r2)    rx_data_r3 <= 'h0;
        else
        begin
            if(sel == 2'b01)
            begin
                rx_data_r3   <=  `DLY    {rx_data_r[(RX_DATA_WIDTH/2 - 1):0],rx_data_r2[(RX_DATA_WIDTH-1):RX_DATA_WIDTH/2]};  
            end
        else rx_data_r3  <=  `DLY    rx_data_r2;
        end
    end

    always @(posedge USER_CLK)
    begin
        if(system_reset_r2)  
        begin
            rx_data_r4      <=  `DLY   'h0;
            rx_data_r5      <=  `DLY   'h0;
            rx_data_r6      <=  `DLY   'h0;
            rx_data_r_track <=  `DLY   'h0;
        end
        else
        begin
            rx_data_r4      <=  `DLY    rx_data_r3;
            rx_data_r5      <=  `DLY    rx_data_r4;
            rx_data_r6      <=  `DLY    rx_data_r5;
            rx_data_r_track <=  `DLY    rx_data_r6;
        end
    end

    always @(posedge USER_CLK)
    begin
        if(system_reset_r2)  
        begin
            rxctrl_r2      <=  `DLY   'h0;
            rxctrl_r3      <=  `DLY   'h0;
        end
        else
        begin
            rxctrl_r2      <=  `DLY   rxctrl_r;
            rxctrl_r3      <=  `DLY   rxctrl_r2;
        end
    end
    assign rx_data_aligned = rx_data_r3;

    //___________________________ Code for Channel bonding ____________________    
    // code to prevent checking of clock correction sequences for the start of packet char
    always @(posedge USER_CLK)
    begin
        rx_chanbond_seq_r  <=  `DLY    RX_CHANBOND_SEQ_IN;
        rx_chanbond_seq_r2 <=  `DLY    rx_chanbond_seq_r;
        rx_chanbond_seq_r3 <=  `DLY    rx_chanbond_seq_r2;
    end
    
    assign input_to_chanbond_reg_i  = rx_chanbond_seq_r2;
    assign input_to_chanbond_data_i = tied_to_ground_i;


   //______________ Code for Bit Slipping Logic______________

    assign rxdata_or = |(rx_data_r|rx_data_r2|rx_data_r3);

    // State registers
    always @(posedge USER_CLK)
        if( (system_reset_r2 == 1'b1) | (wait_before_init_r[6] == 1'b0) | (rxdata_or == 1'b0) )
            {idle_slip_r,slip_assert_r,wait_state_r}  <=  `DLY    3'b100;
        else
        begin
            idle_slip_r            <=  `DLY    next_idle_slip_c;
            slip_assert_r          <=  `DLY    next_slip_assert_c;
            wait_state_r           <=  `DLY    wait_state_c;
        end

    // Next state logic
    assign  next_idle_slip_c            =   (idle_slip_r & bit_align_r) | (wait_state_r & count_slip_complete_c);

    assign  next_slip_assert_c          =   (idle_slip_r & !bit_align_r);

    assign  wait_state_c                =   (slip_assert_r) | (wait_state_r & !count_slip_complete_c);

    //_______ Counter for waiting clock cycles after RXSLIDE________
    always @(posedge USER_CLK)
    begin
        if (!wait_state_r)
           wait_before_slip_r  <= `DLY  7'b000000;
        else
           wait_before_slip_r  <= `DLY  wait_before_slip_r + 1'b1;
    end

    //_______ Counter for waiting clock cycles before starting RXSLIDE operation________
    //_______ Wait for 64 clock cycles to see if the RXDATA is already byte aligned. If not, start RXSLIDE operation
    always @(posedge USER_CLK)
    begin	    
        if( (system_reset_r2 == 1'b1) | (rxdata_or == 1'b0) )
	     wait_before_init_r <= `DLY    7'b0000000;
        else if (wait_before_init_r[6] == 1'b0)
             wait_before_init_r <= `DLY    wait_before_init_r + 1'b1;
    end

    assign count_slip_complete_c = wait_before_slip_r[6];

    always @(posedge USER_CLK)
    begin
        if( (system_reset_r2 == 1'b1) | (rxdata_or == 1'b0) )   begin
          bit_align_r <= 1'b0;
        end else begin
            if( ({rx_data_r[7:0],rx_data_r2[15:8]} == START_OF_PACKET_CHAR) || (rx_data_r[15:0]== START_OF_PACKET_CHAR) )
            begin
                bit_align_r <= 1'b1;
            end
        end
    end


    // In 2 Byte scenario, when align_comma_word=1, Comma can appear on any of the two bytes
    // The comma is moved to the lower byte so that error checking can start
    always @(posedge USER_CLK)
    begin
        if(reset_on_error_in_r2 || system_reset_r2)    sel <= 2'b00;
        else if (begin_r && !rx_chanbond_seq_r)
        begin
            // if Comma appears on BYTE0 ..
            if((rx_data_r[(RX_DATA_WIDTH/2 - 1):0] == START_OF_PACKET_CHAR[7:0]) && rxctrl_r[0])
                sel <= 2'b00;
            // if Comma appears on BYTE1 ..            
            else if((rx_data_r[(RX_DATA_WIDTH-1):RX_DATA_WIDTH/2] == START_OF_PACKET_CHAR[7:0]) && rxctrl_r[1])
            begin
                sel <= 2'b01;
            end
        end      
    end

    //___________________________ Code for Channel bonding ____________________    
    // code to prevent checking of clock correction sequences for the start of packet char
    genvar i; 
    generate
    for (i=0;i<CHANBOND_SEQ_LEN ;i=i+1)
    begin:register_chan_seq
    if(i==0)
        FD rx_chanbond_reg_0  ( .Q (rx_chanbond_reg[i]), .D (input_to_chanbond_reg_i), .C(USER_CLK));
    else
        FD rx_chanbond_reg_i  ( .Q (rx_chanbond_reg[i]), .D (rx_chanbond_reg[i-1]), .C(USER_CLK));
    end
    endgenerate
    
    assign chanbondseq_in_data = |rx_chanbond_reg || input_to_chanbond_data_i;


    assign rx_data_has_start_char_c = (rx_data_aligned[7:0] == START_OF_PACKET_CHAR[7:0]) && !chanbondseq_in_data && (|rxctrl_r3);


    //_____________________________ Assign output ports _______________________    
    //assign TRACK_DATA_OUT = track_data_r;

    assign RX_SLIDE = slip_assert_r;

    // Drive the enpcommaalign port of the gt for alignment
    always @(posedge USER_CLK)
        if(system_reset_r2)  RXENPCOMMADET_OUT   <=  `DLY    1'b0;
        else              RXENPCOMMADET_OUT   <=  `DLY    1'b1;

    // Drive the enmcommaalign port of the gt for alignment
    always @(posedge USER_CLK)
        if(system_reset_r2)  RXENMCOMMADET_OUT   <=  `DLY    1'b0;
        else              RXENMCOMMADET_OUT   <=  `DLY    1'b1;

    assign INC_OUT =  start_of_packet_detected_c;   

    assign PATTERN_MATCHB_OUT =  data_error_detected_r;

    // Drive the enchansync port of the mgt for channel bonding
    always @(posedge USER_CLK)
        if(system_reset_r2)  RX_ENCHAN_SYNC_OUT   <=  `DLY    1'b0;
        else              RX_ENCHAN_SYNC_OUT   <=  `DLY    1'b1;

    //___________________________ Check incoming data for errors ______________
         
    //An error is detected when data read for the BRAM does not match the incoming data
    assign  error_detected_c    =  track_data_r3 && (rx_data_r_track != bram_data_r); 

    //We register the error_detected signal for use with the error counter logic
    always @(posedge USER_CLK)
        if(!track_data_r)  
            error_detected_r    <=  `DLY    1'b0;
        else
            error_detected_r    <=  `DLY    error_detected_c;  

    //We count the total number of errors we detect. By keeping a count we make it less likely that we will miss
    //errors we did not directly observe. 
    always @(posedge USER_CLK)
        if(system_reset_r2)
            error_count_r       <=  `DLY    9'd0;
        else if(error_detected_r)
            error_count_r       <=  `DLY    error_count_r + 1;    
    
    //Here we connect the lower 8 bits of the count (the MSbit is used only to check when the counter reaches
    //max value) to the module output
    assign  ERROR_COUNT_OUT =   error_count_r[7:0];

  localparam ST_LINK_DOWN = 1'b0;
  localparam ST_LINK_UP   = 1'b1;
  reg        sm_link      = ST_LINK_DOWN;
  reg [6:0]  link_ctr     = 7'd0;

  always @(posedge USER_CLK) begin
        if(!track_data_r)  
              sm_link  <= ST_LINK_DOWN;
        else       
    case (sm_link)
      // The link is considered to be down when the link counter initially has a value less than 67. When the link is
      // down, the counter is incremented on each cycle where all PRBS bits match, but reset whenever any PRBS mismatch
      // occurs. When the link counter reaches 67, transition to the link up state.
      ST_LINK_DOWN: begin
        if (error_detected_r !== 1'b0) begin
          link_ctr <= 7'd0;
        end
        else begin
          if (link_ctr < 7'd67)
            link_ctr <= link_ctr + 7'd1;
          else
            sm_link <= ST_LINK_UP;
        end
      end

      // When the link is up, the link counter is decreased by 34 whenever any PRBS mismatch occurs, but is increased by
      // only 1 on each cycle where all PRBS bits match, up to its saturation point of 67. If the link counter reaches
      // 0 (including rollover protection), transition to the link down state.
      ST_LINK_UP: begin
        if (error_detected_r !== 1'b0) begin
          if (link_ctr > 7'd33) begin
            link_ctr <= link_ctr - 7'd34;
            if (link_ctr == 7'd34)
              sm_link  <= ST_LINK_DOWN;
          end
          else begin
            link_ctr <= 7'd0;
            sm_link  <= ST_LINK_DOWN;
          end
        end
        else begin
          if (link_ctr < 7'd67)
            link_ctr <= link_ctr + 7'd1;
        end
      end
    endcase
  end

assign TRACK_DATA_OUT = sm_link;
    //____________________________ Counter to read from BRAM __________________________    
    always @(posedge USER_CLK)
        if(system_reset_r2 ||  (read_counter_i == (WORDS_IN_BRAM-1)))
        begin
            read_counter_i   <=  `DLY    10'd0;
        end
        else if (start_of_packet_detected_r && !track_data_r)
        begin
            read_counter_i   <=  `DLY    10'd0;
        end
        else
        begin
            read_counter_i  <=  `DLY    read_counter_i + 10'd1;
        end

    //________________________________ BRAM Inference Logic _____________________________    

//Array slice from dat file to compare against receive data  
generate
if(RX_DATA_WIDTH==80)
begin : datapath_80
    assign bram_data_r      = rx_data_ram_r[(RX_DATA_WIDTH-1):0];
end
else
begin : datapath_16_20_32_40_64
    assign bram_data_r = rx_data_ram_r[(16+RX_DATA_WIDTH-1):16];
end 
endgenerate

    initial
    begin
           $readmemh("gt_rom_init_rx.dat",rom,0,511);
    end

    always @(posedge USER_CLK)
           rx_data_ram_r <= `DLY  rom[read_counter_i];
    
    
endmodule           



可以换成自己的检测逻辑,或者不修改使用,我这里是使用了。

5. 仿真测试

代码分析完后对整个的GT框架是不是有一定的了解了,接着我们就开始仿真吧。官方的demo例程不需要修改,直接Run Simulation就可以啦!
我们来看下波形,重点关注gt0_txdatagt0_rxdata、就行。
在这里插入图片描述
在这里插入图片描述

发送的数据和接收的数据一致,跑到差不多600us的时候track_data_high_r信号会拉高,仿真结束,打印消息。

最后打印信息中显示test passed
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值