📄 phy_calib.v
字号:
reg cal4_dlyce_gate; reg cal4_dlyinc_gate; reg cal4_dlyrst_gate; reg [4:0] cal4_gate_srl_a; reg [5:0] cal4_idel_adj_cnt; reg cal4_idel_adj_inc; reg cal4_idel_bit_tap; reg [5:0] cal4_idel_tap_cnt; reg cal4_idel_max_tap; reg [4:0] cal4_rden_srl_a; reg cal4_ref_req; reg cal4_seek_left; reg cal4_stable_window; reg [2:0] cal4_state; reg [3:0] cal4_window_cnt; reg [3:0] calib_done_tmp; // only for stg1/2/4 reg calib_ctrl_gate_pulse_r; reg calib_ctrl_rden; reg calib_ctrl_rden_r; wire calib_ctrl_rden_negedge; reg calib_ctrl_rden_negedge_r; reg [3:0] calib_done_r; reg [3:0] calib_err; reg [1:0] calib_err_2; wire calib_init_gate_pulse; reg calib_init_gate_pulse_r; reg calib_init_gate_pulse_r1; reg calib_init_rden; reg calib_init_rden_r; reg [4:0] calib_rden_srl_a; wire [4:0] calib_rden_srl_a_r; reg [(5*DQS_WIDTH)-1:0] calib_rden_dly; reg calib_rden_edge_r; reg [4:0] calib_rden_pipe_cnt; wire calib_rden_srl_out; wire calib_rden_srl_out_r; reg calib_rden_srl_out_r1; reg calib_rden_valid; reg calib_rden_valid_stgd; reg [DQ_BITS-1:0] count_dq; reg [DQS_BITS_FIX-1:0] count_dqs; reg [DQS_BITS_FIX-1:0] count_gate; reg [DQS_BITS_FIX-1:0] count_rden; reg ctrl_rden_r; wire dlyce_or; reg [(5*DQS_WIDTH)-1:0] gate_dly; wire [(5*DQS_WIDTH)-1:0] gate_dly_r; wire gate_srl_in; wire [DQS_WIDTH-1:0] gate_srl_out; wire [DQS_WIDTH-1:0] gate_srl_out_r; reg [2:0] idel_set_cnt; wire idel_set_wait; reg [DQ_BITS-1:0] next_count_dq; reg [DQS_BITS_FIX-1:0] next_count_dqs; reg [DQS_BITS_FIX-1:0] next_count_gate; reg phy_init_rden_r; reg phy_init_rden_r1; reg [DQ_WIDTH-1:0] rd_data_fall_1x_r; reg [DQS_WIDTH-1:0] rd_data_fall_1x_r1; reg [DQS_WIDTH-1:0] rd_data_fall_2x_r; wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1; wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2; reg [DQ_WIDTH-1:0] rd_data_rise_1x_r; reg [DQS_WIDTH-1:0] rd_data_rise_1x_r1; reg [DQS_WIDTH-1:0] rd_data_rise_2x_r; wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1; wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2; reg rdd_fall_q1; reg rdd_fall_q1_r; reg rdd_fall_q1_r1; reg rdd_fall_q2; reg rdd_fall_q2_r; reg rdd_rise_q1; reg rdd_rise_q1_r; reg rdd_rise_q1_r1; reg rdd_rise_q2; reg rdd_rise_q2_r; reg [DQS_BITS_FIX-1:0] rdd_mux_sel; reg rden_dec; reg [(5*DQS_WIDTH)-1:0] rden_dly; wire [(5*DQS_WIDTH)-1:0] rden_dly_r; reg [4:0] rden_dly_0; reg rden_inc; reg [DQS_WIDTH-1:0] rden_mux; wire [DQS_WIDTH-1:0] rden_srl_out; // Debug integer x; reg [5:0] dbg_dq_tap_cnt [DQ_WIDTH-1:0]; reg [5:0] dbg_dqs_tap_cnt [DQS_WIDTH-1:0]; reg [5:0] dbg_gate_tap_cnt [DQS_WIDTH-1:0]; //*************************************************************************** // Debug output ("dbg_phy_calib_*") // NOTES: // 1. All debug outputs coming out of PHY_CALIB are clocked off CLKDIV0, // although they are also static after calibration is complete. This // means the user can either connect them to a Chipscope ILA, or to // either a sync/async VIO input block. Using an async VIO has the // advantage of not requiring these paths to meet cycle-to-cycle timing. // 2. The widths of most of these debug buses are dependent on the # of // DQS/DQ bits (e.g. dq_tap_cnt width = 6 * (# of DQ bits) // SIGNAL DESCRIPTION: // 1. calib_done: 4 bits - each one asserted as each phase of calibration // is completed. // 2. calib_err: 4 bits - each one asserted when a calibration error // encountered for that stage. Some of these bits may not // be used (not all cal stages report an error). // 3. dq_tap_cnt: final IDELAY tap counts for all DQ IDELAYs // 4. dqs_tap_cnt: final IDELAY tap counts for all DQS IDELAYs // 5. gate_tap_cnt: final IDELAY tap counts for all DQS gate // synchronization IDELAYs // 6. rd_data_sel: final read capture MUX (either "positive" or "negative" // edge capture) settings for all DQS groups // 7. rden_dly: related to # of cycles after issuing a read until when // read data is valid - for all DQS groups // 8. gate_dly: related to # of cycles after issuing a read until when // clock enable for all DQ's is deasserted to prevent // effect of DQS postamble glitch - for all DQS groups //*************************************************************************** //***************************************************************** // Record IDELAY tap values by "snooping" IDELAY control signals //***************************************************************** // record DQ IDELAY tap values genvar dbg_dq_tc_i; generate for (dbg_dq_tc_i = 0; dbg_dq_tc_i < DQ_WIDTH; dbg_dq_tc_i = dbg_dq_tc_i + 1) begin: gen_dbg_dq_tap_cnt assign dbg_calib_dq_tap_cnt[(6*dbg_dq_tc_i)+5:(6*dbg_dq_tc_i)] = dbg_dq_tap_cnt[dbg_dq_tc_i]; always @(posedge clkdiv) if (rstdiv | dlyrst_dq) dbg_dq_tap_cnt[dbg_dq_tc_i] <= 6'b000000; else if (dlyce_dq[dbg_dq_tc_i]) if (dlyinc_dq[dbg_dq_tc_i]) dbg_dq_tap_cnt[dbg_dq_tc_i] <= dbg_dq_tap_cnt[dbg_dq_tc_i] + 1; else dbg_dq_tap_cnt[dbg_dq_tc_i] <= dbg_dq_tap_cnt[dbg_dq_tc_i] - 1; end endgenerate // record DQS IDELAY tap values genvar dbg_dqs_tc_i; generate for (dbg_dqs_tc_i = 0; dbg_dqs_tc_i < DQS_WIDTH; dbg_dqs_tc_i = dbg_dqs_tc_i + 1) begin: gen_dbg_dqs_tap_cnt assign dbg_calib_dqs_tap_cnt[(6*dbg_dqs_tc_i)+5:(6*dbg_dqs_tc_i)] = dbg_dqs_tap_cnt[dbg_dqs_tc_i]; always @(posedge clkdiv) if (rstdiv | dlyrst_dqs) dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= 6'b000000; else if (dlyce_dqs[dbg_dqs_tc_i]) if (dlyinc_dqs[dbg_dqs_tc_i]) dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] + 1; else dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] - 1; end endgenerate // record DQS gate IDELAY tap values genvar dbg_gate_tc_i; generate for (dbg_gate_tc_i = 0; dbg_gate_tc_i < DQS_WIDTH; dbg_gate_tc_i = dbg_gate_tc_i + 1) begin: gen_dbg_gate_tap_cnt assign dbg_calib_gate_tap_cnt[(6*dbg_gate_tc_i)+5:(6*dbg_gate_tc_i)] = dbg_gate_tap_cnt[dbg_gate_tc_i]; always @(posedge clkdiv) if (rstdiv | dlyrst_gate[dbg_gate_tc_i]) dbg_gate_tap_cnt[dbg_gate_tc_i] <= 6'b000000; else if (dlyce_gate[dbg_gate_tc_i]) if (dlyinc_gate[dbg_gate_tc_i]) dbg_gate_tap_cnt[dbg_gate_tc_i] <= dbg_gate_tap_cnt[dbg_gate_tc_i] + 1; else dbg_gate_tap_cnt[dbg_gate_tc_i] <= dbg_gate_tap_cnt[dbg_gate_tc_i] - 1; end endgenerate assign dbg_calib_done = calib_done; assign dbg_calib_err = calib_err; assign dbg_calib_rd_data_sel = cal2_rd_data_sel; assign dbg_calib_rden_dly = rden_dly; assign dbg_calib_gate_dly = gate_dly; //*************************************************************************** // Read data pipelining, and read data "ISERDES" data width expansion //*************************************************************************** // For all data bits, register incoming capture data to slow clock to improve // timing. Adding single pipeline stage does not affect functionality (as // long as we make sure to wait extra clock cycle after changing DQ IDELAY) // Also note in this case that we're "missing" every other clock cycle's // worth of data capture since we're sync'ing to the slow clock. This is // fine for stage 1 and stage 2 cal, but not for stage 3 and 4 (see below // for different circuit to handle those stages) always @(posedge clkdiv) begin rd_data_rise_1x_r <= rd_data_rise; rd_data_fall_1x_r <= rd_data_fall; end // For every DQ_PER_DQS bit, generate what is essentially a ISERDES-type // data width expander. Will need this for stage 3 and 4 cal, where we need // to compare data over consecutive clock cycles. We can also use this for // stage 2 as well (stage 2 doesn't require every bit to be looked at, only // one bit per DQS group) genvar rdd_i; generate for (rdd_i = 0; rdd_i < DQS_WIDTH; rdd_i = rdd_i + 1) begin: gen_rdd // first stage: keep data in fast clk domain. Store data over two // consecutive clock cycles for rise/fall data for proper transfer // to slow clock domain always @(posedge clk) begin rd_data_rise_2x_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)]; rd_data_fall_2x_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)]; end // second stage, register first stage to slow clock domain, 2nd stage // consists of both these flops, and the rd_data_rise_1x_r flops always @(posedge clkdiv) begin rd_data_rise_1x_r1[rdd_i] <= rd_data_rise_2x_r[rdd_i]; rd_data_fall_1x_r1[rdd_i] <= rd_data_fall_2x_r[rdd_i]; end // now we have four outputs - representing rise/fall outputs over last // 2 fast clock cycles. However, the ordering these represent can either // be: (1) Q2 = data @ time = n, Q1 = data @ time = n+1, or (2) // Q2 = data @ time = n - 1, Q1 = data @ time = n (and data at [Q1,Q2] // is "staggered") - leave it up to the stage of calibration using this // to figure out which is which, if they care at all (e.g. stage 2 cal // doesn't care about the ordering) assign rd_data_rise_chk_q1[rdd_i] = rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)]; assign rd_data_rise_chk_q2[rdd_i] = rd_data_rise_1x_r1[rdd_i]; assign rd_data_fall_chk_q1[rdd_i] = rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)]; assign rd_data_fall_chk_q2[rdd_i] = rd_data_fall_1x_r1[rdd_i]; end endgenerate //***************************************************************** // Outputs of these simplified ISERDES circuits then feed MUXes based on // which DQ the current calibration algorithm needs to look at //***************************************************************** // generate MUX control; assume that adding an extra pipeline stage isn't // an issue - whatever stage cal logic is using output of MUX will wait // enough time after changing it always @(posedge clkdiv) begin (* full_case, parallel_case *) case (calib_done[2:0]) 3'b001: rdd_mux_sel <= next_count_dqs; 3'b011: rdd_mux_sel <= count_rden; 3'b111: rdd_mux_sel <= next_count_gate; endcase end always @(posedge clkdiv) begin rdd_rise_q1 <= rd_data_rise_chk_q1[rdd_mux_sel]; rdd_rise_q2 <= rd_data_rise_chk_q2[rdd_mux_sel]; rdd_fall_q1 <= rd_data_fall_chk_q1[rdd_mux_sel]; rdd_fall_q2 <= rd_data_fall_chk_q2[rdd_mux_sel]; end //*************************************************************************** // Demultiplexor to control (reset, increment, decrement) IDELAY tap values // For DQ: // STG1: for per-bit-deskew, only inc/dec the current DQ. For non-per // deskew, increment all bits in the current DQS set // STG2: inc/dec all DQ's in the current DQS set. // NOTE: Nice to add some error checking logic here (or elsewhere in the // code) to check if logic attempts to overflow tap value //***************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -