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
- 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 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
);
接着例化了三个子模块。
- 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 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_txdata、gt0_rxdata、就行。
发送的数据和接收的数据一致,跑到差不多600us的时候track_data_high_r信号会拉高,仿真结束,打印消息。
最后打印信息中显示test passed