217 lines
5.5 KiB
Systemverilog
217 lines
5.5 KiB
Systemverilog
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
|
/*
|
|
|
|
Copyright (c) 2025 FPGA Ninja, LLC
|
|
|
|
Authors:
|
|
- Alex Forencich
|
|
|
|
*/
|
|
|
|
`resetall
|
|
`timescale 1ns / 1ps
|
|
`default_nettype none
|
|
|
|
/*
|
|
* GT TX reset controller for UltraScale/UltraScale+ GTH/GTY
|
|
*/
|
|
module taxi_gt_tx_reset #
|
|
(
|
|
parameter GT_TX_PD = 1'b0,
|
|
parameter GT_TX_QPLL_SEL = 1'b0,
|
|
parameter CNT_W = 8
|
|
)
|
|
(
|
|
input wire logic clk,
|
|
input wire logic rst,
|
|
|
|
/*
|
|
* GT
|
|
*/
|
|
input wire logic gt_txusrclk2,
|
|
output wire logic gt_tx_pd_out,
|
|
output wire logic gt_tx_reset_out,
|
|
input wire logic gt_tx_reset_done_in,
|
|
input wire logic gt_userclk_tx_active_in,
|
|
output wire logic gt_tx_pma_reset_out,
|
|
output wire logic gt_tx_pcs_reset_out,
|
|
input wire logic gt_tx_pma_reset_done_in,
|
|
output wire logic gt_tx_prgdiv_reset_out,
|
|
input wire logic gt_tx_prgdiv_reset_done_in,
|
|
output wire logic gt_tx_qpll_sel_out,
|
|
output wire logic gt_tx_userrdy_out,
|
|
|
|
/*
|
|
* Control/status
|
|
*/
|
|
input wire logic qpll0_lock_in,
|
|
input wire logic qpll1_lock_in,
|
|
input wire logic tx_reset_in = 1'b0,
|
|
output wire logic tx_reset_done_out,
|
|
input wire logic tx_pma_reset_in = 1'b0,
|
|
output wire logic tx_pma_reset_done_out,
|
|
output wire logic tx_prgdiv_reset_done_out,
|
|
input wire logic tx_pcs_reset_in = 1'b0,
|
|
input wire logic tx_pd_in = GT_TX_PD,
|
|
input wire logic tx_qpll_sel_in = GT_TX_QPLL_SEL
|
|
);
|
|
|
|
logic gt_tx_reset_reg = 1'b1;
|
|
logic gt_tx_pma_reset_reg = 1'b0;
|
|
logic gt_tx_pcs_reset_reg = 1'b0;
|
|
|
|
logic gt_tx_prgdiv_reset_reg = 1'b0;
|
|
logic gt_tx_userrdy_reg = 1'b0;
|
|
|
|
logic gt_tx_pd_reg = GT_TX_PD;
|
|
|
|
logic gt_tx_qpll_sel_reg = GT_TX_QPLL_SEL;
|
|
|
|
wire gt_tx_reset_done_sync;
|
|
wire gt_tx_pma_reset_done_sync;
|
|
wire gt_tx_prgdiv_reset_done_sync;
|
|
wire gt_userclk_tx_active_sync;
|
|
|
|
taxi_sync_signal #(
|
|
.WIDTH(4),
|
|
.N(2)
|
|
)
|
|
gt_status_sync_inst (
|
|
.clk(clk),
|
|
.in({gt_tx_reset_done_in, gt_tx_pma_reset_done_in, gt_tx_prgdiv_reset_done_in, gt_userclk_tx_active_in}),
|
|
.out({gt_tx_reset_done_sync, gt_tx_pma_reset_done_sync, gt_tx_prgdiv_reset_done_sync, gt_userclk_tx_active_sync})
|
|
);
|
|
|
|
taxi_sync_signal #(
|
|
.WIDTH(1),
|
|
.N(2)
|
|
)
|
|
gt_ctrl_sync_inst (
|
|
.clk(gt_txusrclk2),
|
|
.in({gt_tx_pd_reg}),
|
|
.out({gt_tx_pd_out})
|
|
);
|
|
|
|
wire tx_reset_sync;
|
|
|
|
taxi_sync_reset #(
|
|
.N(4)
|
|
)
|
|
reset_sync_inst (
|
|
.clk(clk),
|
|
.rst(tx_reset_in),
|
|
.out(tx_reset_sync)
|
|
);
|
|
|
|
localparam [1:0]
|
|
STATE_RESET = 2'd0,
|
|
STATE_WAIT_LOCK = 2'd1,
|
|
STATE_WAIT_USRCLK = 2'd2,
|
|
STATE_DONE = 2'd3;
|
|
|
|
logic [1:0] state_reg = STATE_RESET;
|
|
logic [CNT_W-1:0] tx_reset_cnt_reg = '0;
|
|
logic tx_reset_done_reg = 1'b0;
|
|
|
|
assign gt_tx_reset_out = gt_tx_reset_reg;
|
|
assign gt_tx_pma_reset_out = gt_tx_pma_reset_reg;
|
|
assign gt_tx_pcs_reset_out = gt_tx_pcs_reset_reg;
|
|
assign gt_tx_prgdiv_reset_out = gt_tx_prgdiv_reset_reg;
|
|
assign gt_tx_qpll_sel_out = gt_tx_qpll_sel_reg;
|
|
assign gt_tx_userrdy_out = gt_tx_userrdy_reg;
|
|
|
|
assign tx_reset_done_out = tx_reset_done_reg;
|
|
assign tx_pma_reset_done_out = gt_tx_pma_reset_done_sync;
|
|
assign tx_prgdiv_reset_done_out = gt_tx_prgdiv_reset_done_sync;
|
|
|
|
wire tx_sel_pll_lock = gt_tx_qpll_sel_reg ? qpll1_lock_in : qpll0_lock_in;
|
|
|
|
always_ff @(posedge clk) begin
|
|
gt_tx_reset_reg <= 1'b1;
|
|
gt_tx_pma_reset_reg <= tx_pma_reset_in;
|
|
gt_tx_pcs_reset_reg <= tx_pcs_reset_in;
|
|
|
|
gt_tx_prgdiv_reset_reg <= 1'b1;
|
|
gt_tx_userrdy_reg <= 1'b0;
|
|
|
|
state_reg <= STATE_RESET;
|
|
tx_reset_cnt_reg <= '0;
|
|
tx_reset_done_reg <= 1'b0;
|
|
|
|
case (state_reg)
|
|
STATE_RESET: begin
|
|
gt_tx_reset_reg <= 1'b1;
|
|
gt_tx_prgdiv_reset_reg <= 1'b1;
|
|
gt_tx_userrdy_reg <= 1'b0;
|
|
|
|
gt_tx_pd_reg <= tx_pd_in;
|
|
gt_tx_qpll_sel_reg <= tx_qpll_sel_in;
|
|
|
|
state_reg <= STATE_WAIT_LOCK;
|
|
end
|
|
STATE_WAIT_LOCK: begin
|
|
gt_tx_reset_reg <= 1'b1;
|
|
gt_tx_prgdiv_reset_reg <= 1'b1;
|
|
gt_tx_userrdy_reg <= 1'b0;
|
|
|
|
state_reg <= STATE_WAIT_LOCK;
|
|
if (tx_sel_pll_lock) begin
|
|
// QPLL locked
|
|
tx_reset_cnt_reg <= tx_reset_cnt_reg + 1;
|
|
if (&tx_reset_cnt_reg) begin
|
|
state_reg <= STATE_WAIT_USRCLK;
|
|
end
|
|
end
|
|
end
|
|
STATE_WAIT_USRCLK: begin
|
|
gt_tx_reset_reg <= 1'b0;
|
|
gt_tx_prgdiv_reset_reg <= 1'b0;
|
|
gt_tx_userrdy_reg <= 1'b0;
|
|
|
|
state_reg <= STATE_WAIT_USRCLK;
|
|
if (gt_userclk_tx_active_sync) begin
|
|
// user clock running
|
|
tx_reset_cnt_reg <= tx_reset_cnt_reg + 1;
|
|
if (&tx_reset_cnt_reg) begin
|
|
state_reg <= STATE_DONE;
|
|
end
|
|
end
|
|
end
|
|
STATE_DONE: begin
|
|
gt_tx_reset_reg <= 1'b0;
|
|
gt_tx_prgdiv_reset_reg <= 1'b0;
|
|
gt_tx_userrdy_reg <= 1'b1;
|
|
|
|
tx_reset_done_reg <= gt_tx_reset_done_sync && gt_tx_prgdiv_reset_done_sync;
|
|
|
|
state_reg <= STATE_DONE;
|
|
end
|
|
default: begin
|
|
state_reg <= STATE_RESET;
|
|
end
|
|
endcase
|
|
|
|
if (tx_reset_sync || tx_pd_in || !tx_sel_pll_lock || (gt_tx_qpll_sel_reg != tx_qpll_sel_in)) begin
|
|
state_reg <= STATE_RESET;
|
|
end
|
|
|
|
if (rst) begin
|
|
gt_tx_reset_reg <= 1'b1;
|
|
gt_tx_pma_reset_reg <= 1'b0;
|
|
gt_tx_pcs_reset_reg <= 1'b0;
|
|
|
|
gt_tx_prgdiv_reset_reg <= 1'b1;
|
|
gt_tx_userrdy_reg <= 1'b0;
|
|
|
|
gt_tx_pd_reg <= GT_TX_PD;
|
|
gt_tx_qpll_sel_reg <= GT_TX_QPLL_SEL;
|
|
|
|
state_reg <= STATE_RESET;
|
|
tx_reset_done_reg <= 1'b0;
|
|
end
|
|
end
|
|
|
|
endmodule
|
|
|
|
`resetall
|