GTX_IP核实现SMA口发送数据(3)GTX例程代码详细介绍
所以分为三个模块进行介绍
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
第二个代码的讲解如下( 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复位。
首先介绍一下基础知识
翻译如下:
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 字节的内部数据路径。
`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核里面,是一个黑匣子。所以补充了一点资料:
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接收。