gtwizard_ultrascale_1_example_top
gtwizrd를 block design에 넣어 사용하려고 했지만 직접 넣어 사용할수가 없었다.
아래 링크에 따르면,
https://support.xilinx.com/s/article/75723?language=en_US
75723 - UltraScale Transceiver Wizard: Cannot add an UltraScale GT wizard instance to an IP Integrator Block Design
UltraScale Transceiver Wizard designs are not compatible with board designs. As a result you cannot package a GT in an RTL module and then put it in an IP Integrator Block Design.
support.xilinx.com
transceiver example design을 IP로 package를 하고 block design에 넣어 사용을 권고한다.
단계로
1. GT example design을 만들고 TOP level파일을 목적에 맞게 수정 후 Package a new IP를 tool 메뉴에서 선택한다.
자세한 사항은 아래 파일을 참고한다.
Vivado Design Suite Tutorial: Creating and Packaging Custom IP - 2019.1 English
docs.xilinx.com
IPI 사용법에 대해서는 아래 링크를 참고한다.
Vivado 2022.1 - Using IP Integrator
www.xilinx.com
gtwizrd를 block design에 넣어 사용하려고 했지만 직접 넣어 사용할수 없기 때문에
1. GT example design을 만들고
2. TOP level파일을 수정을 하기위해서 우선 example design을 분석을 진행했다.
gtwizard_ultrascale_1_example_top.v의 부분코드
- 분석이 필요한 부분만 선택적 발췌
--------------------- 코드 ---------------------
module gtwizard_ultrascale_1_example_top (
// Differential reference clock inputs
input wire mgtrefclk0_x1y3_p, // gtwizard에서 사용될 reference clock input port
input wire mgtrefclk0_x1y3_n,
// Serial data ports for transceiver channel 0
input wire ch0_gthrxn_in, // Serial lane
input wire ch0_gthrxp_in,
output wire ch0_gthtxn_out,
output wire ch0_gthtxp_out,
// User-provided ports for reset helper block(s)
input wire hb_gtwiz_reset_clk_freerun_in, // gtwizard reset을 위한 clock
input wire hb_gtwiz_reset_all_in, // gtwizard reset 입력
// PRBS-based link status ports
input wire link_down_latched_reset_in,
output wire link_status_out,
output reg link_down_latched_out = 1'b1
);
--------------------- 설명 ---------------------
TOP 모듈의 input output 정의
--------------------- 코드 ---------------------
// ===================================================================================================================
// BUFFERS
// ===================================================================================================================
// Buffer the hb_gtwiz_reset_all_in input and logically combine it with the internal signal from the example
// initialization block as well as the VIO-sourced reset
wire hb_gtwiz_reset_all_vio_int;
wire hb_gtwiz_reset_all_buf_int;
wire hb_gtwiz_reset_all_init_int;
wire hb_gtwiz_reset_all_int;
IBUF ibuf_hb_gtwiz_reset_all_inst (
.I (hb_gtwiz_reset_all_in),
.O (hb_gtwiz_reset_all_buf_int)
);
assign hb_gtwiz_reset_all_int = hb_gtwiz_reset_all_buf_int || hb_gtwiz_reset_all_init_int || hb_gtwiz_reset_all_vio_int;
--------------------- 설명 ---------------------
hb_gtwiz_reset_all_int 신호는 아래 3가지 신호를 or 하여 구성된다.
1. 외부에서 받은 hb_gtwiz_reset_all_in리셋 신호
- hb_gtwiz_reset_all_in은 input buffer(IBUF)를 지나서 입력된다.
2. The example initialization module에서 받는 hb_gtwiz_reset_all_init_int 리셋 신호
- The example initialization module의 주요 목적은 gtwizard reset이 실패했을때 리셋을 다시 시도하도록 도와주는 모듈이다.
- 예를들어 초기에 유효하지 않은 reference clock 또는 유효하지 않는 data connection이 있을때 다시 리셋을 걸어주고
- rx측의 링크가 끊겼을대 리셋을 시도한다.
- 사용자가 어떻게 transceiver를 사용하느냐에 따라 수정할 수 있다.
3. Vio에서 사용자가 직접 리셋을 입력을 가능하게 하는 hb_gtwiz_reset_all_vio_int신호 (=Vio에서 사용자가 입력한 리셋 신호)
--------------------- 코드 ---------------------
// Globally buffer the free-running input clock
wire hb_gtwiz_reset_clk_freerun_buf_int;
BUFG bufg_clk_freerun_inst (
.I (hb_gtwiz_reset_clk_freerun_in),
.O (hb_gtwiz_reset_clk_freerun_buf_int)
);
--------------------- 설명---------------------
free-running input clock을 Global buffer를 통해 받아온다.
--------------------- 코드 ---------------------
// Instantiate a differential reference clock buffer for each reference clock differential pair in this configuration,
// and assign the single-ended output of each differential reference clock buffer to the appropriate PLL input signal
// Differential reference clock buffer for MGTREFCLK0_X1Y3
wire mgtrefclk0_x1y3_int;
IBUFDS_GTE3 #(
.REFCLK_EN_TX_PATH (1'b0),
.REFCLK_HROW_CK_SEL (2'b00),
.REFCLK_ICNTL_RX (2'b00)
) IBUFDS_GTE3_MGTREFCLK0_X1Y3_INST (
.I (mgtrefclk0_x1y3_p),
.IB (mgtrefclk0_x1y3_n),
.CEB (1'b0),
.O (mgtrefclk0_x1y3_int),
.ODIV2 ()
);
assign cm0_gtrefclk00_int = mgtrefclk0_x1y3_int;
--------------------- 설명 ---------------------
IBUFDS_GTE3:
https://docs.xilinx.com/r/2021.1-English/ug974-vivado-ultrascale-libraries/IBUFDS_GTE3
IBUFDS_GTE3 - 2021.1 English
Primitive: Gigabit Transceiver Buffer PRIMITIVE_GROUP: ADVANCED PRIMITIVE_SUBGROUP: GT Families: UltraScale Introduction IBUFDS_GTE3 is the gigabit transceiver input pad buffer component. The REFCLK signal should be routed to the dedicated reference clock
docs.xilinx.com
reference clock은 xilinx fpga에서 전용 pad를 통해 받아야 하는데 이를 IBUFDS_GTE3 Primitive로 받게된다.
UltraScale Architecture GTH Transceivers User Guide(UG576) page 67
1) REFCLK_EN_TX_PATH: 1'b0로 고정
2) REFCLK_HROW_CK_SEL: input clock대비 output clock의 분주를 설정한다.
- 예) 입력클럭이 100 MHz일때 2'b01로 설정 시 출력클럭이 50MHz가 된다.
3) REFCLK_ICNTL_RX : 2'b00로 고정
--------------------- 코드 ---------------------
// ===================================================================================================================
// USER CLOCKING RESETS
// ===================================================================================================================
// The TX user clocking helper block should be held in reset until the clock source of that block is known to be
// stable. The following assignment is an example of how that stability can be determined, based on the selected TX
// user clock source. Replace the assignment with the appropriate signal or logic to achieve that behavior as needed.
assign hb0_gtwiz_userclk_tx_reset_int = ~(&txpmaresetdone_int);
// The RX user clocking helper block should be held in reset until the clock source of that block is known to be
// stable. The following assignment is an example of how that stability can be determined, based on the selected RX
// user clock source. Replace the assignment with the appropriate signal or logic to achieve that behavior as needed.
assign hb0_gtwiz_userclk_rx_reset_int = ~(&rxpmaresetdone_int);
--------------------- 설명 ---------------------
txpmaresetdone_int의 모든비트끼리 and연산 후 not을하여 hb0_gtwiz_userclk_tx_reset_int 에 할당한다.
txpmaresetdone_int는 gtwizard_ultrascale_1_example_wrapper(transceiver IP)의 txpmaresetdone_out포트 출력과 연결되어있다.
txpmaresetdone_out의 역할은?
UltraScale Architecture GTH Transceivers:
https://docs.xilinx.com/v/u/en-US/ug576-ultrascale-gth-transceivers
UltraScale Architecture GTH Transceivers User Guide(UG576)
docs.xilinx.com
Page 66
- Async로 동작하고 Transciver의 TX PMA의 리셋 완료를 나타낸다.
- GTTXRESET 또는 TXPMARESET가 assert되었을때 low로 떨어진다.
assign hb0_gtwiz_userclk_tx_reset_int = ~(&txpmaresetdone_int);
즉, TX PMA의 리셋이 완료되면 hb0_gtwiz_userclk_tx_reset_int 는 0으로 출력된다.
RX측도 동일하다.
--------------------- 코드 ---------------------
// ===================================================================================================================
// PRBS STIMULUS, CHECKING, AND LINK MANAGEMENT
// ===================================================================================================================
// PRBS stimulus
// -------------------------------------------------------------------------------------------------------------------
// PRBS-based data stimulus module for transceiver channel 0
(* DONT_TOUCH = "TRUE" *)
gtwizard_ultrascale_1_example_stimulus_8b10b example_stimulus_inst0 (
.gtwiz_reset_all_in (hb_gtwiz_reset_all_int || ~hb0_gtwiz_reset_rx_done_int ),
.gtwiz_userclk_tx_usrclk2_in (hb0_gtwiz_userclk_tx_usrclk2_int),
.gtwiz_userclk_tx_active_in (hb0_gtwiz_userclk_tx_active_int),
.txctrl0_out (ch0_txctrl0_int),
.txctrl1_out (ch0_txctrl1_int),
.txctrl2_out (ch0_txctrl2_int),
.txdata_out (hb0_gtwiz_userdata_tx_int)
);
// PRBS checking
// -------------------------------------------------------------------------------------------------------------------
// Declare a signal vector of PRBS match indicators, with one indicator bit per transceiver channel
wire [0:0] prbs_match_int;
// PRBS-based data checking module for transceiver channel 0
gtwizard_ultrascale_1_example_checking_8b10b example_checking_inst0 (
.gtwiz_reset_all_in (hb_gtwiz_reset_all_int || ~hb0_gtwiz_reset_rx_done_int ),
.gtwiz_userclk_rx_usrclk2_in (hb0_gtwiz_userclk_rx_usrclk2_int),
.gtwiz_userclk_rx_active_in (hb0_gtwiz_userclk_rx_active_int),
.rxctrl0_in (ch0_rxctrl0_int),
.rxctrl1_in (ch0_rxctrl1_int),
.rxctrl2_in (ch0_rxctrl2_int),
.rxctrl3_in (ch0_rxctrl3_int),
.rxdata_in (hb0_gtwiz_userdata_rx_int),
.prbs_match_out (prbs_match_int[0])
);
--------------------- 설명 ---------------------
PRBS stimulus: Tx로 전송할 PRBS data 생성
PRBS checking: Rx로 받은 PRBS data 체크
(* DONT_TOUCH = "TRUE" *): Vivado Synthesis Attributes로 합성시 코드 최적화를 방지한다.
page 49
적용 가능한곳: signal, module, entity, or component
적용 불가능한곳: port, module, entity
1. gtwiz_reset_all_in에 2가지 신호가 들어간다.
1) gtwiz_reset_all_in: 외부에서 받은 hb_gtwiz_reset_all_in리셋 신호(active high) || he example initialization module에서 받는 hb_gtwiz_reset_all_init_int 리셋 신호(active high) || Vio에서 사용자가 입력한 리셋 신호(active high)
2) ~hb0_gtwiz_reset_rx_done_int: Transceiver의 gtwiz_reset_rx_done_out신호
즉, GTH transceiver의 RX측 리셋이 끝나면 hb0_gtwiz_reset_rx_done_int는 1이 되고 ~hb0_gtwiz_reset_rx_done_int는 0이 된다.
위 2가지로 보아 gtwiz_reset_all_in신호는 active high으로 동작한다.
2. gtwiz_userclk_tx_usrclk2_in
- Transceiver에 입력되는 TXDATA는 Clock Domain이 TXUSRCLK2이다. 따라서 Transciver의 gtwiz_userclk_tx_usrclk2_out포트에서 나오는 clock을 연결해줬다.
3. gtwiz_userclk_rx_active_in
- 간단하게 1이 되면 tx_usrclk2가 동작상태, 0이면 tx_usrclk2가 리셋상태를 의미한다.
4. txctrl0_out, txctrl1_out, txctrl2_out
이전글 참조: https://lunar7604.tistory.com/23
[UltraScale Architecture GTH Transceiver] Decoder Error Detection
Decoder Error Detection disparity check: performed by the decoder - RXDATA에 잘못된 dispraity가 도착하면 RXCTRL1이 1이된다. - 아래 그림에서 A, C는 에러 없는 데이터, B는 disparity 에러가 있는 데이터..
lunar7604.tistory.com
5. txdata_out
- 16 bits prbs 데이터 출력
Transceiver에 입력되는 데이터를 어떻게 생성하는지 좀더 자세히 알아보기 위해 gtwizard_ultrascale_1_example_stimulus_8b10b 모듈을 보면
--------------------- 코드 ---------------------
module: gtwizard_ultrascale_1_example_stimulus_8b10b
module gtwizard_ultrascale_1_example_stimulus_8b10b (
input wire gtwiz_reset_all_in,
input wire gtwiz_userclk_tx_usrclk2_in,
input wire gtwiz_userclk_tx_active_in,
output wire [15:0] txctrl0_out,
output wire [15:0] txctrl1_out,
output wire [7:0] txctrl2_out,
output wire [15:0] txdata_out
);
// -------------------------------------------------------------------------------------------------------------------
// Reset synchronizer
// -------------------------------------------------------------------------------------------------------------------
// Synchronize the example stimulus reset condition into the txusrclk2 domain
wire example_stimulus_reset_int = gtwiz_reset_all_in || ~gtwiz_userclk_tx_active_in;
wire example_stimulus_reset_sync;
(* DONT_TOUCH = "TRUE" *)
gtwizard_ultrascale_1_example_reset_synchronizer example_stimulus_reset_synchronizer_inst (
.clk_in (gtwiz_userclk_tx_usrclk2_in),
.rst_in (example_stimulus_reset_int),
.rst_out (example_stimulus_reset_sync)
);
... 중간 생략
reg [9:0] prbs_slt_ctr = 10'd0;
always @(posedge gtwiz_userclk_tx_usrclk2_in) begin
if (example_stimulus_reset_sync) begin
txdata_reg <= 16'b0;
txctrl2_reg <= 8'b0;
prbs_slt_ctr <= 10'd0;
end
else begin
if (&prbs_slt_ctr) begin
txdata_reg <= txdata_prbs;
txctrl2_reg <= 8'b0;
end
else begin
txdata_reg <= txdata_char;
txctrl2_reg <= 8'b000000_11;
prbs_slt_ctr <= prbs_slt_ctr + 10'd1;
end
end
end
--------------------- 설명 ---------------------
모든 Core, IP는 동작을 위해 clock과 reset이 가장 중요하다.
리셋의 구성을 보면 외부에서 받은 gtwiz_reset_all_in, ~gtwiz_userclk_tx_active_in 신호를 or연산 후 gtwizard_ultrascale_1_example_reset_synchronizer를 통과하여 최종적으로 example_stimulus_reset_sync를 내부 reset 신호로 사용한다. 정확히 분석을 위해서 Reset신호가 통과하는 gtwizard_ultrascale_1_example_reset_synchronizer의 역할을 아래 코드로 보자
module gtwizard_ultrascale_1_example_reset_synchronizer # (
parameter FREQUENCY = 512
)(
input wire clk_in,
input wire rst_in,
output wire rst_out
);
// Use 5 flip-flops as a single synchronizer, and tag each declaration with the appropriate synthesis attribute to
// enable clustering. Each flip-flop in the synchronizer is asynchronously reset so that the downstream logic is also
// asynchronously reset but encounters no reset assertion latency. The removal of reset is synchronous, so that the
// downstream logic is also removed from reset synchronously. This module is designed for active-high reset use.
(* ASYNC_REG = "TRUE" *) reg rst_in_meta = 1'b0;
(* ASYNC_REG = "TRUE" *) reg rst_in_sync1 = 1'b0;
(* ASYNC_REG = "TRUE" *) reg rst_in_sync2 = 1'b0;
(* ASYNC_REG = "TRUE" *) reg rst_in_sync3 = 1'b0;
reg rst_in_out = 1'b0;
always @(posedge clk_in, posedge rst_in) begin
if (rst_in) begin
rst_in_meta <= 1'b1;
rst_in_sync1 <= 1'b1;
rst_in_sync2 <= 1'b1;
rst_in_sync3 <= 1'b1;
rst_in_out <= 1'b1;
end
else begin
rst_in_meta <= 1'b0;
rst_in_sync1 <= rst_in_meta;
rst_in_sync2 <= rst_in_sync1;
rst_in_sync3 <= rst_in_sync2;
rst_in_out <= rst_in_sync3;
end
end
assign rst_out = rst_in_out;
endmodule
(* ASYNC_REG = "TRUE" *): 해당 레지스턴는 synchronization chain에 사용됨으로 합성시 최적화를 하지 않는다. 또한 클럭(clk)에 ansync한 데이터(D)를 받는 레지스터라고 Vivado 합성 툴에 안려준다. Page 45: https://www.xilinx.com/content/dam/xilinx/support/documents/sw_manuals/xilinx2022_1/ug901-vivado-synthesis.pdf
주석에 써있는대로 5개의 flip-flop을 사용하고 비동기 rst_in을 받아 5 clock 지연된 clk_in에 동기된 rst_out을 출력한다. 결국 입력된 비동기 reset신호(example_stimulus_reset_int)를 clock(gtwiz_userclk_tx_usrclk2_in)에 동기된 reset(example_stimulus_reset_sync)신호로 변경해주는 모듈인것이다.
example_stimulus_reset_int = (1)gtwiz_reset_all_in || ~(2)gtwiz_userclk_tx_active_in;
(1) gtwiz_reset_all_in = (1-1) hb_gtwiz_reset_all_int || ~(1-2) hb0_gtwiz_reset_rx_done_int
(1-1) hb_gtwiz_reset_all_int = hb_gtwiz_reset_all_buf_int || hb_gtwiz_reset_all_init_int || hb_gtwiz_reset_all_vio_int;
(1-2) hb0_gtwiz_reset_rx_done_int = gtwiz_reset_rx_done_out (gtwizard_ultrascale_1_example_init의 출력부분)
(2) gtwiz_userclk_tx_active_in = (2-1) hb0_gtwiz_userclk_tx_active_int
(2-1) hb0_gtwiz_userclk_tx_active_int = (2-2) gtwiz_userclk_tx_active_out (Transciver의 출력부분)
example_stimulus_reset_int = hb_gtwiz_reset_all_buf_int || hb_gtwiz_reset_all_init_int || hb_gtwiz_reset_all_vio_int || ~rx_init_done_in || ~gtwiz_userclk_tx_active_out (Transciver의 출력부분)
hb_gtwiz_reset_all_buf_int: 외부에서 받은 리셋 신호 (리셋 스위치와 같은)
hb_gtwiz_reset_all_init_int: The example initialization module에서 받는 hb_gtwiz_reset_all_init_int 리셋 신호
hb_gtwiz_reset_all_vio_int: Vio에서 사용자가 입력한 리셋 신호
gtwiz_reset_rx_done_out: GTH transceiver의 RX측 리셋을 마치고 동작 여부 (0: 비동작, 1: 동작중)
gtwiz_userclk_tx_active_out: usrclk의 출력의 리셋 상태 (0: Rest, 1: Release)
--------------------- 코드 ---------------------
// ===================================================================================================================
// INITIALIZATION
// ===================================================================================================================
// Declare the receiver reset signals that interface to the reset controller helper block. For this configuration,
// which uses the same PLL type for transmitter and receiver, the "reset RX PLL and datapath" feature is not used.
wire hb_gtwiz_reset_rx_pll_and_datapath_int = 1'b0;
wire hb_gtwiz_reset_rx_datapath_int;
// Declare signals which connect the VIO instance to the initialization module for debug purposes
wire init_done_int;
wire [3:0] init_retry_ctr_int;
// Combine the receiver reset signals form the initialization module and the VIO to drive the appropriate reset
// controller helper block reset input
wire hb_gtwiz_reset_rx_pll_and_datapath_vio_int;
wire hb_gtwiz_reset_rx_datapath_vio_int;
wire hb_gtwiz_reset_rx_datapath_init_int;
assign hb_gtwiz_reset_rx_datapath_int = hb_gtwiz_reset_rx_datapath_init_int || hb_gtwiz_reset_rx_datapath_vio_int;
// The example initialization module interacts with the reset controller helper block and other example design logic
// to retry failed reset attempts in order to mitigate bring-up issues such as initially-unavilable reference clocks
// or data connections. It also resets the receiver in the event of link loss in an attempt to regain link, so please
// note the possibility that this behavior can have the effect of overriding or disturbing user-provided inputs that
// destabilize the data stream. It is a demonstration only and can be modified to suit your system needs.
gtwizard_ultrascale_1_example_init example_init_inst (
// input
.clk_freerun_in (hb_gtwiz_reset_clk_freerun_buf_int), // free running clock input
.reset_all_in (hb_gtwiz_reset_all_int), // used at tx path reset
.tx_init_done_in (gtwiz_reset_tx_done_int), // (Active-High) reset sequence of transceiver primitivesk has completed.
.rx_init_done_in (gtwiz_reset_rx_done_int), // (Active-High) reset sequence of transceiver primitivesk has completed.
.rx_data_good_in (sm_link),
// output
.reset_all_out (hb_gtwiz_reset_all_init_int),
.reset_rx_out (hb_gtwiz_reset_rx_datapath_init_int), // used at rx path reset
.init_done_out (init_done_int),
.retry_ctr_out (init_retry_ctr_int)
);
--------------------- 설명 ---------------------
gtwizard_ultrascale_1_example_init 기능
- tx_init_done_in가 30,000us내에 1이 되는지 모니터링하고 계속 30,000us이후에 0이면 reset_all_out에 1을 출력해 Transceiver에 다시 리셋을 걸어준다.
- rx_init_done_in && rx_data_good_sync(RX측에서 데이터가 잘 도착했다는 신호)가 130,000us내에 1이 되는지 모니터링하고 계속 30,000us이후에 0이면 reset_all_out에 1을 출력해 Transceiver에 다시 리셋을 걸어준다.
- tx_init_done_in과 (rx_init_done_in && rx_data_good_sync) 대기시간은 gtwizard_ultrascale_1_example_init module의 parameter를 조절하여 변경할 수 있다.
- gtwizard_ultrascale_1_example_init module의 4개의 입력 신호(reset_all_in, tx_init_done_in, rx_init_done_in, rx_data_good_in)는 모듈 내부에서 clk_freerun_in과 동기된 신호를 만들어 처리한다.
- gtwizard_ultrascale_1_example_init에서 리셋을 해준 횟수를 retry_ctr_out로 내보낸다.
- Transceiver의 RX, TX리셋이 성공했다면 init_done_out 신호를 1로 만든다.
- reset_all_out은 Transceiver의 gtwiz_reset_all_in로 입력된다.
- reset_rx_out은 Transceiver의 gtwiz_reset_rx_datapath_in로 입력된다.
reset_all_in:
- hb_gtwiz_reset_all_int신호를 받는다.
- hb_gtwiz_reset_all_int는 hb_gtwiz_reset_all_buf_int || hb_gtwiz_reset_all_init_int || hb_gtwiz_reset_all_vio_int 이다.
- hb_gtwiz_reset_all_int 는 Transciver의 gtwiz_reset_all_in 포트와도 연결되어있다.
tx_init_done_in:
- Transceiver의 gtwiz_reset_tx_done_out과 연결되어있다.
- (Active-High) reset sequence of transceiver primitives has completed.
rx_init_done_in:
- Transceiver의 gtwiz_reset_rx_done_out과 연결되어있다.
- (Active-High) reset sequence of transceiver primitives has completed.