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

📄 phy_calib.v

📁 DDR2源代码 DDR2源代码 DDR2源代码
💻 V
📖 第 1 页 / 共 5 页
字号:
  // make the final synthesized logic more complicated, but it does make  // the HDL harder to understand b/c we have to "phrase" the logic  // slightly differently than when not worrying about X's  always @(*) begin    // no edge found if: (1) we have recorded prev edge, and rise    // data == fall data, (2) we haven't yet recorded prev edge, but    // rise/fall data is equal to either [0,1] or [1,0] (i.e. rise/fall    // data isn't either X's, or [0,0] or [1,1], which indicates we're    // in the middle of an edge, since normally rise != fall data for stg1)    if ((cal1_data_chk_last_valid &&         (cal1_data_chk_r == cal1_data_chk_last)) ||        (!cal1_data_chk_last_valid &&         ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10))))      cal1_detect_edge = 1'b0;    else      cal1_detect_edge = 1'b1;  end  always @(*) begin    // assert if we've found a region where data valid window is stable    // over consecutive IDELAY taps, and either rise/fall = [1,0], or [0,1]    if ((cal1_data_chk_last_valid &&         (cal1_data_chk_r == cal1_data_chk_last)) &&        ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10)))      cal1_detect_stable <= 1'b1;    else      cal1_detect_stable <= 1'b0;  end  //*****************************************************************  // Find valid window: keep track of how long we've been in the same data  // window. If it's been long enough, then declare that we've found a valid  // window. Also returns whether we found a rising or falling window (only  // valid when found_window is asserted)  //*****************************************************************  always @(posedge clkdiv) begin    if (cal1_state == CAL1_INIT) begin      cal1_window_cnt   <= 4'b0000;      cal1_found_window <= 1'b0;      cal1_found_rising <= 1'bx;    end else if (!cal1_data_chk_last_valid) begin      // if we haven't stored a previous value of CAL1_DATA_CHK (or it got      // invalidated because we detected an edge, and are now looking for the      // second edge), then make sure FOUND_WINDOW deasserted on following      // clock edge (to avoid finding a false window immediately after finding      // an edge). Note that because of jitter, it's possible to not find an      // edge at the end of the IDELAY increment settling time, but to find an      // edge on the next clock cycle (e.g. during CAL1_FIND_FIRST_EDGE)      cal1_window_cnt   <= 4'b0000;      cal1_found_window <= 1'b0;      cal1_found_rising <= 1'bx;    end else if (((cal1_state == CAL1_FIRST_EDGE_IDEL_WAIT) ||                  (cal1_state == CAL1_SECOND_EDGE_IDEL_WAIT)) &&                 !idel_set_wait) begin      // while finding the first and second edges, see if we can detect a      // stable bit window (occurs over MIN_WIN_SIZE number of taps). If      // so, then we're away from an edge, and can conclusively determine the      // starting DQS-DQ phase.      if (cal1_detect_stable) begin        cal1_window_cnt <= cal1_window_cnt + 1;        if (cal1_window_cnt == MIN_WIN_SIZE-1) begin          cal1_found_window <= 1'b1;          if (cal1_data_chk_r == 2'b01)            cal1_found_rising <= 1'b1;          else            cal1_found_rising <= 1'b0;        end      end else begin        // otherwise, we're not in a data valid window, reset the window        // counter, and indicate we're not currently in window. This should        // happen by design at least once after finding the first edge.        cal1_window_cnt <= 4'b0000;        cal1_found_window <= 1'b0;        cal1_found_rising <= 1'bx;      end    end  end  //*****************************************************************  // keep track of edge tap counts found, and whether we've  // incremented to the maximum number of taps allowed  //*****************************************************************  always @(posedge clkdiv)    if (cal1_state == CAL1_INIT) begin      cal1_idel_tap_limit_hit   <= 1'b0;      cal1_idel_tap_cnt   <= 6'b000000;    end else if (cal1_dlyce_dq) begin      if (cal1_dlyinc_dq) begin        cal1_idel_tap_cnt <= cal1_idel_tap_cnt + 1;        cal1_idel_tap_limit_hit <= (cal1_idel_tap_cnt == 6'b111110);      end else begin        cal1_idel_tap_cnt <= cal1_idel_tap_cnt - 1;        cal1_idel_tap_limit_hit <= 1'b0;      end    end  //*****************************************************************  // Pipeline for better timing - amount to decrement by if second  // edge not found  //*****************************************************************  // if only one edge found (possible for low frequencies), then:  //  1. Assume starting DQS-DQ phase has DQS in DQ window (aka "case 1")  //  2. We have to decrement by (63 - first_edge_tap_cnt) + (BIT_TIME_TAPS/2)  //     (i.e. decrement by 63-first_edge_tap_cnt to get to right edge of  //     DQ window. Then decrement again by (BIT_TIME_TAPS/2) to get to center  //     of DQ window.  //  3. Clamp the above value at 63 to ensure we don't underflow IDELAY  //     (note: clamping happens in the CAL1 state machine)  always @(posedge clkdiv)    cal1_low_freq_idel_dec      <= (7'b0111111 - {1'b0, cal1_first_edge_tap_cnt}) +         (BIT_TIME_TAPS/2);  //*****************************************************************  // Keep track of max taps used during stage 1, use this to limit  // the number of taps that can be used in stage 2  //*****************************************************************  always @(posedge clkdiv)    if (rstdiv) begin      cal1_idel_max_tap    <= 6'b000000;      cal1_idel_max_tap_we <= 1'b0;    end else begin      // pipeline latch enable for CAL1_IDEL_MAX_TAP - we have plenty      // of time, tap count gets updated, then dead cycles waiting for      // IDELAY output to settle      cal1_idel_max_tap_we <= (cal1_idel_max_tap < cal1_idel_tap_cnt);      // record maximum # of taps used for stg 1 cal      if ((cal1_state == CAL1_DONE) && cal1_idel_max_tap_we)        cal1_idel_max_tap <= cal1_idel_tap_cnt;    end  //*****************************************************************  always @(posedge clkdiv)    if (rstdiv) begin      calib_done[0]            <= 1'b0;      calib_done_tmp[0]        <= 1'bx;      calib_err[0]             <= 1'b0;      count_dq                 <= {DQ_BITS{1'b0}};      next_count_dq            <= {DQ_BITS{1'b0}};      cal1_bit_time_tap_cnt    <= 6'bxxxxxx;      cal1_data_chk_last       <= 2'bxx;      cal1_data_chk_last_valid <= 1'bx;      cal1_dlyce_dq            <= 1'b0;      cal1_dlyinc_dq           <= 1'b0;      cal1_dqs_dq_init_phase   <= 1'bx;      cal1_first_edge_done     <= 1'bx;      cal1_found_second_edge   <= 1'bx;      cal1_first_edge_tap_cnt  <= 6'bxxxxxx;      cal1_idel_dec_cnt        <= 7'bxxxxxxx;      cal1_idel_inc_cnt        <= 6'bxxxxxx;      cal1_ref_req             <= 1'b0;      cal1_state               <= CAL1_IDLE;    end else begin      // default values for all "pulse" outputs      cal1_ref_req        <= 1'b0;      cal1_dlyce_dq       <= 1'b0;      cal1_dlyinc_dq      <= 1'b0;      case (cal1_state)        CAL1_IDLE: begin          count_dq      <= {DQ_BITS{1'b0}};          next_count_dq <= {DQ_BITS{1'b0}};          if (calib_start[0]) begin            calib_done[0] <= 1'b0;            calib_done_tmp[0] <= 1'b0;            cal1_state    <= CAL1_INIT;          end        end        CAL1_INIT: begin          cal1_data_chk_last_valid <= 1'b0;          cal1_found_second_edge <= 1'b0;          cal1_dqs_dq_init_phase <= 1'b0;          cal1_idel_inc_cnt      <= 6'b000000;          cal1_state <= CAL1_INC_IDEL;        end        // increment DQ IDELAY so that either: (1) DQS starts somewhere in        // first rising DQ window, or (2) DQS starts in first falling DQ        // window. The amount to shift is frequency dependent (and is either        // precalculated by MIG or possibly adjusted by the user)        CAL1_INC_IDEL:          if ((cal1_idel_inc_cnt == DQ_IDEL_INIT) && !idel_set_wait) begin            cal1_state <= CAL1_FIND_FIRST_EDGE;          end else if (cal1_idel_inc_cnt != DQ_IDEL_INIT) begin            cal1_idel_inc_cnt <= cal1_idel_inc_cnt + 1;            cal1_dlyce_dq <= 1'b1;            cal1_dlyinc_dq <= 1'b1;          end        // look for first edge        CAL1_FIND_FIRST_EDGE: begin          // Determine DQS-DQ phase if we can detect enough of a valid window          if (cal1_found_window)            cal1_dqs_dq_init_phase <= ~cal1_found_rising;          // find first edge - if found then record position          if (cal1_detect_edge) begin            cal1_state <= CAL1_FOUND_FIRST_EDGE_WAIT;            cal1_first_edge_done   <= 1'b0;            cal1_first_edge_tap_cnt <= cal1_idel_tap_cnt;            cal1_data_chk_last_valid <= 1'b0;          end else begin            // otherwise, store the current value of DATA_CHK, increment            // DQ IDELAY, and compare again            cal1_state <= CAL1_FIRST_EDGE_IDEL_WAIT;            cal1_data_chk_last <= cal1_data_chk_r;            // avoid comparing against DATA_CHK_LAST for previous iteration            cal1_data_chk_last_valid <= 1'b1;            cal1_dlyce_dq <= 1'b1;            cal1_dlyinc_dq <= 1'b1;          end        end        // wait for DQ IDELAY to settle        CAL1_FIRST_EDGE_IDEL_WAIT:          if (!idel_set_wait)            cal1_state <= CAL1_FIND_FIRST_EDGE;        // delay state between finding first edge and looking for second        // edge. Necessary in order to invalidate CAL1_FOUND_WINDOW before        // starting to look for second edge        CAL1_FOUND_FIRST_EDGE_WAIT:          cal1_state <= CAL1_FIND_SECOND_EDGE;        // Try and find second edge        CAL1_FIND_SECOND_EDGE: begin          // When looking for 2nd edge, first make sure data stabilized (by          // detecting valid data window) - needed to avoid false edges          if (cal1_found_window) begin            cal1_first_edge_done <= 1'b1;            cal1_dqs_dq_init_phase <= cal1_found_rising;          end          // exit if run out of taps to increment          if (cal1_idel_tap_limit_hit)            cal1_state <= CAL1_CALC_IDEL;          else begin            // found second edge, record the current edge count            if (cal1_first_edge_done && cal1_detect_edge) begin              cal1_state <= CAL1_CALC_IDEL;              cal1_found_second_edge <= 1'b1;              cal1_bit_time_tap_cnt <= cal1_idel_tap_cnt -                                       cal1_first_edge_tap_cnt + 1;            end else begin              cal1_state <= CAL1_SECOND_EDGE_IDEL_WAIT;              cal1_data_chk_last <= cal1_data_chk_r;              cal1_data_chk_last_valid <= 1'b1;              cal1_dlyce_dq <= 1'b1;              cal1_dlyinc_dq <= 1'b1;            end          end        end        // wait for DQ IDELAY to settle, then store ISERDES output        CAL1_SECOND_EDGE_IDEL_WAIT:          if (!idel_set_wait)            cal1_state <= CAL1_FIND_SECOND_EDGE;        // pipeline delay state to calculate amount to decrement DQ IDELAY        // NOTE: We're calculating the amount to decrement by, not the        //  absolute setting for DQ IDELAY        CAL1_CALC_IDEL: begin          // if two edges found          if (cal1_found_second_edge)            // case 1: DQS was in DQ window to start with. First edge found            // corresponds to left edge of DQ rising window. Backup by 1.5*BT            // NOTE: In this particular case, it is possible to decrement            //  "below 0" in the case where DQS delay is less than 0.5*BT,            //  need to limit decrement to prevent IDELAY tap underflow            if (!cal1_dqs_dq_init_phase)              cal1_idel_dec_cnt <= {1'b0, cal1_bit_time_tap_cnt} +                                   {1'b0, (cal1_bit_time_tap_cnt >> 1)};            // case 2: DQS was in wrong DQ window (in DQ falling window).            // First edge found is right edge of DQ rising window. Second            // edge is left edge of DQ rising window. Backup by 0.5*BT            else              cal1_idel_dec_cnt <= {1'b0, (cal1_bit_time_tap_cnt >> 1)};          // if only one edge found - assume will always be case 1 - DQS in          // DQS window. Case 2 only possible if path delay on DQS > 5ns

⌨️ 快捷键说明

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