⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phy_calib.v

📁 DDR2源代码 DDR2源代码 DDR2源代码
💻 V
📖 第 1 页 / 共 5 页
字号:
  // don't use DLYRST to reset value of IDELAY after reset. Need to change this  // if we want to allow user to recalibrate after initial reset  always @(posedge clkdiv)    if (rstdiv) begin      dlyrst_dq <= 1'b1;      dlyrst_dqs <= 1'b1;    end else begin      dlyrst_dq <= 1'b0;      dlyrst_dqs <= 1'b0;    end  always @(posedge clkdiv) begin    if (rstdiv) begin      dlyce_dq   <= 'b0;      dlyinc_dq  <= 'b0;      dlyce_dqs  <= 'b0;      dlyinc_dqs <= 'b0;    end else begin      dlyce_dq   <= 'b0;      dlyinc_dq  <= 'b0;      dlyce_dqs  <= 'b0;      dlyinc_dqs <= 'b0;      // stage 1 cal: change only specified DQ      if (cal1_dlyce_dq) begin        if (SIM_ONLY == 0) begin          dlyce_dq[count_dq] <= 1'b1;          dlyinc_dq[count_dq] <= cal1_dlyinc_dq;        end else begin          // if simulation, then calibrate only first DQ, apply results          // to all DQs (i.e. assume delay on all DQs is the same)          for (i = 0; i < DQ_WIDTH; i = i + 1) begin: loop_sim_dq_dly            dlyce_dq[i] <= 1'b1;            dlyinc_dq[i] <= cal1_dlyinc_dq;          end        end      end else if (cal2_dlyce_dqs) begin        // stage 2 cal: change DQS and all corresponding DQ's        if (SIM_ONLY == 0) begin          dlyce_dqs[count_dqs] <= 1'b1;          dlyinc_dqs[count_dqs] <= cal2_dlyinc_dqs;          for (i = 0; i < DQ_PER_DQS; i = i + 1) begin: loop_dqs_dly            dlyce_dq[(DQ_PER_DQS*count_dqs)+i] <= 1'b1;            dlyinc_dq[(DQ_PER_DQS*count_dqs)+i] <= cal2_dlyinc_dqs;          end        end else begin          for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_dqs_dly            // if simulation, then calibrate only first DQS            dlyce_dqs[i] <= 1'b1;            dlyinc_dqs[i] <= cal2_dlyinc_dqs;            for (j = 0; j < DQ_PER_DQS; j = j + 1) begin: loop_sim_dq_dqs_dly              dlyce_dq[(DQ_PER_DQS*i)+j] <= 1'b1;              dlyinc_dq[(DQ_PER_DQS*i)+j] <= cal2_dlyinc_dqs;            end          end        end      end else if (DEBUG_EN != 0) begin        // DEBUG: allow user to vary IDELAY tap settings        // For DQ IDELAY taps        if (dbg_idel_up_all || dbg_idel_down_all ||            dbg_sel_all_idel_dq) begin          for (x = 0; x < DQ_WIDTH; x = x + 1) begin: loop_dly_inc_dq            dlyce_dq[x] <= dbg_idel_up_all | dbg_idel_down_all |                           dbg_idel_up_dq  | dbg_idel_down_dq;            dlyinc_dq[x] <= dbg_idel_up_all | dbg_idel_up_dq;          end        end else begin          dlyce_dq <= 'b0;          dlyce_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq |                                       dbg_idel_down_dq;          dlyinc_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq;        end        // For DQS IDELAY taps        if (dbg_idel_up_all || dbg_idel_down_all ||            dbg_sel_all_idel_dqs) begin          for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_dqs            dlyce_dqs[x] <= dbg_idel_up_all | dbg_idel_down_all |                            dbg_idel_up_dqs | dbg_idel_down_dqs;            dlyinc_dqs[x] <= dbg_idel_up_all | dbg_idel_up_dqs;          end        end else begin          dlyce_dqs <= 'b0;          dlyce_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs |                                         dbg_idel_down_dqs;          dlyinc_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs;        end      end    end  end  // GATE synchronization is handled directly by Stage 4 calibration FSM  always @(posedge clkdiv)    if (rstdiv) begin      dlyrst_gate <= {DQS_WIDTH{1'b1}};      dlyce_gate  <= {DQS_WIDTH{1'b0}};      dlyinc_gate <= {DQS_WIDTH{1'b0}};    end else begin      dlyrst_gate <= {DQS_WIDTH{1'b0}};      dlyce_gate  <= {DQS_WIDTH{1'b0}};      dlyinc_gate <= {DQS_WIDTH{1'b0}};      if (cal4_dlyrst_gate) begin        if (SIM_ONLY == 0)          dlyrst_gate[count_gate] <= 1'b1;        else          for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly_rst            dlyrst_gate[i] <= 1'b1;          end      end      if (cal4_dlyce_gate) begin        if (SIM_ONLY == 0) begin          dlyce_gate[count_gate]  <= 1'b1;          dlyinc_gate[count_gate] <= cal4_dlyinc_gate;        end else begin          // if simulation, then calibrate only first gate          for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly            dlyce_gate[i]  <= 1'b1;            dlyinc_gate[i] <= cal4_dlyinc_gate;          end        end      end else if (DEBUG_EN != 0) begin        // DEBUG: allow user to vary IDELAY tap settings        if (dbg_idel_up_all || dbg_idel_down_all ||            dbg_sel_all_idel_gate) begin          for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_gate            dlyce_gate[x] <= dbg_idel_up_all | dbg_idel_down_all |                             dbg_idel_up_gate | dbg_idel_down_gate;            dlyinc_gate[x] <= dbg_idel_up_all | dbg_idel_up_gate;          end        end else begin          dlyce_gate <= {DQS_WIDTH{1'b0}};          dlyce_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate |                                           dbg_idel_down_gate;          dlyinc_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate;        end      end    end  //***************************************************************************  // signal to tell calibration state machines to wait and give IDELAY time to  // settle after it's value is changed (both time for IDELAY chain to settle,  // and for settled output to propagate through ISERDES). For general use: use  // for any calibration state machines that modify any IDELAY.  // Should give at least enough time for IDELAY output to settle (technically  // for V5, this should be "glitchless" when IDELAY taps are changed, so don't  // need any time here), and also time for new data to propagate through both  // ISERDES and the "RDD" MUX + associated pipelining  // For now, give very "generous" delay - doesn't really matter since only  // needed during calibration  //***************************************************************************  // determine if calibration polarity has changed  always @(posedge clkdiv)    cal2_rd_data_sel_r   <= cal2_rd_data_sel;  assign cal2_rd_data_sel_edge = |(cal2_rd_data_sel ^ cal2_rd_data_sel_r);  // combine requests to modify any of the IDELAYs into one. Also when second  // stage capture "edge" polarity is changed (IDELAY isn't changed in this  // case, but use the same counter to stall cal logic)  assign dlyce_or = cal1_dlyce_dq |                    cal2_dlyce_dqs |                    cal2_rd_data_sel_edge |                    cal4_dlyce_gate |                    cal4_dlyrst_gate;  // SYN_NOTE: Can later recode to avoid combinational path  assign idel_set_wait = dlyce_or || (idel_set_cnt != IDEL_SET_VAL);  always @(posedge clkdiv)    if (rstdiv)      idel_set_cnt <= 4'b0000;    else if (dlyce_or)      idel_set_cnt <= 4'b0000;    else if (idel_set_cnt != IDEL_SET_VAL)      idel_set_cnt <= idel_set_cnt + 1;  // generate request to PHY_INIT logic to issue auto-refresh  // used by certain states to force prech/auto-refresh part way through  // calibration to avoid a tRAS violation (which will happen if that  // stage of calibration lasts long enough). This signal must meet the  // following requirements: (1) only transition from 0->1 when the refresh  // request is needed, (2) stay at 1 and only transition 1->0 when  // CALIB_REF_DONE is asserted  always @(posedge clkdiv)    if (rstdiv)      calib_ref_req <= 1'b0;    else      calib_ref_req <= cal1_ref_req | cal2_ref_req  | cal4_ref_req;  // stage 1 calibration requests auto-refresh every 4 bits  generate    if (DQ_BITS < 2) begin: gen_cal1_refresh_dq_lte4      assign cal1_refresh = 1'b0;    end else begin: gen_cal1_refresh_dq_gt4      assign cal1_refresh = (next_count_dq[1:0] == 2'b00);    end  endgenerate  //***************************************************************************  // First stage calibration: DQ-DQS  // Definitions:  //  edge: detected when varying IDELAY, and current capture data != prev  //    capture data  //  valid bit window: detected when current capture data == prev capture  //    data for more than half the bit time  //  starting conditions for DQS-DQ phase:  //    case 1: when DQS starts somewhere in rising edge bit window, or  //      on the right edge of the rising bit window.  //    case 2: when DQS starts somewhere in falling edge bit window, or  //      on the right edge of the falling bit window.  // Algorithm Description:  //  1. Increment DQ IDELAY until we find an edge.  //  2. While we're finding the first edge, note whether a valid bit window  //     has been detected before we found an edge. If so, then figure out if  //     this is the rising or falling bit window. If rising, then our starting  //     DQS-DQ phase is case 1. If falling, then it's case 2. If don't detect  //     a valid bit window, then we must have started on the edge of a window.  //     Need to wait until later on to decide which case we are.  //       - Store FIRST_EDGE IDELAY value  //  3. Now look for second edge.  //  4. While we're finding the second edge, note whether valid bit window  //     is detected. If so, then use to, along with results from (2) to figure  //     out what the starting case is. If in rising bit window, then we're in  //     case 2. If falling, then case 1.  //       - Store SECOND_EDGE IDELAY value  //     NOTES:  //       a. Finding two edges allows us to calculate the bit time (although  //          not the "same" bit time polarity - need to investigate this  //          more).  //       b. If we run out of taps looking for the second edge, then the bit  //       time must be too long (>= 2.5ns, and DQS-DQ starting phase must be  //       case 1).  //  5. Calculate absolute amount to delay DQ as:  //       If second edge found, and case 1:  //         - DQ_IDELAY = FIRST_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE)  //       If second edge found, and case 2:  //         - DQ_IDELAY = SECOND_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE)  //       If second edge not found, then need to make an approximation on  //       how much to shift by (should be okay, because we have more timing  //       margin):  //         - DQ_IDELAY = FIRST_EDGE - 0.5 * (bit_time)  //     NOTE: Does this account for either case 1 or case 2?????  //     NOTE: It's also possible even when we find the second edge, that  //           to instead just use half the bit time to subtract from either  //           FIRST or SECOND_EDGE. Finding the actual bit time (which is  //           what (SECOND_EDGE - FIRST_EDGE) is, is slightly more accurate,  //           since it takes into account duty cycle distortion.  //  6. Repeat for each DQ in current DQS set.  //***************************************************************************  //*****************************************************************  // for first stage calibration - used for checking if DQS is aligned to the  // particular DQ, such that we're in the data valid window. Basically, this  // is one giant MUX.  //  = [falling data, rising data]  //  = [0, 1] = rising DQS aligned in proper (rising edge) bit window  //  = [1, 0] = rising DQS aligned in wrong (falling edge) bit window  //  = [0, 0], or [1,1] = in uncertain region between windows  //*****************************************************************  // SYN_NOTE: May have to split this up into multiple levels - MUX can get  //  very wide - as wide as the data bus width  always @(posedge clkdiv)    cal1_data_chk_r <= {rd_data_fall_1x_r[next_count_dq],                       rd_data_rise_1x_r[next_count_dq]};  //*****************************************************************  // determine when an edge has occurred - when either the current value  // is different from the previous latched value or when the DATA_CHK  // outputs are the same (rare, but indicates that we're at an edge)  // This is only valid when the IDELAY output and propagation of the  // data through the capture flops has had a chance to settle out.  //*****************************************************************  // write CAL1_DETECT_EDGE and CAL1_DETECT_STABLE in such a way that  // if X's are captured on the bus during functional simulation, that  // the logic will register this as an edge detected. Do this to allow  // use of this HDL with Denali memory models (Denali models drive DQ  // to X's on both edges of the data valid window to simulate jitter)  // This is only done for functional simulation purposes. **Should not**

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -