GTX_IP核实现SMA口发送数据(3)GTX例程代码详细介绍

配置IP核生产的example文件代码如下
各个代码模块的功能如下:

所以分为三个模块进行介绍
gt_frame_gen通过读取FPGA内部的ROM的数据来产生伪随机码
gt_frame_gen通过测验相关的数据来观察数据的正确
然后是support配置的介绍,主要代码如下图所示
时钟端的基本知识介绍

以7系列的GTX来说,每个Quad有两个外部差分参考时钟源,其中一个Quad的时钟结构如图所示:

红色方框部分是两个差分参考时钟输入,每个外部参考时钟的输入必须经过IBUFDS_GTE2源语之后才能使用。绿色方框是来自其他Quad的参考时钟输入,7系列FPGA支持使用相邻(南北方向)Quad的参考时钟作为当前Quad的参考时钟,多路参考时钟源经过一个选择器之后,分两路进入QPLL和CPLL,其中蓝色方框是QPLL,黄色方框是CPLL,对于一个GTX Channel来说,可以独立选择参考时钟,可以选择QPLL,也可以选择CPLL,QPLL和CPLL的区别在于两者支持的线速率不同,QPLL支持的线速率高于CPLL,图是外部参考时钟模型的详细结构,红色箭头表示QPLL通路,黄色箭头表示CPLL通路。
QPLL的内部多路选择器如上图,通过QPLLREFCLKSEL来控制输入的时钟,各个参数的具体的定义如下图所示,
输入端的定义:

输出端的定义


代码在gtx.common里面


同理,CPLL的配置不做详细介绍,看手册就好了。
关于进入TX或者RX端的时钟是QPLL还是CPLL,交给TXSYSCLKSEL寄存器来实现,当其选择为1的时候,QPLL进入,如下图所示。
动态改变方式:
下面进行代码及各个参数的详细讲解:
第一个讲解的代码如下(gtx_common.v):
`default_nettype wire

`timescale 1ns / 1ps
`define DLY #1
//***************************** Entity Declaration ****************************
module gtx_common #
(
    // Simulation attributes
    parameter   WRAPPER_SIM_GTRESET_SPEEDUP    =   "TRUE",     // Set to "true" to speed up sim reset
    parameter   SIM_QPLLREFCLK_SEL             =   3'b001     
)
(
    input   [2:0]   QPLLREFCLKSEL_IN,
    input           GTREFCLK0_IN,
    input           GTREFCLK1_IN,
    output          QPLLLOCK_OUT,
    input           QPLLLOCKDETCLK_IN,
    output          QPLLOUTCLK_OUT,
    output          QPLLOUTREFCLK_OUT,
    output          QPLLREFCLKLOST_OUT,   
    input           QPLLRESET_IN
);



//***************************** Parameter Declarations ************************
    localparam QPLL_FBDIV_TOP =  40;

    localparam QPLL_FBDIV_IN  =  (QPLL_FBDIV_TOP == 16)  ? 10'b0000100000 : 
				(QPLL_FBDIV_TOP == 20)  ? 10'b0000110000 :
				(QPLL_FBDIV_TOP == 32)  ? 10'b0001100000 :
				(QPLL_FBDIV_TOP == 40)  ? 10'b0010000000 :
				(QPLL_FBDIV_TOP == 64)  ? 10'b0011100000 :
				(QPLL_FBDIV_TOP == 66)  ? 10'b0101000000 :
				(QPLL_FBDIV_TOP == 80)  ? 10'b0100100000 :
				(QPLL_FBDIV_TOP == 100) ? 10'b0101110000 : 10'b0000000000;

   localparam QPLL_FBDIV_RATIO = (QPLL_FBDIV_TOP == 16)  ? 1'b1 : 
				(QPLL_FBDIV_TOP == 20)  ? 1'b1 :
				(QPLL_FBDIV_TOP == 32)  ? 1'b1 :
				(QPLL_FBDIV_TOP == 40)  ? 1'b1 :
				(QPLL_FBDIV_TOP == 64)  ? 1'b1 :
				(QPLL_FBDIV_TOP == 66)  ? 1'b0 :
				(QPLL_FBDIV_TOP == 80)  ? 1'b1 :
				(QPLL_FBDIV_TOP == 100) ? 1'b1 : 1'b1;

    // ground and vcc signals
wire            tied_to_ground_i;
wire    [63:0]  tied_to_ground_vec_i;
wire            tied_to_vcc_i;
wire    [63:0]  tied_to_vcc_vec_i;

    assign tied_to_ground_i             = 1'b0;
    assign tied_to_ground_vec_i         = 64'h0000000000000000;
    assign tied_to_vcc_i                = 1'b1;
    assign tied_to_vcc_vec_i            = 64'hffffffffffffffff;//高低电平

    //_________________________________________________________________________
    //_________________________________________________________________________
    //_________________________GTXE2_COMMON____________________________________

    GTXE2_COMMON #
    (
            // Simulation attributes
            .SIM_RESET_SPEEDUP   (WRAPPER_SIM_GTRESET_SPEEDUP),
            .SIM_QPLLREFCLK_SEL  (SIM_QPLLREFCLK_SEL),
            .SIM_VERSION         ("4.0"),


           //----------------COMMON BLOCK Attributes---------------
            .BIAS_CFG                               (64'h0000040000001000),
            .COMMON_CFG                             (32'h00000000),
            .QPLL_CFG                               (27'h06801C1),
            .QPLL_CLKOUT_CFG                        (4'b0000),
            .QPLL_COARSE_FREQ_OVRD                  (6'b010000),
            .QPLL_COARSE_FREQ_OVRD_EN               (1'b0),
            .QPLL_CP                                (10'b0000011111),
            .QPLL_CP_MONITOR_EN                     (1'b0),
            .QPLL_DMONITOR_SEL                      (1'b0),
            .QPLL_FBDIV                             (QPLL_FBDIV_IN),
            .QPLL_FBDIV_MONITOR_EN                  (1'b0),
            .QPLL_FBDIV_RATIO                       (QPLL_FBDIV_RATIO),
            .QPLL_INIT_CFG                          (24'h000006),
            .QPLL_LOCK_CFG                          (16'h21E8),
            .QPLL_LPF                               (4'b1111),
            .QPLL_REFCLK_DIV                        (1)

    )
    gtxe2_common_i
    (
        //----------- Common Block  - Dynamic Reconfiguration Port (DRP) -----------
        .DRPADDR                        (tied_to_ground_vec_i[7:0]),
        .DRPCLK                         (tied_to_ground_i),
        .DRPDI                          (tied_to_ground_vec_i[15:0]),
        .DRPDO                          (),
        .DRPEN                          (tied_to_ground_i),
        .DRPRDY                         (),
        .DRPWE                          (tied_to_ground_i),
        //-------------------- Common Block  - Ref Clock Ports ---------------------
        .GTGREFCLK                      (tied_to_ground_i),
        .GTNORTHREFCLK0                 (tied_to_ground_i),
        .GTNORTHREFCLK1                 (tied_to_ground_i),
        .GTREFCLK0                      (GTREFCLK0_IN),
        .GTREFCLK1                      (GTREFCLK1_IN),
        .GTSOUTHREFCLK0                 (tied_to_ground_i),
        .GTSOUTHREFCLK1                 (tied_to_ground_i),
        //----------------------- Common Block -  QPLL Ports -----------------------
        .QPLLDMONITOR                   (),
        //--------------------- Common Block - Clocking Ports ----------------------
        .QPLLOUTCLK                     (QPLLOUTCLK_OUT),
        .QPLLOUTREFCLK                  (QPLLOUTREFCLK_OUT),
        .REFCLKOUTMONITOR               (),
        //----------------------- Common Block - QPLL Ports ------------------------
        .QPLLFBCLKLOST                  (),
        .QPLLLOCK                       (QPLLLOCK_OUT),
        .QPLLLOCKDETCLK                 (QPLLLOCKDETCLK_IN),
        .QPLLLOCKEN                     (tied_to_vcc_i),
        .QPLLOUTRESET                   (tied_to_ground_i),
        .QPLLPD                         (tied_to_vcc_i),
        .QPLLREFCLKLOST                 (QPLLREFCLKLOST_OUT),
        .QPLLREFCLKSEL                  (QPLLREFCLKSEL_IN),
        .QPLLRESET                      (QPLLRESET_IN),
        .QPLLRSVD1                      (16'b0000000000000000),
        .QPLLRSVD2                      (5'b11111),
        //------------------------------- QPLL Ports -------------------------------
        .BGBYPASSB                      (tied_to_vcc_i),
        .BGMONITORENB                   (tied_to_vcc_i),
        .BGPDB                          (tied_to_vcc_i),
        .BGRCALOVRD                     (5'b11111),
        .PMARSVD                        (8'b00000000),
        .RCALENB                        (tied_to_vcc_i)

    );
endmodule
第十行开始讲解:第十行为SIM_QPLLREFCLK_SEL ,其主要是用来仿真的,并且要与QPLLREFCLK_SEL保持一致
输入输出在上面的表介绍过了,其他的补充在下图。
QPLLLOCKDETCLK
QPLLFBCLKLOST
QPLLREFCLKLOST
QPLLRESET
QPLL_FBDIV_IN和  QPLL_FBDIV_RATIO



DRP的用法

DRP的英文应该是dynamic reconfiguration port,意思是动态可重配置端口,那么drp clk到底是个什么呢?在IP核中用来干嘛的?

你听说过在线配置属性吗?(例如:GTX可以工作在不同线速率,用户可能需要通过更改内部属性来实现,这就需要DRP时钟了。)也许做过GTX/GTH的朋友,有意无意都听说过,那这个drp clk就是用于此的。

它还可以用来复位:

关于复位的代码的提示:GTRXRESET先为高电平就可以复位了
综上第一个代码的参数的讲解完毕。
第二个代码的讲解如下( gtx_common_reset.v)
`timescale 1ns / 1ps
`define DLY #1


module gtx_common_reset  #
   (
      parameter     STABLE_CLOCK_PERIOD      = 8        // Period of the stable clock driving this state-machine, unit is [ns]
   )
   (    
      input  wire      STABLE_CLOCK,             //Stable Clock, either a stable clock from the PCB
      input  wire      SOFT_RESET,               //User Reset, can be pulled any time
      output reg      COMMON_RESET = 1'b0             //Reset QPLL
   );


  localparam integer  STARTUP_DELAY    = 500;//AR43482: Transceiver needs to wait for 500 ns after configuration
  localparam integer WAIT_CYCLES      = STARTUP_DELAY / STABLE_CLOCK_PERIOD; // Number of Clock-Cycles to wait after configuration
  localparam integer WAIT_MAX         = WAIT_CYCLES + 10;                    // 500 ns plus some additional margin

  reg [7:0] init_wait_count = 0;
  reg       init_wait_done = 1'b0;
  wire      common_reset_i;
  reg       common_reset_asserted = 1'b0;

  localparam INIT = 1'b0;
  localparam ASSERT_COMMON_RESET = 1'b1;
    
  reg state = INIT;

  always @(posedge STABLE_CLOCK)
  begin
      // The counter starts running when configuration has finished and 
      // the clock is stable. When its maximum count-value has been reached,
      // the 500 ns from Answer Record 43482 have been passed.
      if (init_wait_count == WAIT_MAX) 
          init_wait_done <= `DLY  1'b1;
      else
        init_wait_count <= `DLY  init_wait_count + 1;
  end


  always @(posedge STABLE_CLOCK)
  begin
      if (SOFT_RESET == 1'b1)
       begin
         state <= INIT;
         COMMON_RESET <= 1'b0;
         common_reset_asserted <= 1'b0;
       end
      else
       begin
        case (state)
         INIT :
          begin
            if (init_wait_done == 1'b1) state <= ASSERT_COMMON_RESET;
          end
         ASSERT_COMMON_RESET :
          begin
            if(common_reset_asserted == 1'b0)
              begin
                COMMON_RESET <= 1'b1;
                common_reset_asserted <= 1'b1;
              end
            else
                COMMON_RESET <= 1'b0;
          end
          default:
              state <=  INIT; 
        endcase
       end
   end 


endmodule 
看名字就知道是复位用的,不做详细讲解:看一下输入输出就好了,连接到GTX收发器的sysclk引脚,和soft_reset引脚,主要是用来让GTX复位。
第三个代码比较重要(gtx_gt_usrclk_source.v)
首先介绍一下基础知识
翻译如下:

FPGA TX 接口包括两个并行时钟:TXUSRCLK 和 TXUSRCLK2。 TXUSRCLK 是 GTX/GTH 发送器中 PCS 逻辑的内部时钟。 TXUSRCLK 所需的速率取决于 GTXE2_CHANNEL/GTHE2_CHANNEL 原语的内部数据路径宽度和 GTX/GTH 发送器的 TX 线路速率。公式 3-1 显示了如何计算 TXUSRCLK 所需的速率。

翻译如下:

TXUSRCLK2 是进入 GTX/GTH 收发器 TX 侧的所有信号的主同步时钟。大多数进入 GTX/GTH 收发器 TX 侧的信号在 TXUSRCLK2 的正沿采样。 TXUSRCLK2 和 TXUSRCLK 具有基于 TX_DATA_WIDTH 和 TX_INT_DATAWIDTH 设置的固定速率关系。表 3-3 显示了每个 TX_DATA_WIDTH 和 TX_INT_DATAWIDTH 值的 TXUSRCLK2 和 TXUSRCLK 之间的关系。通过将 TX_INT_DATAWIDTH 设置为 1,大于 6.6 Gb/s 的线速需要 4 字节的内部数据路径。

根据GTX_IP核实现SMA口发送数据(一)IP核配置的配置,得到的具体参数如下:
TXUSRCLK 和 TXUSRCLK2的作用如下图:通过自锁发出TXOUTCLK和位宽来限制传输的线速率。

代码如下(gtx_gt_usrclk_source.v)
`timescale 1ns / 1ps

//***********************************Entity Declaration*******************************

module gtx_GT_USRCLK_SOURCE 
(
 
    output          GT0_TXUSRCLK_OUT,
    output          GT0_TXUSRCLK2_OUT,
    input           GT0_TXOUTCLK_IN,
    output          GT0_TXCLK_LOCK_OUT,
    input           GT0_TX_MMCM_RESET_IN,
    output          GT0_RXUSRCLK_OUT,
    output          GT0_RXUSRCLK2_OUT,
    output          GT0_RXCLK_LOCK_OUT,
    input           GT0_RX_MMCM_RESET_IN,
    input  wire  Q2_CLK1_GTREFCLK_PAD_N_IN,
    input  wire  Q2_CLK1_GTREFCLK_PAD_P_IN,
    output wire  Q2_CLK1_GTREFCLK_OUT



);


`define DLY #1

//*********************************Wire Declarations**********************************
    wire            tied_to_ground_i;
    wire            tied_to_vcc_i;
 
    wire            gt0_txoutclk_i; 
    wire  q2_clk1_gtrefclk /*synthesis syn_noclockbuf=1*/;

    wire            gt0_txusrclk_i;
    wire            gt0_txusrclk2_i;
    wire            txoutclk_mmcm0_locked_i;
    wire            txoutclk_mmcm0_reset_i;
    wire            gt0_txoutclk_to_mmcm_i;


//*********************************** Beginning of Code *******************************

    //  Static signal Assigments    
    assign tied_to_ground_i             = 1'b0;
    assign tied_to_vcc_i                = 1'b1;
    assign gt0_txoutclk_i = GT0_TXOUTCLK_IN;
     
    assign Q2_CLK1_GTREFCLK_OUT = q2_clk1_gtrefclk;

    //IBUFDS_GTE2
    IBUFDS_GTE2 ibufds_instQ2_CLK1  
    (
        .O               (q2_clk1_gtrefclk),
        .ODIV2           (),
        .CEB             (tied_to_ground_i),
        .I               (Q2_CLK1_GTREFCLK_PAD_P_IN),
        .IB              (Q2_CLK1_GTREFCLK_PAD_N_IN)
    );



    // Instantiate a MMCM module to divide the reference clock. Uses internal feedback
    // for improved jitter performance, and to avoid consuming an additional BUFG

    assign  txoutclk_mmcm0_reset_i               =  GT0_TX_MMCM_RESET_IN;
    gtx_CLOCK_MODULE #
    (
        .MULT                           (10.0),
        .DIVIDE                         (1),
        .CLK_PERIOD                     (16.0),
        .OUT0_DIVIDE                    (20.0),
        .OUT1_DIVIDE                    (10),
        .OUT2_DIVIDE                    (1),
        .OUT3_DIVIDE                    (1)
    )
    txoutclk_mmcm0_i
    (
        .CLK0_OUT                       (gt0_txusrclk2_i),
        .CLK1_OUT                       (gt0_txusrclk_i),
        .CLK2_OUT                       (),
        .CLK3_OUT                       (),
        .CLK_IN                         (gt0_txoutclk_i),
        .MMCM_LOCKED_OUT                (txoutclk_mmcm0_locked_i),
        .MMCM_RESET_IN                  (txoutclk_mmcm0_reset_i)
    );



 
assign GT0_TXUSRCLK_OUT = gt0_txusrclk_i;
assign GT0_TXUSRCLK2_OUT = gt0_txusrclk2_i;
assign GT0_TXCLK_LOCK_OUT = txoutclk_mmcm0_locked_i;
assign GT0_RXUSRCLK_OUT = gt0_txusrclk_i;
assign GT0_RXUSRCLK2_OUT = gt0_txusrclk2_i;
assign GT0_RXCLK_LOCK_OUT = txoutclk_mmcm0_locked_i;

endmodule
看代码主要就是例化了两个相关的IP核来配置TXUSRCLK和TXUSRCLK2
之后的代码( gtx_support.v)就是GTX的顶层模块,将上述的三个IP核例化,直接看RTL就好了,由于把三个IP集成了,所以输入输出较多,看信号输入输出需要从前面的IP看。代码没有关于8/10编码和FIFO,估计仍在了IP核里面,是一个黑匣子。所以补充了一点资料:
最后是顶层模块(gtx_exdes.v),代码较长,我们只看输入输出模块,6个输入3个输出。
    input wire  Q2_CLK1_GTREFCLK_PAD_N_IN,
    input wire  Q2_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
关于整体的信号的输入输出分析如下,看上图 
输入分析:
 input wire  Q2_CLK1_GTREFCLK_PAD_N_IN,
 input wire  Q2_CLK1_GTREFCLK_PAD_P_I
这两个是user_sma_clk 用来控制gtx_gt_usrclk_source.v文件生成TXUSRCLK和TXUSRCLK2
input wire  DRP_CLK_IN_P,
input wire  DRP_CLK_IN_N,
这两个是DRP时钟,用来gtx_common生成QPLLOUTCLK_OUT 和QPLLOUTREFCLK_OUT
 input  wire         RXN_IN,
input  wire         RXP_IN,
这两个是接受端输入,用来接受TX发送的数据,然后进行传输。
输出分析:
output wire         TXN_OUT,
output wire         TXP_OUT
这两个是发射端输出
TRACK_DATA_OUT  这个是跟追,高电平时候说明发出数据了

仿真结果:
系统通过读取frame_gen的ROM核数据进行伪随机码的发送,通过上述的输入输出分析,传输到RX接收。





posted @ 2021-09-02 15:23  快乐气氛组阿宇  阅读(2337)  评论(0编辑  收藏  举报