📄 mem_phy_calib.v
字号:
///////////////////////////////////////////////////////////////////////////////// Copyright (c) 2005 Xilinx, Inc.// All Rights Reserved///////////////////////////////////////////////////////////////////////////////// ____ ____// / /\/ /// /___/ \ / Vendor: Xilinx// \ \ \/ Version: 1.0// \ \ Filename: addr_gen.v// / / Timestamp: 12 Dec 2005// /___/ /\ // \ \ / \// \___\/\___\//////Device: Virtex-5///////////////////////////////////////////////////////////////////////////////// This module does the claibration after initialization. module mem_phy_calib ( input clk90, input reset90, input clk0, input reset0, input ctrl_rden, input idelay_ctrl_rdy, input [(`data_width*2)-1:0] capture_data, input phy_init_rden, input phy_init_initialization_done, input phy_init_st1_read, input phy_init_st2_read, output [43:0] test_bus, output reg [`data_strobe_width-1:0] phy_calib_rden, output reg first_calib_done, output reg second_calib_done, output reg [`data_width-1:0] phy_calib_dq_dlyinc, output reg [`data_width-1:0] phy_calib_dq_dlyce, output reg [`data_width-1:0] phy_calib_dq_dlyrst, output reg [`data_strobe_width-1:0] phy_calib_dqs_dlyinc, output reg [`data_strobe_width-1:0] phy_calib_dqs_dlyce, output reg [`data_strobe_width-1:0] phy_calib_dqs_dlyrst); reg [3:0] state_r; reg [3:0] state_r_test; reg [(`data_width*2)-1:0] capture_data_r2_test; reg [`data_strobe_width-1:0] dqs_count_r1_test; reg data_detect_r; reg [5:0] inc_count_r; reg [4:0] tap_count_r; reg [5:0] dec_count_r; reg [5:0] rise_count_r; reg rise_done_r; reg [5:0] start_window_r; reg add_dq_delay_r; reg phy_init_rden_270_r; reg ctrl_rden_270_r; reg first_calib_done_90_r; reg second_calib_done_90_r; reg stg2_read_r1; reg stg2_read_r2; reg stg2_read_r3; reg stg1_read_r1; reg stg1_read_r2; reg [4:0] read_en_r; reg [(`data_strobe_width*2)-1 :0] read_en_stg_r; reg [`data_strobe_width-1:0] dqs_count_r, dqs_count_r1; reg [`data_strobe_width-1:0] rden_count_r; reg [(`data_width*2)-1:0] capture_data_r; reg [(`data_width*2)-1:0] capture_data_r1; reg [(`data_width*2)-1:0] capture_data_r2; reg dq_calib_done_r; reg dq_calib_begin_r; reg [3:0] dq_state_r; reg [1:0] dq_inc_count_r; reg [1:0] dq_dec_count_r; reg [2:0] dq_count_r; reg data_match; reg data_check_r; reg data_xor_r; reg data_xor_r1; wire read_en_r1_edge; wire read_en_r2_edge; wire read_en_r3_edge; wire read_en_r4_edge; reg [7:0] rd_en_stages_r; wire [14:0] load_mode_reg;wire [14:0] ext_mode_reg;assign REGISTERED_VALUE = `registered; assign CAS_LATENCY_VALUE = load_mode_reg[6:4];assign ADDITIVE_LATENCY_VALUE = ext_mode_reg[5:3];assign ECC_VALUE= `ecc_enable; localparam IDLE = 4'h0; localparam CHECK = 4'h1; localparam INC = 4'h2; localparam WAIT0 = 4'h3; localparam WAIT1 = 4'h4; localparam WAIT2 = 4'h5; localparam DEC = 4'h6; localparam SELECT = 4'h7; localparam DQS_DQ_INC = 4'h8; localparam FINAL_INC = 4'h9; localparam FINAL_CHECK = 4'hA; localparam DEC_WAIT = 4'hB; localparam DQ_CALIB = 4'hC; localparam INC_WAIT0 = 4'hD; localparam INC_WAIT1 = 4'hE; localparam INC_WAIT2 = 4'hF; localparam DQ_IDLE = 4'h0; localparam DQ_DQ_CHECK = 4'h1; localparam DQ_DQ_DEC = 4'h2; localparam DQ_DQ_INC = 4'h3; localparam DQ_DQ_WAIT0 = 4'h4; localparam DQ_DQ_WAIT1 = 4'h5; localparam DQ_DQ_WAIT2 = 4'h6; localparam DQ_DQ_SELECT = 4'h7; localparam DQ_DQ_CALIB_DONE0 = 4'h8; localparam DQ_DQ_CALIB_DONE1 = 4'h9; assign load_mode_reg = `load_mode_register;assign ext_mode_reg = `ext_load_mode_register;assign REGISTERED_VALUE = `registered; assign CAS_LATENCY_VALUE = load_mode_reg[6:4];assign ADDITIVE_LATENCY_VALUE = ext_mode_reg[5:3]; assign test_bus = {capture_data_r2_test[31:0], dqs_count_r1_test, state_r_test[3:0]}; //12'd0,dqs_count_r1,rise_done_r,rise_count_r,inc_count_r[4:0], // SM for the first stage of calibration. In the first stage of calibration the taps for DQS are incremented until // there is valid data. Once there is a data match the sm will increase the taps to find out the window for valid data. // This will be done with respect to clock0 first and then with clock180. The clock that takes the lowest number of taps // will be chosen. During the calibration the SM will look at bit 0 of the DQS byte. Once the calibration is done for the // DQS, then the DQ calibration will be done by the next state machine. always@(posedge clk90) begin if(reset90 || ~idelay_ctrl_rdy)begin state_r <= IDLE; data_detect_r <= 1'd0; // will go high when there is a data match. phy_calib_dqs_dlyinc <= `data_strobe_width'd0; phy_calib_dqs_dlyce <= `data_strobe_width'd0; phy_calib_dqs_dlyrst <= `data_strobe_width'hff; inc_count_r <= 6'd0; tap_count_r <= 5'd0; dec_count_r <= 6'd0; first_calib_done_90_r <= 1'd0; // flag to indicate the first stage of calibration is done. rise_count_r <= 6'd0; // counter to count the taps during clock0 calibration. rise_done_r <= 1'd0; // flag for clock0 calibration dqs_count_r <= `data_strobe_width'd0; // count for dqs dqs_count_r1 <= `data_strobe_width'd0; // count for dqs capture_data_r <= `data_width*2'd0; capture_data_r1 <= `data_width*2'd0; capture_data_r2 <= `data_width*2'd0; start_window_r <= 6'd0; // register to keep track of the start of the window. dq_calib_begin_r <= 1'd0; // flag to the dq calib state machine. add_dq_delay_r <= 1'd0; data_check_r <= 1'd0; end else begin // if (reset90 || ~idelay_ctrl_rdy) capture_data_r <= capture_data; capture_data_r1 <= capture_data_r; capture_data_r2 <= capture_data_r1; dqs_count_r1 <= dqs_count_r; data_check_r <= ((capture_data_r1[dqs_count_r*8] == capture_data_r1[(dqs_count_r*8) + `data_width] ) && ((capture_data_r1[dqs_count_r*8] ^ capture_data_r[dqs_count_r*8]) && (capture_data_r1[(dqs_count_r*8) + `data_width] ^ capture_data_r[(dqs_count_r*8) + `data_width]))); case(state_r) IDLE: if(stg1_read_r2) state_r <= CHECK; CHECK: begin // The condition checks for data match. Also checks for rise and fall counter not going over 64. // once the window is 16, we stop incrementing (inc_counter <= 4'd15) if(data_check_r && (~(&rise_count_r))) begin data_detect_r <= 1'd1; state_r <= INC; inc_count_r <= inc_count_r + 1'd1; end else begin // if data_detect went high or rise,fall count has reached 64 without match if((data_detect_r) || (&rise_count_r))begin state_r <= DEC; tap_count_r <= 5'd4; end else state_r <= INC; end // else: !if((capture_data_r[dqs_count_r*8] == capture_data_r[(dqs_count_r*8) + `data_width] )... end // case: CHECK INC: begin phy_calib_dqs_dlyce[dqs_count_r] <= 1'd1; phy_calib_dqs_dlyinc[dqs_count_r] <= 1'd1; state_r <= WAIT0; rise_count_r <= rise_count_r + 1'd1; end WAIT0: begin state_r <= WAIT1; add_dq_delay_r <= 1'd0; phy_calib_dqs_dlyce[dqs_count_r] <= 1'd0; phy_calib_dqs_dlyinc[dqs_count_r] <= 1'd0; phy_calib_dqs_dlyrst[dqs_count_r] <= 1'd0; end WAIT1: state_r <= WAIT2; WAIT2: begin if(rise_done_r ) // IF both clock0 and clock180 windows are found. state_r <= FINAL_INC; else state_r <= CHECK; end DEC: begin tap_count_r <= tap_count_r -1; phy_calib_dqs_dlyrst[dqs_count_r] <= 1'd1; // reset90 all the taps to 0 data_detect_r <= 1'd0; start_window_r <= rise_count_r - inc_count_r; if(inc_count_r < 6'd14) begin add_dq_delay_r <= 1'd1; if(tap_count_r > 5'd0) begin state_r <= DEC; end else begin state_r <= WAIT0; inc_count_r <= 6'd0; rise_count_r <= 6'd0; end // else: !if(tap_count_r == 5'd1) end else begin rise_done_r <= 1'd1; state_r <= DEC_WAIT; end // else: !if(inc_count_r < 5'd8) end // case: DEC DEC_WAIT: begin state_r <= SELECT; // wait state for dqs_rst phy_calib_dqs_dlyrst[dqs_count_r] <= 1'd0; end SELECT: begin // state to select either clock0 or clock180 state_r <= DQS_DQ_INC; if(inc_count_r > 6'd15) rise_count_r <= inc_count_r/2; else rise_count_r <= inc_count_r -8; //rise_count_r <= ((inc_count_r -8));// loading the counter with the tap value that needs to incremented from the start of the window. end // case: SELECT DQS_DQ_INC: begin if(start_window_r > 6'd0)begin // increment until the start of window. phy_calib_dqs_dlyce[dqs_count_r] <= 1'd1; phy_calib_dqs_dlyinc[dqs_count_r] <= 1'd1; start_window_r <= start_window_r - 1'b1; state_r <= INC_WAIT0; end else begin // once incremented do the individual dq calibration in the SM below. if(dq_calib_done_r) state_r <= FINAL_INC; else dq_calib_begin_r <= 1'd1; end // else: !if(start_window_r > 6'd0) end // case: INC INC_WAIT0: begin state_r <= INC_WAIT1; phy_calib_dqs_dlyce[dqs_count_r] <= 1'd0; phy_calib_dqs_dlyinc[dqs_count_r] <= 1'd0; end INC_WAIT1: state_r <= INC_WAIT2; INC_WAIT2: state_r <= DQS_DQ_INC; FINAL_INC:begin dq_calib_begin_r <= 1'd0; if(rise_count_r > 6'd0) // increment until the middle of the window. begin phy_calib_dqs_dlyce[dqs_count_r] <= 1'd1; phy_calib_dqs_dlyinc[dqs_count_r] <= 1'd1; rise_count_r <= rise_count_r - 1'd1; state_r <= WAIT0; end else begin state_r <= FINAL_CHECK; dqs_count_r <= dqs_count_r + 1'b1; // increment the dqs counter end end // case: FINAL_INC FINAL_CHECK: begin if(dqs_count_r >= (`data_strobe_width)) begin // if all the dqs has been calibrated then end the first calibration. first_calib_done_90_r <= 1'd1; // state_r <= IDLE; end else begin // reset90 all the counters and start on the next dqs. inc_count_r <= 4'd0; dec_count_r <= 6'd0; rise_count_r <= 6'd0; rise_done_r <= 1'd0; // phy_calib_dqs_dlyrst[dqs_count_r] <= 1'd1; state_r <= WAIT0; end // else: !if(dqs_count_r >= `data_strobe_width) end // case: FINAL_CHECK endcase // case(state_r) end // else: !if(reset90 || ~idelay_ctrl_rdy) end // always@ (posedge clk90) // This state machine does the DQ calibration. After the DQS calibration is done, the dq calibration // will be done. The DQ bits start with a tap setting of 5. The taps will be incremented or decremented // to fine tune the individual DQ window. always@(posedge clk90) begin if(reset90 || ~idelay_ctrl_rdy)begin dq_state_r <= DQ_IDLE; dq_calib_done_r <= 1'd0; dq_inc_count_r <= 2'd0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -