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

📄 mem_interface_top_phy_calib_0.v

📁 sata_device_model,对做硬盘控制器的朋友有帮助
💻 V
📖 第 1 页 / 共 4 页
字号:
  genvar rdd_i;
  generate
    for (rdd_i = 0; rdd_i < DQS_WIDTH; rdd_i = rdd_i + 1) begin: gen_rdd
      always @(posedge clk90) begin
        rd_data_rise_chk_r1[(2*rdd_i)] <=
          rd_data_rise_r[(rdd_i*DQ_PER_DQS)];
        rd_data_rise_chk_r1[(2*rdd_i)+1] <=
          rd_data_rise_r[(rdd_i*DQ_PER_DQS)+1];
        rd_data_fall_chk_r1[(2*rdd_i)] <=
          rd_data_fall_r[(rdd_i*DQ_PER_DQS)];
        rd_data_fall_chk_r1[(2*rdd_i)+1] <=
          rd_data_fall_r[(rdd_i*DQ_PER_DQS)+1];
      end
    end
  endgenerate

  //***************************************************************************
  // IDELAY increment, decmerent and reset
  //***************************************************************************

  always @(posedge clk90) begin
    if (rst90) begin
      dlyce_dq   <= {DQ_WIDTH{1'b0}};
      dlyinc_dq  <= {DQ_WIDTH{1'b0}};
      dlyce_dqs  <= {DQS_WIDTH{1'b0}};
      dlyinc_dqs <= {DQS_WIDTH{1'b0}};
      dlyrst_dq  <= {DQ_WIDTH{1'b1}};
      dlyrst_dqs <= 1'b1;
    end
    else begin
         dlyrst_dqs <= 1'b0;
         dlyrst_dq <= {DQS_WIDTH{1'b0}};
         dlyinc_dqs[idelay_dqs_count] <= dqs_inc;
         dlyce_dqs[idelay_dqs_count] <= dqs_ce;

        for (i = 0; i < DQ_PER_DQS; i = i + 1) begin: loop_dly
          dlyce_dq[(DQ_PER_DQS*(idelay_dqs_count))+i] <= dq_ce[i];
          dlyinc_dq[(DQ_PER_DQS*(idelay_dqs_count))+i] <= dq_inc[i];
          if(dq_rst_cond)
            dlyrst_dq[(DQ_PER_DQS*(idelay_dqs_count))+i] <= dq_rst;
        end
      end
  end // always @ (posedge clk90)

  //***************************************************************************
  // IDELAY increment variables registered for timing reasons
  //***************************************************************************

  //synthesis attribute max_fanout of idelay_dqs_count is 5
  //synthesis attribute max_fanout of dq_ce is 5
  //synthesis attribute max_fanout of dqs_ce is 5
  //synthesis attribute max_fanout of dq_rst is 5
  //synthesis attribute max_fanout of dq_inc is 5
  always @(posedge clk90) begin
    if (rst90) begin
     idelay_dqs_count <=   {DQ_WIDTH{1'bx}};
     dqs_inc          <=   1'bx;
     dqs_ce           <=   1'bx;
     dq_inc           <=   {DQ_PER_DQS{1'bx}};
     dq_ce            <=   {DQ_PER_DQS{1'bx}};
     dq_rst           <=   1'bx;
     dq_rst_cond      <=   1'bx;
    end
    else begin
       idelay_dqs_count <= cal1_dqs_count_r1 + cal2_dqs_count_r1;
       dqs_inc          <= cal1_dlyinc_dqs | cal2_inc_tap;
       dqs_ce           <= cal1_dlyce_dqs | cal2_inc_tap | cal2_dec_tap;
       dq_inc           <= cal1_dlyinc_dq | {DQ_PER_DQS{cal2_inc_tap}};
       dq_ce            <= cal1_dlyce_dq | {DQ_PER_DQS{cal2_inc_tap | cal2_dec_tap}};
       dq_rst           <= cal1_dlyrst_dq;
       dq_rst_cond      <= ((cal1_state==CAL1_DQ_RESET ) || (cal1_state == CAL1_DQ_RESET1));
    end // else: !if(rst90)
  end // always @ (posedge clk90)

  //***************************************************************************
  // 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 2*5ns (worst case "guess", based on IDELAY being 5ns max) + 2 clock
  // cycles = 10ns + 2 clock cycles
  //***************************************************************************

  //synthesis attribute max_fanout of idel_set_cnt is 5
  always @(posedge clk90) begin
    //idel_set_wait <= (idel_set_cnt != IDEL_SET_VAL);
    if ( (cal2_state == CAL2_EDGE_DETECT) || (cal1_state == CAL1_EDGE_DETECT)
       || (cal1_state == CAL1_DQ_DESKEW) ||
        (cal2_state == CAL2_TAP_DEC)) begin
      idel_set_cnt <= 4'b0000;
      idel_set_wait <= 1'b1;
   end  else if (idel_set_cnt != IDEL_SET_VAL) begin
      idel_set_cnt <= idel_set_cnt + 1;
      idel_set_wait <= 1'b1;
   end else
     idel_set_wait <= 1'b0;
  end

  //***************************************************************************
  // 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:
  //  The DQS due to the BUFIO delay will be either in the right side of
  //  the rising edge window or in the falling edge window. It depends on
  //  the frequency of operation. At higher frequencies 300 MHz and above it
  //  can be in the falling edge window. At frequencies below 300 MHz it will
  //  be in the rising edge window. These assumptions are valid provided the
  //  DQ and DQS skews are matched.
  // Algorithm Description:
  //  1. Increment DQ IDELAY for the byte until we find an edge.
  //  2. Record the number of taps when all the DQ's are in valid data
  //    window (cal1_window_cnt).
  //     Record the number of taps where the individual DQ's are in
  //     valid window (cal1_dq_count)
  //  3. If the number of taps before the edge (cal1_window_cnt) is
  //     less than the MIN_WIN_SIZE, add delay to DQS so that the
  //     valid window is MIN_WIN_SIZE
  //  4. Reset the DQ idelay taps
  //  5. If the dq taps that where in the valid window + any DQS inc taps
  //     is greater tha MIN_WIN_SIZE, deskew the dq so that all the dq's
  //     look alike and are MIN_WIN_SIZE away from the DQS. The deskew will
  //     only be performed in higher frequencies. In lower frequencies the
  //     taps have to be saved for second stage calibration.
  //  6. Once done with the current byte move on to the next byte in the design

  //***************************************************************************

  //*****************************************************************
  // 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
  //*****************************************************************

 genvar chk_cnt_i;
  generate
    for(chk_cnt_i = 0; chk_cnt_i < DQ_PER_DQS; chk_cnt_i = chk_cnt_i + 1)
    begin: gen_chk_cnt
       assign cal1_data_chk[chk_cnt_i] =
              rd_data_fall_r[(cal1_dqs_count_r1*DQ_PER_DQS)+chk_cnt_i];
       assign cal1_data_chk[(chk_cnt_i)+DQ_PER_DQS] =
              rd_data_rise_r[(cal1_dqs_count_r1*DQ_PER_DQS)+chk_cnt_i];
       end
  endgenerate

  // register for timing purposes
  always @(posedge clk90)
    cal1_data_chk_r <= cal1_data_chk;

  //*****************************************************************
  // determine when the data is stable. When the current value is
  // equal to the previous latched valuse and when rise data == 1
  // and fall data == 0
  //*****************************************************************

  genvar st_cnt_i;
   generate
     for(st_cnt_i = 0; st_cnt_i < DQ_PER_DQS; st_cnt_i = st_cnt_i + 1)
     begin: gen_st_cnt
        assign cal1_detect_stable[st_cnt_i] = (cal1_data_chk_r[st_cnt_i] ==
               cal1_data_chk_last[st_cnt_i]) &&
               (cal1_data_chk_r[st_cnt_i+DQ_PER_DQS] ==
               cal1_data_chk_last[st_cnt_i+DQ_PER_DQS]) &&
               (cal1_data_chk_r[st_cnt_i+DQ_PER_DQS] == 1'b1) &&
               (cal1_data_chk_r[st_cnt_i] == 1'b0) ;
     end
  endgenerate

  //*****************************************************************
  // Find valid window: increments the counter when all the DQ bits
  // are in the valid window.
  //*****************************************************************

  //synthesis attribute max_fanout of cal1_window_cnt is 2
  //synthesis attribute max_fanout of cal1_window_cnt_r1 is 2
  always @(posedge clk90) begin
     cal1_window_cnt_r1 <= cal1_window_cnt;

    if (cal1_state == CAL1_INIT) begin
      cal1_window_cnt   <= 6'd0;
      cal1_stable_flag <= 1'd1;
    end else if (cal1_state == CAL1_EDGE_DETECT) begin
      if (&cal1_detect_stable_r) begin
        cal1_window_cnt <= cal1_window_cnt + 1;
        cal1_stable_flag <= 1'd0;
        end
      end
   end // always @ (posedge clk90)

  //*****************************************************************
  // Counter for dq idelay tap increments. DQ counter will be
  // incremented when the particular DQ is in the valid window
  // or when the cal1_window_cnt is 0 ( indicating no dq was
  // found in the valid window). During the CAL1_DQ_RESET1 state
  // the amount of deskew that needs for each DQ is calculated
  // and updated in the counter. In the CAL1_DQ_DESKEW state
  // as long as the counter is above 0, the DQ will be incremented.
  //*****************************************************************

  //*****************************************************************
  // The cal1_dq_count, cal1_dlyce_dq and cal1_dlyinc_dq counts are
  // pipelined here in the three generate statements below for
  // timing reasons. The three generate statements are
  // pipelines for the folloing conditions
  // if (cal1_state == CAL1_INIT)
  // if (cal1_state_r1 == CAL1_EDGE_DETECT)
  // if (cal1_state_r2 == CAL1_DQ_DESKEW)
  //*****************************************************************

  //synthesis attribute max_fanout of cal1_dq_count is 5
  //synthesis attribute max_fanout of cal1_dq_count_cp1 is 5
  //synthesis attribute max_fanout of cal1_dq_count_cp2 is 5
  //synthesis attribute max_fanout of cal1_dq_count_cp3 is 5
  genvar dq_cnt_i;
  generate
    for(dq_cnt_i = 0; dq_cnt_i < DQ_PER_DQS; dq_cnt_i = dq_cnt_i + 1)
    begin: gen_dq_cnt
      always @(posedge clk90)begin
        cal1_dlyce_dq[dq_cnt_i:dq_cnt_i] <= 1'd0;
        cal1_dlyinc_dq[dq_cnt_i:dq_cnt_i] <= 1'd0;
        if (cal1_state == CAL1_INIT)begin
          cal1_dq_count[(dq_cnt_i * 5)+4:dq_cnt_i*5] <= 5'd0;
          cal1_dlyce_dq[dq_cnt_i:dq_cnt_i]  <= 1'd0;
          cal1_dlyinc_dq[dq_cnt_i:dq_cnt_i]  <= 1'd0;
        end else if(cal1_state_r2 == CAL1_EDGE_DETECT)begin
          cal1_dq_count[(dq_cnt_i * 5)+4:dq_cnt_i*5] <=
          cal1_dq_count_cp1[(dq_cnt_i * 5)+4:dq_cnt_i*5];
          cal1_dlyce_dq[dq_cnt_i:dq_cnt_i] <=
          cal1_dlyce_dq_cp1[dq_cnt_i:dq_cnt_i] ;
          cal1_dlyinc_dq[dq_cnt_i:dq_cnt_i] <=
          cal1_dlyinc_dq_cp1[dq_cnt_i:dq_cnt_i] ;
        end else if (cal1_state_r2 == CAL1_DQ_RESET1) begin
          cal1_dq_count[(dq_cnt_i * 5)+4:dq_cnt_i*5] <=
          cal1_dq_count_cp2[(dq_cnt_i * 5)+4:dq_cnt_i*5];
        end else if (cal1_state_r2 == CAL1_DQ_DESKEW)begin
           cal1_dlyce_dq[dq_cnt_i:dq_cnt_i] <=
           cal1_dlyce_dq_cp3[dq_cnt_i:dq_cnt_i];
           cal1_dlyinc_dq[dq_cnt_i:dq_cnt_i] <=
           cal1_dlyinc_dq_cp3[dq_cnt_i:dq_cnt_i] ;
           cal1_dq_count[(dq_cnt_i * 5)+4:dq_cnt_i*5] <=
           cal1_dq_count_cp3[(dq_cnt_i * 5)+4:dq_cnt_i*5];
        end
      end
   end
   endgenerate

 genvar dq_cnt_i1;
  generate
    for(dq_cnt_i1 = 0; dq_cnt_i1 < DQ_PER_DQS; dq_cnt_i1 = dq_cnt_i1 + 1)
    begin: gen_dq_cnt1
      always @(posedge clk90)begin
        if(cal1_state_r1 == CAL1_EDGE_DETECT)begin
          cal1_dq_count_cp1[(dq_cnt_i1 * 5)+4:dq_cnt_i1*5] <=
          cal1_dq_count[(dq_cnt_i1 * 5)+4:dq_cnt_i1*5] +
          (cal1_detect_stable_r[dq_cnt_i1]) | (cal1_stable_flag);
          cal1_dlyce_dq_cp1[dq_cnt_i1:dq_cnt_i1] <=
          (cal1_detect_stable_r[dq_cnt_i1]) | (cal1_stable_flag);
          cal1_dlyinc_dq_cp1[dq_cnt_i1:dq_cnt_i1] <=
          (cal1_detect_stable_r[dq_cnt_i1]) | (cal1_stable_flag);
        end
      end
   end
   endgenerate


  genvar dq_cnt_i2;
  generate
    for(dq_cnt_i2 = 0; dq_cnt_i2 < DQ_PER_DQS; dq_cnt_i2 = dq_cnt_i2 + 1)
    begin: gen_dq_cnt2
      always @(posedge clk90)begin
         if (cal1_state_r1 == CAL1_DQ_RESET1) begin
          cal1_dq_count_cp2[(dq_cnt_i2 * 5)+4:dq_cnt_i2*5] <=
          cal1_dq_count_cp1[(dq_cnt_i2 * 5)+4:dq_cnt_i2*5] +
                              cal1_dqs_inc_count[4:0];
        end
      end
   end
   endgenerate

⌨️ 快捷键说明

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