📄 mem_interface_top_phy_calib_0.v
字号:
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 + -