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

📄 phy_calib.v

📁 DDR2源代码 DDR2源代码 DDR2源代码
💻 V
📖 第 1 页 / 共 5 页
字号:
          else            cal1_idel_dec_cnt <= cal1_low_freq_idel_dec;          cal1_state <= CAL1_DEC_IDEL;        end        // decrement DQ IDELAY for final adjustment        CAL1_DEC_IDEL:          // once adjustment is complete, we're done with calibration for          // this DQ, now return to IDLE state and repeat for next DQ          // Add underflow protection for case of 2 edges found and DQS          // starting in DQ window (see comments for above state) - note we          // have to take into account delayed value of CAL1_IDEL_TAP_CNT -          // gets updated one clock cycle after CAL1_DLYCE/INC_DQ          if ((cal1_idel_dec_cnt == 7'b0000000) ||              (cal1_dlyce_dq && (cal1_idel_tap_cnt == 6'b000001))) begin            cal1_state <= CAL1_DONE;            // stop when all DQ's calibrated, or DQ[0] cal'ed (for sim)            if ((count_dq == DQ_WIDTH-1) || (SIM_ONLY != 0))              calib_done_tmp[0] <= 1'b1;            else              // need for VHDL simulation to prevent out-of-index error              next_count_dq <= count_dq + 1;          end else begin            // keep decrementing until final tap count reached            cal1_idel_dec_cnt <= cal1_idel_dec_cnt - 1;            cal1_dlyce_dq <= 1'b1;            cal1_dlyinc_dq <= 1'b0;          end        // delay state to allow count_dq and DATA_CHK to point to the next        // DQ bit (allows us to potentially begin checking for an edge on        // next DQ right away).        CAL1_DONE:          if (!idel_set_wait) begin            count_dq <= next_count_dq;            if (calib_done_tmp[0]) begin              calib_done[0] <= 1'b1;              cal1_state <= CAL1_IDLE;            end else begin              // request auto-refresh after every 8-bits calibrated to              // avoid tRAS violation              if (cal1_refresh) begin                cal1_ref_req <= 1'b1;                if (calib_ref_done)                  cal1_state <= CAL1_INIT;              end else                // if no need this time for refresh, proceed to next bit                cal1_state <= CAL1_INIT;            end          end      endcase    end  //***************************************************************************  // Second stage calibration: DQS-FPGA Clock  // Algorithm Description:  //  1. Assumes a training pattern that will produce a pattern oscillating at  //     half the core clock frequency each on rise and fall outputs, and such  //     that rise and fall outputs are 180 degrees out of phase from each  //     other. Note that since the calibration logic runs at half the speed  //     of the interface, expect that data sampled with the slow clock always  //     to be constant (either always = 1, or = 0, and rise data != fall data)  //     unless we cross the edge of the data valid window  //  2. Start by setting RD_DATA_SEL = 0. This selects the rising capture data  //     sync'ed to rising edge of core clock, and falling edge data sync'ed  //     to falling edge of core clock  //  3. Start looking for an edge. An edge is defined as either: (1) a  //     change in capture value or (2) an invalid capture value (e.g. rising  //     data != falling data for that same clock cycle).  //  4. If an edge is found, go to step (6). If edge hasn't been found, then  //     set RD_DATA_SEL = 1, and try again.  //  5. If no edge is found, then increment IDELAY and return to step (3)  //  6. If an edge if found, then invert RD_DATA_SEL - this shifts the  //     capture point 180 degrees from the edge of the window (minus duty  //     cycle distortion, delay skew between rising/falling edge capture  //     paths, etc.)  //  7. If no edge is found by CAL2_IDEL_TAP_LIMIT (= 63 - # taps used for  //     stage 1 calibration), then decrement IDELAY (without reinverting  //     RD_DATA_SEL) by CAL2_IDEL_TAP_LIMIT/2. This guarantees we at least  //     have CAL2_IDEL_TAP_LIMIT/2 of slack both before and after the  //     capture point (not optimal, but best we can do not having found an  //     of the window). This happens only for very low frequencies.  //  8. Repeat for each DQS group.  //  NOTE: Step 6 is not optimal. A better (and perhaps more complicated)  //   algorithm might be to find both edges of the data valid window (using  //   the same polarity of RD_DATA_SEL), and then decrement to the midpoint.  //***************************************************************************  // RD_DATA_SEL should be tagged with FROM-TO (multi-cycle) constraint in  // UCF file to relax timing. This net is "pseudo-static" (after value is  // changed, FSM waits number of cycles before using the output).  // Note that we are adding one clock cycle of delay (to isolate it from  // the other logic CAL2_RD_DATA_SEL feeds), make sure FSM waits long  // enough to compensate (by default it does, it waits a few cycles more  // than minimum # of clock cycles)  genvar rd_i;  generate    for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rd_data_sel      FD u_ff_rd_data_sel        (         .Q (rd_data_sel[rd_i]),         .C (clkdiv),         .D (cal2_rd_data_sel[rd_i])         ) /* synthesis syn_preserve = 1 */           /* synthesis syn_replicate = 0 */;    end  endgenerate  //*****************************************************************  // Max number of taps used for stg2 cal dependent on number of taps  // used for stg1 (give priority to stg1 cal - let it use as many  // taps as it needs - the remainder of the IDELAY taps can be used  // by stg2)  //*****************************************************************  always @(posedge clkdiv)    cal2_idel_tap_limit <= 6'b111111 - cal1_idel_max_tap;  //*****************************************************************  // second stage calibration uses readback pattern of "1100" (i.e.  // 1st rising = 1, 1st falling = 1, 2nd rising = 0, 2nd falling = 0)  // only look at the first bit of each DQS group  //*****************************************************************  // deasserted when captured data has changed since IDELAY was  // incremented, or when we're right on the edge (i.e. rise data =  // fall data).  assign cal2_detect_edge =    ((((rdd_rise_q1 != cal2_rd_data_rise_last_pos) ||       (rdd_fall_q1 != cal2_rd_data_fall_last_pos)) &&      cal2_rd_data_last_valid_pos && (!cal2_curr_sel)) ||     (((rdd_rise_q1 != cal2_rd_data_rise_last_neg) ||       (rdd_fall_q1 != cal2_rd_data_fall_last_neg)) &&      cal2_rd_data_last_valid_neg && (cal2_curr_sel)) ||     (rdd_rise_q1 != rdd_fall_q1));  //*****************************************************************  // keep track of edge tap counts found, and whether we've  // incremented to the maximum number of taps allowed  // NOTE: Assume stage 2 cal always increments the tap count (never  //       decrements) when searching for edge of the data valid window  //*****************************************************************  always @(posedge clkdiv)    if (cal2_state == CAL2_INIT) begin      cal2_idel_tap_limit_hit <= 1'b0;      cal2_idel_tap_cnt <= 6'b000000;    end else if (cal2_dlyce_dqs) begin      cal2_idel_tap_cnt <= cal2_idel_tap_cnt + 1;      cal2_idel_tap_limit_hit <= (cal2_idel_tap_cnt ==                                  cal2_idel_tap_limit - 1);    end  //*****************************************************************  always @(posedge clkdiv)    if (rstdiv) begin      calib_done[1]               <= 1'b0;      calib_done_tmp[1]           <= 1'bx;      calib_err[1]                <= 1'b0;      count_dqs                   <= 'b0;      next_count_dqs              <= 'b0;      cal2_dlyce_dqs              <= 1'b0;      cal2_dlyinc_dqs             <= 1'b0;      cal2_idel_dec_cnt           <= 6'bxxxxxx;      cal2_rd_data_last_valid_neg <= 1'bx;      cal2_rd_data_last_valid_pos <= 1'bx;      cal2_rd_data_sel            <= 'b0;      cal2_ref_req                <= 1'b0;      cal2_state                  <= CAL2_IDLE;    end else begin      cal2_ref_req      <= 1'b0;      cal2_dlyce_dqs    <= 1'b0;      cal2_dlyinc_dqs   <= 1'b0;      case (cal2_state)        CAL2_IDLE: begin          count_dqs      <= 'b0;          next_count_dqs <= 'b0;          if (calib_start[1]) begin            cal2_rd_data_sel  <= {DQS_WIDTH{1'b0}};            calib_done[1]     <= 1'b0;            calib_done_tmp[1] <= 1'b0;            cal2_state        <= CAL2_INIT;          end        end        // Pass through this state every time we calibrate a new DQS group        CAL2_INIT: begin          cal2_curr_sel <= 1'b0;          cal2_rd_data_last_valid_neg <= 1'b0;          cal2_rd_data_last_valid_pos <= 1'b0;          cal2_state <= CAL2_INIT_IDEL_WAIT;        end        // Stall state only used if calibration run more than once. Can take        // this state out if design never runs calibration more than once.        // We need this state to give time for MUX'ed data to settle after        // resetting RD_DATA_SEL        CAL2_INIT_IDEL_WAIT:          if (!idel_set_wait)            cal2_state <= CAL2_FIND_EDGE_POS;        // Look for an edge - first check "positive-edge" stage 2 capture        CAL2_FIND_EDGE_POS: begin          // if found an edge, then switch to the opposite edge stage 2          // capture and we're done - no need to decrement the tap count,          // since switching to the opposite edge will shift the capture          // point by 180 degrees          if (cal2_detect_edge) begin            cal2_curr_sel <= 1'b1;            cal2_state <= CAL2_DONE;            // set all DQS groups to be the same for simulation            if (SIM_ONLY != 0)              cal2_rd_data_sel <= {DQS_WIDTH{1'b1}};            else              cal2_rd_data_sel[count_dqs] <= 1'b1;            if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0))              calib_done_tmp[1] <= 1'b1;	    else              // MIG 2.1: Fix for simulation out-of-bounds error when              // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL)  	      next_count_dqs <= count_dqs + 1;          end else begin            // otherwise, invert polarity of stage 2 capture and look for            // an edge with opposite capture clock polarity            cal2_curr_sel <= 1'b1;            cal2_rd_data_sel[count_dqs] <= 1'b1;            cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_POS;            cal2_rd_data_rise_last_pos  <= rdd_rise_q1;            cal2_rd_data_fall_last_pos  <= rdd_fall_q1;            cal2_rd_data_last_valid_pos <= 1'b1;          end        end        // Give time to switch from positive-edge to negative-edge second        // stage capture (need time for data to filter though pipe stages)        CAL2_FIND_EDGE_IDEL_WAIT_POS:          if (!idel_set_wait)            cal2_state <= CAL2_FIND_EDGE_NEG;        // Look for an edge - check "negative-edge" stage 2 capture        CAL2_FIND_EDGE_NEG:          if (cal2_detect_edge) begin            cal2_curr_sel <= 1'b0;            cal2_state <= CAL2_DONE;            // set all DQS groups to be the same for simulation            if (SIM_ONLY != 0)              cal2_rd_data_sel <= {DQS_WIDTH{1'b0}};            else              cal2_rd_data_sel[count_dqs] <= 1'b0;            if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0))              calib_done_tmp[1] <= 1'b1;	    else              // MIG 2.1: Fix for simulation out-of-bounds error when              // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL)	      next_count_dqs <= count_dqs + 1;          end else if (cal2_idel_tap_limit_hit) begin            // otherwise, if we've run out of taps, then immediately            // backoff by half # of taps used - that's our best estimate            // for optimal calibration point. Doesn't matter whether which            // polarity we're using for capture (we don't know which one is            // best to use)            cal2_idel_dec_cnt <= {1'b0, cal2_idel_tap_limit[5:1]};            cal2_state <= CAL2_DEC_IDEL;            if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0))              calib_done_tmp[1] <= 1'b1;	    else              // MIG 2.1: Fix for simulation out-of-bounds error when              // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL)	      next_count_dqs <= count_dqs + 1;          end else begin            // otherwise, increment IDELAY, and start looking for edge again            cal2_curr_sel <= 1'b0;            cal2_rd_data_sel[count_dqs] <= 1'b0;            cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_NEG;            cal2_rd_data_rise_last_neg  <= rdd_rise_q1;            cal2_rd_data_fall_last_neg  <= rdd_fall_q1;            cal2_rd_data_last_valid_neg <=

⌨️ 快捷键说明

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