GT IP核仿真测试
GT IP核仿真测试
- 1. 前言
- 2. 概述
- 3. IP核配置
- 第一页
- 第二页
- 第三页
- 第四页
- 第五页
- 第六页
- 第七页
- 4. 代码框架分析
- 4.1 gtwizard_exdes.v
- 4.2 gtwizard_0_GT_FRAME_GEN.v
- 4.3 gtwizard_0_GT_FRAME_CHECK.v
- 5. 仿真测试
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
- TX
External Data width(bits):外部数据宽度,可配置,我配的20bit,这个看个人的;
Encoding:编码方式,可选择8B/10B,我选择的NONE;
Internal Data with(bits);内部数据宽度,也就是IP核内部的数据宽度 - RX
External Data width(bits):外部数据宽度,可配置,我配的20bit,这个看个人的;
Encoding:编码方式,可选择8B/10B,我选择的NONE;
Internal Data with(bits);内部数据宽度,也就是IP核内部的数据宽度 - Synchronization and Clocking
勾选Enable TX buffer和Enable RX buffer,勾选后代表增加了一个FIFO去缓存发送的数据,不知道我这样理解对不对,勾选就对了。 - 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 checkparameter EXAMPLE_LANE_WITH_START_CHAR = 0, // specifies lane with unique start frame charparameter EXAMPLE_WORDS_IN_BRAM = 512, // specifies amount of data in BRAMparameter EXAMPLE_SIM_GTRESET_SPEEDUP = "TRUE", // simulation setting for GT SecureIP modelparameter EXAMPLE_USE_CHIPSCOPE = 0, // Set to 1 to use Chipscope to drive resetsparameter 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
);
接着例化了三个子模块。
- support是GT的核心代码,它例化了GTX IP核,一般无需修改。
- frame_gen是我们需要发送的数据,在实际应用中,换成自己数据输入源就可以了;
- 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 BRAMparameter 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)beginsystem_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")) beginread_counter_i <= `DLY 9'd0;endelse read_counter_i <= `DLY read_counter_i + 9'd1;// Assign TX_DATA_OUT to BRAM outputalways @(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 outputalways @(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];initialbegin$readmemh("gt_rom_init_tx.dat",rom,0,511);endalways @(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 BRAMparameter 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 Interfaceinput 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 Interfaceinput wire INC_IN,output wire INC_OUT,output wire PATTERN_MATCHB_OUT,input wire RESET_ON_ERROR_IN,// Error Monitoringoutput wire [7:0] ERROR_COUNT_OUT,// Track Dataoutput wire TRACK_DATA_OUT,output wire RX_SLIDE,// System Interfaceinput 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)beginsystem_reset_r <= `DLY SYSTEM_RESET; system_reset_r2 <= `DLY system_reset_r; end always@(posedge USER_CLK)beginreset_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)beginrx_data_r <= `DLY RX_DATA_IN;rx_data_r2 <= `DLY rx_data_r;end always @(posedge USER_CLK)beginrxctrl_r <= `DLY RXCTRL_IN;end//________________________________ State machine __________________________ // State registersalways @(posedge USER_CLK)if(system_reset_r2){begin_r,track_data_r,data_error_detected_r} <= `DLY 3'b100;elsebeginbegin_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 logicassign 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 timingalways @(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)beginif(system_reset_r2) rx_data_r3 <= 'h0;elsebeginif(sel == 2'b01)beginrx_data_r3 <= `DLY {rx_data_r[(RX_DATA_WIDTH/2 - 1):0],rx_data_r2[(RX_DATA_WIDTH-1):RX_DATA_WIDTH/2]}; endelse rx_data_r3 <= `DLY rx_data_r2;endendalways @(posedge USER_CLK)beginif(system_reset_r2) beginrx_data_r4 <= `DLY 'h0;rx_data_r5 <= `DLY 'h0;rx_data_r6 <= `DLY 'h0;rx_data_r_track <= `DLY 'h0;endelsebeginrx_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;endendalways @(posedge USER_CLK)beginif(system_reset_r2) beginrxctrl_r2 <= `DLY 'h0;rxctrl_r3 <= `DLY 'h0;endelsebeginrxctrl_r2 <= `DLY rxctrl_r;rxctrl_r3 <= `DLY rxctrl_r2;endendassign rx_data_aligned = rx_data_r3;//___________________________ Code for Channel bonding ____________________ // code to prevent checking of clock correction sequences for the start of packet charalways @(posedge USER_CLK)beginrx_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;endassign 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 registersalways @(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;elsebeginidle_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 logicassign 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)beginif (!wait_state_r)wait_before_slip_r <= `DLY 7'b000000;elsewait_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 operationalways @(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;endassign count_slip_complete_c = wait_before_slip_r[6];always @(posedge USER_CLK)beginif( (system_reset_r2 == 1'b1) | (rxdata_or == 1'b0) ) beginbit_align_r <= 1'b0;end else beginif( ({rx_data_r[7:0],rx_data_r2[15:8]} == START_OF_PACKET_CHAR) || (rx_data_r[15:0]== START_OF_PACKET_CHAR) )beginbit_align_r <= 1'b1;endendend// 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 startalways @(posedge USER_CLK)beginif(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])beginsel <= 2'b01;endend end//___________________________ Code for Channel bonding ____________________ // code to prevent checking of clock correction sequences for the start of packet chargenvar i; generatefor (i=0;i<CHANBOND_SEQ_LEN ;i=i+1)begin:register_chan_seqif(i==0)FD rx_chanbond_reg_0 ( .Q (rx_chanbond_reg[i]), .D (input_to_chanbond_reg_i), .C(USER_CLK));elseFD rx_chanbond_reg_i ( .Q (rx_chanbond_reg[i]), .D (rx_chanbond_reg[i-1]), .C(USER_CLK));endendgenerateassign 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 alignmentalways @(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 alignmentalways @(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 bondingalways @(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 dataassign 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 logicalways @(posedge USER_CLK)if(!track_data_r) error_detected_r <= `DLY 1'b0;elseerror_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 outputassign 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) beginif(!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: beginif (error_detected_r !== 1'b0) beginlink_ctr <= 7'd0;endelse beginif (link_ctr < 7'd67)link_ctr <= link_ctr + 7'd1;elsesm_link <= ST_LINK_UP;endend// 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: beginif (error_detected_r !== 1'b0) beginif (link_ctr > 7'd33) beginlink_ctr <= link_ctr - 7'd34;if (link_ctr == 7'd34)sm_link <= ST_LINK_DOWN;endelse beginlink_ctr <= 7'd0;sm_link <= ST_LINK_DOWN;endendelse beginif (link_ctr < 7'd67)link_ctr <= link_ctr + 7'd1;endendendcaseendassign 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)))beginread_counter_i <= `DLY 10'd0;endelse if (start_of_packet_detected_r && !track_data_r)beginread_counter_i <= `DLY 10'd0;endelsebeginread_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_80assign bram_data_r = rx_data_ram_r[(RX_DATA_WIDTH-1):0];
end
else
begin : datapath_16_20_32_40_64assign bram_data_r = rx_data_ram_r[(16+RX_DATA_WIDTH-1):16];
end
endgenerateinitialbegin$readmemh("gt_rom_init_rx.dat",rom,0,511);endalways @(posedge USER_CLK)rx_data_ram_r <= `DLY rom[read_counter_i];endmodule
可以换成自己的检测逻辑,或者不修改使用,我这里是使用了。
5. 仿真测试
代码分析完后对整个的GT框架是不是有一定的了解了,接着我们就开始仿真吧。官方的demo例程不需要修改,直接Run Simulation就可以啦!
我们来看下波形,重点关注gt0_txdata、gt0_rxdata、就行。
发送的数据和接收的数据一致,跑到差不多600us的时候track_data_high_r信号会拉高,仿真结束,打印消息。
最后打印信息中显示test passed