📄 mem_interface_top_phy_calib_0.v
字号:
cal2_dqs_count <= {DQS_WIDTH{1'bx}};
cal2_state <= CAL2_IDLE;
cal2_rd_data_fall_last <= 1'd0;
cal2_rd_data_rise_last <= 1'd0;
cal2_rd_valid <= 1'd0;
end else begin
cal2_inc_tap <= 1'd0;
cal2_dec_tap <= 1'd0;
case (cal2_state)
CAL2_IDLE: begin
cal2_dqs_count <= {DQS_WIDTH{1'b0}};
if (calib_start[1]) begin
cal2_state <= CAL2_INIT;
end
end
CAL2_INIT: begin
cal2_first_edge_detect <= 1'b0;
cal2_inc_count <= 6'd0;
cal2_tap_count <= cal2_tap_count_cp1;
cal2_state <= CAL2_EDGE_DETECT;
end
CAL2_EDGE_DETECT:begin
if ((cal2_detect_edge_r)) begin
cal2_first_edge_detect <= 1'd1;
if ((cal2_first_edge_detect) && (cal2_inc_count > 10))
cal2_state <= CAL2_CASE1; // two edges found
else if ((cal2_inc_count >= MIN_WIN_SIZE+1))
cal2_state <= CAL2_CASE2;
else begin
cal2_inc_tap <= 1'd1;
cal2_state <= CAL2_EDGE_DETECT_WAIT;
cal2_inc_count <= 6'd0;
end
end else if (cal2_tap_count == MAX_TAPS) // if (cal2_detect_edge)
cal2_state <= CAL2_CASE3;
else begin
cal2_inc_tap <= cal2_rd_valid;// increment only when there is valid data
cal2_state <= CAL2_EDGE_DETECT_WAIT;
end
end // case: CAL2_EDGE_DETECT
CAL2_EDGE_DETECT_WAIT:begin
if (!idel_set_wait)begin
cal2_state <= CAL2_EDGE_DETECT;
cal2_rd_valid <= 1'd1;
cal2_tap_count <= cal2_tap_count + cal2_rd_valid;
cal2_inc_count <= cal2_inc_count + cal2_rd_valid;
cal2_rd_data_fall_last <= cal2_rd_data_fall_r;
cal2_rd_data_rise_last <= cal2_rd_data_rise_r;
end
end
// case where the first edge was found with not enough taps and have to
// move over to the next edge.
// Two edges found
CAL2_CASE1:begin
cal2_dec_count <= cal2_dec_count_c1;
cal2_state <= CAL2_TAP_DEC;
end
// where the window size was > MIN_WIN_SIZE before the
// first edge
CAL2_CASE2:begin
cal2_state <= CAL2_TAP_DEC;
cal2_dec_count <= MIN_WIN_SIZE+1;
end
// where the first edge did not have enough taps and second edge
// not found.
CAL2_CASE3:begin
cal2_state <= CAL2_TAP_DEC;
cal2_dec_count <= cal2_dec_count_c3;
end
CAL2_TAP_DEC:begin
if(cal2_dec_count > 6'd0) begin
cal2_dec_count <= cal2_dec_count -1;
cal2_dec_tap <= 1'd1;
end
else begin
cal2_state <= CAL2_DONE;
cal2_dec_tap <= 1'd0;
end
end
CAL2_DONE:begin
if (!idel_set_wait) begin
if (cal2_dqs_count_check) begin
calib_done[1] <= 1'b1;
cal2_state <= CAL2_IDLE;
end else begin
cal2_state <= CAL2_INIT;
cal2_rd_valid <= 1'd0;
cal2_dqs_count <= cal2_dqs_count + 1;
end
end
end
endcase
end // else: !if(rst90)
end // always @ (posedge clk90)
//***************************************************************************
// Stage 3 calibration: Read Enable
//***************************************************************************
// CLK0 -> CLK90 (well CLK270, but we'll eventually get to CLK90) sync
always @(negedge clk90) begin
ctrl_rden_270 <= ctrl_rden_0;
phy_init_rden_270 <= phy_init_rden_0;
end
// don't start calibrating until told to do so, need this if initialization
// logic will assert RDEN at times prior to start of Stage 2 calibration
always @(posedge clk90)
if (rst90)
cal3_en <= 1'b0;
else if (calib_start[2])
cal3_en <= 1'b1;
else if (calib_done[2])
cal3_en <= 1'b0;
always @(posedge clk90) begin
// long delay chain to delay read enable signal from controller/
// initialization logic (i.e. this is used for both initialization and
// during normal controller operation). Stage 3 calibration logic decides
// which delayed version is appropriate to use (which is affected by the
// round trip delay of DQ/DQS) as a "valid" signal to tell rest of logic
// when the captured data output from ISERDES is valid. NOTE: Note all of
// these taps will be used - depends also on ADDITIVE_CAS_LATENCY, and
// whether various optional features (which result in extra pipeline
// delay) are enabled
rden_stages_r[0] <= ctrl_rden_270 | phy_init_rden_270;
rden_stages_r[1] <= rden_stages_r[0];
rden_stages_r[2] <= rden_stages_r[1];
rden_stages_r[3] <= rden_stages_r[2];
rden_stages_r[4] <= rden_stages_r[3];
rden_stages_r[5] <= rden_stages_r[4];
rden_stages_r[6] <= rden_stages_r[5];
rden_stages_r[7] <= rden_stages_r[6];
rden_stages_r[8] <= rden_stages_r[7];
rden_stages_r[9] <= rden_stages_r[8];
rden_stages_r[10] <= rden_stages_r[9];
rden_stages_r[11] <= rden_stages_r[10];
rden_stages_r[12] <= rden_stages_r[11];
rden_stages_r[13] <= rden_stages_r[12];
rden_stages_r[14] <= rden_stages_r[13];
rden_stages_r[15] <= rden_stages_r[14];
rden_stages_r[16] <= rden_stages_r[15];
rden_stages_r[17] <= rden_stages_r[16];
rden_stages_r[18] <= rden_stages_r[17];
rden_stages_r[19] <= rden_stages_r[18];
rden_stages_r[20] <= rden_stages_r[19];
rden_stages_r[21] <= rden_stages_r[20];
rden_stages_r[22] <= rden_stages_r[21];
rden_stages_r[23] <= rden_stages_r[22];
// read_en_r is the range of possible taps - one of which will ultimately
// be used to generate the read valid for each DQS. READ_EN_R[0] is the
// MINIMUM possible delay from issuance of read command until when
// captured data at ISERDES output is valid
rden_r[0] <= rden_stages_r[ADDITIVE_LAT + ECC_ENABLE + REG_ENABLE + CAS_LAT + 5];
rden_r[1] <= rden_r[0];
rden_r[2] <= rden_r[1];
rden_r[3] <= rden_r[2];
rden_r[4] <= rden_r[3];
rden_r[5] <= rden_r[4];
rden_r[6] <= rden_r[5];
rden_r[7] <= rden_r[6];
rden_r[8] <= rden_r[7];
// used to determine one which clock cycle valid data is returned
rden_edge <= {rden_r[7] & ~rden_r[8],
rden_r[6] & ~rden_r[7],
rden_r[5] & ~rden_r[6],
rden_r[4] & ~rden_r[5],
rden_r[3] & ~rden_r[4],
rden_r[2] & ~rden_r[3],
rden_r[1] & ~rden_r[2],
rden_r[0] & ~rden_r[1]};
end
//*****************************************************************
// indicates that current received data is the correct pattern. Check both
// rising and falling data for first 2 DQ's in each DQS group. Note that
// we're checking using registered, and twice-registered version of ISERDES
// output, so need to take this delay into account in determining final
// read valid delay.
// Expect data in sequence (in binary): 11, 10, 01, 00
// We check for the presence of the two middle words (10, 01), and
// compensate read valid delay accordingly
// NOTE: Original read enable calibration data checking compared using more
// bits. Check if this is required.
//*****************************************************************
always @(posedge clk90) begin
cal3_data <=
{rd_data_rise_r[(rden_cnt_r2*DQ_PER_DQS+1)],
rd_data_rise_r[(rden_cnt_r2*DQ_PER_DQS)],
rd_data_rise_chk_r1[(2*rden_cnt_r2)+1],
rd_data_rise_chk_r1[(2*rden_cnt_r2)],
rd_data_fall_r[(rden_cnt_r2*DQ_PER_DQS)+1],
rd_data_fall_r[(rden_cnt_r2*DQ_PER_DQS)],
rd_data_fall_chk_r1[(2*rden_cnt_r2)+1],
rd_data_fall_chk_r1[(2*rden_cnt_r2)]};
end
always @(posedge clk90)
cal3_data_match <= (cal3_data == 8'b01100110);
// when calibrating, check to see which clock cycle (after the read is
// issued) does the expected data pattern arrive. Record this result
//synthesis attribute max_fanout of rden_cnt is 5
//synthesis attribute max_fanout of rden_cnt_r1 is 5
//synthesis attribute max_fanout of rden_cnt_r2 is 5
//synthesis attribute max_fanout of calib3_done 2
//synthesis attribute max_fanout of rden_dly 2
always @(posedge clk90) begin
if (rst90) begin
calib_done[2] <= 1'b0;
calib3_done <= 1'd0;
rden_cnt <= {DQS_WIDTH{1'b0}};
rden_cnt_r1 <= {DQS_WIDTH{1'bx}};
rden_cnt_r2 <= {DQS_WIDTH{1'bx}};
rden_dly_cnt <= {DQS_BITS_FIX+3{1'b0}};
rden_dly_tmp <= 3'd0;
rden_dly <= {3*DQS_WIDTH{1'b0}};
rden_dly_r1 <= {3*DQS_WIDTH{1'b0}};
end else begin
calib3_done <= calib_done[2];
// increment count when data match
if( cal3_data_match && cal3_en) begin
// assert done when count reached
if (rden_cnt_r1 == DQS_WIDTH-1)
calib_done[2] <= 1'b1;
if (rden_cnt != DQS_WIDTH-1)
rden_cnt <= rden_cnt + 1;
rden_dly_tmp[0] <= rden_edge[6] | rden_edge[4]
| rden_edge[2] | rden_edge[0];
rden_dly_tmp[1] <= rden_edge[6] | rden_edge[5]
|rden_edge[2] | rden_edge[1];
rden_dly_tmp[2] <= | rden_edge[6:3];
end
rden_cnt_r1 <= rden_cnt;
rden_cnt_r2 <= rden_cnt_r1;
// index calulation pipelined for timing
rden_dly_cnt <= (rden_cnt_r1*3);
rden_dly[rden_dly_cnt+2] <= rden_dly_tmp[2];
rden_dly[rden_dly_cnt+1] <= rden_dly_tmp[1];
rden_dly[rden_dly_cnt] <= rden_dly_tmp[0];
rden_dly_r1 <= rden_dly;
end
end
// generate read valid signal for each DQS group
// keep CALIB_RDEN deasserted until calibration complete (i.e. stage 3
// finished), otherwise, user will get rogue RDEN pulses during calibration
// calib_rden calculation is pipelined for timing.
// synthesis attribute max_fanout of calib_rden is 1
genvar rden_i;
generate
for(rden_i = 0; rden_i < DQS_WIDTH; rden_i = rden_i + 1) begin: gen_rden
always @(posedge clk90)begin
calib_rden[rden_i] <= calib_rden_tmp_1[rden_i];
calib_rden_tmp_1[rden_i] <= calib3_done && calib_rden_tmp[rden_i];
calib_rden_tmp[rden_i] <= rden_stages_r[ADDITIVE_LAT + ECC_ENABLE
+ REG_ENABLE + CAS_LAT + {rden_dly_r1[(rden_i*3)+2],
rden_dly_r1[(rden_i*3)+1], rden_dly_r1[(rden_i*3)]}-2];
end // always @ (posedge clk90)
end
endgenerate
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -