added read phy interface

This commit is contained in:
Angelo Jacobo 2023-04-27 19:40:35 +08:00 committed by GitHub
parent 7debc3a4ce
commit c0172c24a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 567 additions and 73 deletions

View File

@ -8,8 +8,8 @@
// - High (sustained) data throughput. Sequential writes should be able to continue without interruption
//`define FORMAL_COVER //change delay in reset sequence to fit in cover statement
//`define COVER_DELAY 3 //fixed delay used in formal cover for reset sequence
`define FORMAL_COVER //change delay in reset sequence to fit in cover statement
`define COVER_DELAY 3 //fixed delay used in formal cover for reset sequence
`default_nettype none
@ -42,7 +42,14 @@ module ddr3_controller #(
wb_sel_bits = wb_data_bits / 8
)
(
input wire i_controller_clk, i_ddr3_clk, //i_controller_clk has period of CONTROLLER_CLK_PERIOD, i_ddr3_clk has period of DDR3_CLK_PERIOD
input wire i_controller_clk, i_ddr3_clk, i_ddr3_clk_n, //i_controller_clk has period of CONTROLLER_CLK_PERIOD, i_ddr3_clk has period of DDR3_CLK_PERIOD
// i_ddr3_clk_n is used for ISERDES
/* The only valid clocking arrangements for the ISERDESE2 block using the networking
interface type are:
CLK driven by BUFIO, CLKDIV driven by BUFR
CLK driven by MMCM or PLL, CLKDIV driven by CLKOUT[0:6] of same MMCM or
PLL
*/
input wire i_rst_n, //200MHz input clock
// Wishbone inputs
input wire i_wb_cyc, //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled)
@ -55,7 +62,7 @@ module ddr3_controller #(
// Wishbone outputs
output reg o_wb_stall, //1 = busy, cannot accept requests
output reg o_wb_ack, //1 = read/write request has completed
output reg[wb_data_bits - 1:0] o_wb_data, //read data, for a 4:1 controller data width is 8 times the number of pins on the device
output wire[wb_data_bits - 1:0] o_wb_data, //read data, for a 4:1 controller data width is 8 times the number of pins on the device
output reg o_aux, //for AXI-interface compatibility (returned upon ack)
// PHY Interface (to be added later)
output wire ck_en, // CKE
@ -67,8 +74,8 @@ module ddr3_controller #(
output wire reset_n,
output wire[ROW_BITS-1:0] addr,
output wire[BA_BITS-1:0] ba_addr,
output wire[(DQ_BITS*LANES)-1:0] dq,
output wire[(DQ_BITS*LANES)/8-1:0] dqs, dqs_n
input wire[(DQ_BITS*LANES)-1:0] dq,
input wire[(DQ_BITS*LANES)/8-1:0] dqs, dqs_n
////////////////////////////////////
);
@ -99,8 +106,8 @@ module ddr3_controller #(
CMD_RAS_N = CMD_LEN - 2,
CMD_CAS_N= CMD_LEN - 3,
CMD_WE_N = CMD_LEN - 4,
CMD_CK_EN = CMD_LEN - 5,
CMD_ODT = CMD_LEN - 6,
CMD_ODT = CMD_LEN - 5,
CMD_CK_EN = CMD_LEN - 6,
CMD_RESET_N = CMD_LEN - 7,
CMD_BANK_START = BA_BITS + ROW_BITS - 1,
CMD_ROW_ADDRESS_START = ROW_BITS - 1;
@ -128,8 +135,10 @@ module ddr3_controller #(
localparam[1:0] MPR_LOC = 2'b00; //Data location for MPR Reads: Predefined Pattern 0_1_0_1_0_1_0_1
localparam[0:0] MPR_EN = 1'b0; //MPR Enable: Enable MPR reads and calibration during initialization
localparam[2:0] MR3_SEL = 3'b011; //MPR Selected
localparam[18:0] MR3 = {MR3_SEL, 13'b0_0000_0000_0000, MPR_EN, MPR_LOC};
localparam[18:0] MR3_EN = {MR3_SEL, 13'b0_0000_0000_0000, 1'b1, MPR_LOC};
localparam[18:0] MR3_DIS = {MR3_SEL, 13'b0_0000_0000_0000, 1'b0, MPR_LOC};
localparam[ROW_BITS+BA_BITS-1:0] MR3_RD_ADDR = 0;
// MR1 (JEDEC DDR3 doc pg. 27)
localparam DLL_EN = 1'b0; //DLL Enable/Disable: Enabled(0)
localparam[1:0] DIC = 2'b00; //Output Driver Impedance Control (IS THIS THE SAME WITH RTT_NOM???????????? Search later)
@ -192,7 +201,7 @@ module ddr3_controller #(
localparam DELAY_MAX_VALUE = ns_to_cycles(INITIAL_CKE_LOW); //Largest possible delay needed by the reset and refresh sequence
localparam DELAY_COUNTER_WIDTH= $clog2(DELAY_MAX_VALUE); //Bitwidth needed by the maximum possible delay, this will be the delay counter width
localparam DELAY_SLOT_WIDTH = 19; //Bitwidth of the delay slot and mode register slot on the reset/refresh rom will be at the same size as the Mode Register
localparam READ_CAL_DELAY = 100;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
localparam PRE_STALL_DELAY = 10;
@ -214,7 +223,7 @@ module ddr3_controller #(
// Timer-Delay or MRS = 18:0 //timer delay and MRS shares same slot, thus MRS commands cannot have delays
// NOTE: The timer delay is a delay in clock cycles AFTER EXECUTING COMMAND, not the ACTUAL CYCLES of the command (delay of 1 means 2 clock cycles of command execution)
function [27:0] read_rom_instruction(input[3:0] instruction_address);
function [27:0] read_rom_instruction(input[5:0] instruction_address);
case(instruction_address)
4'd0: read_rom_instruction = {5'b01000 , CMD_NOP , ns_to_cycles(POWER_ON_RESET_HIGH)};
@ -236,9 +245,8 @@ module ddr3_controller #(
4'd4: read_rom_instruction = {5'b01011, CMD_NOP, nCK_to_cycles(tMRD)};
//4. Delay of tMRD between MRS commands
4'd5: read_rom_instruction = {5'b00011, CMD_MRS, MR3};
//5. Issue MRS command to load MR3. Prior to enabling the MPR for read calibration, all banks must be in the idle state (all banks
// precharged and tRP met). Once the MPR is enabled, any subsequent RD or RDA commands will be redirected to the MultiPurpose Register.
4'd5: read_rom_instruction = {5'b00011, CMD_MRS, MR3_DIS};
//5. All banks must first be in the idle state (all banks precharged and tRP met) before doing MPR calibration, thus issue first disabled MR3
4'd6: read_rom_instruction = {5'b01011, CMD_NOP, nCK_to_cycles(tMRD)};
//6. Delay of tMRD between MRS commands
@ -260,18 +268,32 @@ module ddr3_controller #(
//inside the DRAM and, once calibration is achieved, the calibrated values area transferred from the calibration engine to
//DRAM IO, which gets reflected as updated output driver
// Perform first refresh and any subsequent refresh (so instruction 12 to 15 will be re-used for the refresh sequence)
// Precharge all banks before enabling MPR
4'd12: read_rom_instruction = {5'b01011, CMD_PRE, ns_to_cycles(tRP)};
//12. All banks must be precharged (A10-AP = high) and idle for a minimum of the precharge time tRP(min) before the Refresh Command can be applied.
4'd13: read_rom_instruction = {5'b01011, CMD_REF, ns_to_cycles(tRFC)};
4'd13: read_rom_instruction = {5'b00011, CMD_MRS, MR3_EN};
//13. Issue MRS command to load MR3. Prior to enabling the MPR for read calibration, all banks must be in the idle state (all banks
// precharged and tRP met). Once the MPR is enabled, any subsequent RD or RDA commands will be redirected to the MultiPurpose Register.
4'd14: read_rom_instruction = {5'b01011, CMD_NOP, tMOD};
//14. Delay of tMOD between MRS command to a non-MRS command excluding NOP and DES
4'd15: read_rom_instruction = {5'b00011, CMD_NOP, READ_CAL_DELAY};
//15. Delay for read/write calibration
// Perform first refresh and any subsequent refresh (so instruction 12 to 15 will be re-used for the refresh sequence)
4'd16: read_rom_instruction = {5'b01011, CMD_PRE, ns_to_cycles(tRP)};
//12. All banks must be precharged (A10-AP = high) and idle for a minimum of the precharge time tRP(min) before the Refresh Command can be applied.
4'd17: read_rom_instruction = {5'b01011, CMD_REF, ns_to_cycles(tRFC)};
//13. A delay between the Refresh Command and the next valid command, except NOP or DES, must be greater than or equal to the minimum
//Refresh cycle time tRFC(min)
4'd14: read_rom_instruction = {5'b11011, CMD_NOP, ns_to_cycles(tREFI)};
4'd18: read_rom_instruction = {5'b11011, CMD_NOP, ns_to_cycles(tREFI)};
//14. Reset ends now. The refresh interval also starts to count.
4'd15: read_rom_instruction = {5'b01011, CMD_NOP, PRE_STALL_DELAY[DELAY_SLOT_WIDTH-1:0]};
4'd19: read_rom_instruction = {5'b01011, CMD_NOP, PRE_STALL_DELAY[DELAY_SLOT_WIDTH-1:0]};
// 15. Extra delay needed before starting the refresh sequence. (this already sets the wishbone stall high to make sure no user request is on-going when refresh seqeunce starts)
default: read_rom_instruction = {5'b00011, CMD_NOP, {(DELAY_SLOT_WIDTH){1'b0}}};
@ -345,8 +367,8 @@ module ddr3_controller #(
//Also, worscase is when the anticipated bank still has the leftover of the
//WRITE_TO_PRECHARGE_DELAY thus consider also this.
localparam MARGIN_BEFORE_ANTICIPATE = PRECHARGE_TO_ACTIVATE_DELAY + ACTIVATE_TO_WRITE_DELAY + WRITE_TO_PRECHARGE_DELAY;
localparam STAGE2_DATA_DEPTH = ($rtoi($floor((CWL_nCK - (3 - WRITE_SLOT + 1))/4.0 )));
localparam STAGE2_DATA_DEPTH = ($rtoi($floor((CWL_nCK - (3 - WRITE_SLOT + 1))/4.0 ))) + 1; //this is always >= 1
localparam READ_DELAY = $rtoi($floor((CL_nCK - (3 - READ_SLOT + 1))/4.0 ));
reg[(1<<BA_BITS)-1:0] bank_status_q, bank_status_d; //bank_status[bank_number]: determine current state of bank (1=active , 0=idle)
reg[ROW_BITS-1:0] bank_active_row_q[(1<<BA_BITS)-1:0], bank_active_row_d[(1<<BA_BITS)-1:0]; //bank_active_row[bank_number] = stores the active row address in the specified bank
@ -392,7 +414,7 @@ module ddr3_controller #(
reg[3:0] delay_before_write_counter_q[(1<<BA_BITS)-1:0], delay_before_write_counter_d[(1<<BA_BITS)-1:0] ;
reg[3:0] delay_before_read_counter_q[(1<<BA_BITS)-1:0] , delay_before_read_counter_d[(1<<BA_BITS)-1:0] ;
reg[3:0] delay_before_odt_off_q, delay_before_odt_off_d;
reg[3:0] delay_before_read_ack_q, delay_before_read_ack_d;
//set all delay counters to zero
initial begin
for(index=0; index<(1<<BA_BITS); index=index+1) begin
@ -402,6 +424,7 @@ module ddr3_controller #(
delay_before_read_counter_q[index] = 0;
end
delay_before_odt_off_q = 0;
delay_before_read_ack_q = 0;
end
//commands to be sent to PHY (4 slots per controller clk cycle)
@ -419,7 +442,8 @@ module ddr3_controller #(
reg pipe_stall;
reg precharge_slot_busy;
reg activate_slot_busy;
reg[(STAGE2_DATA_DEPTH+1)*4+8-1:0] write_dqs_q, write_dqs_d;
reg write_dqs_q, write_dqs_d;
reg[STAGE2_DATA_DEPTH+1:0] write_dqs;
//process request transaction
always @(posedge i_controller_clk, negedge i_rst_n) begin
@ -442,7 +466,9 @@ module ddr3_controller #(
stage2_bank <= 0;
stage2_row <= 0;
delay_before_odt_off_q <= 0;
delay_before_read_ack_q <= 0;
write_dqs_q <= 0;
write_dqs <= 0;
//set delay counters to 0
for(index=0; index<(1<<BA_BITS); index=index+1) begin
delay_before_precharge_counter_q[index] <= 0;
@ -465,7 +491,7 @@ module ddr3_controller #(
else if(1/*reset_done*/) begin
o_wb_stall <= o_wb_stall_d;
o_wb_ack <= o_wb_ack_d;
write_dqs_q <= write_dqs_d;
//update delay counter
for(index=0; index< (1<<BA_BITS); index=index+1) begin
delay_before_precharge_counter_q[index] <= delay_before_precharge_counter_d[index];
@ -474,10 +500,11 @@ module ddr3_controller #(
delay_before_read_counter_q[index] <= delay_before_read_counter_d[index];
end
delay_before_odt_off_q <= delay_before_odt_off_d;
delay_before_read_ack_q <= delay_before_read_ack_d;
//update cmd
//for( index=0; index < 4; index=index+1) begin
// cmd_q[index] <= cmd_d[index];
//end
for( index=0; index < 4; index=index+1) begin
cmd_q[index] <= cmd_d[index];
end
//update bank status and active row
for(index=0; index < (1<<BA_BITS); index=index+1) begin
bank_status_q[index] <= bank_status_d[index];
@ -508,7 +535,8 @@ module ddr3_controller #(
stage2_bank <= stage1_bank;
stage2_row <= stage1_row;
stage2_data[0] <= stage1_data;
write_dqs_q <= write_dqs_d;
write_dqs[0] <= write_dqs_d || write_dqs_q; //high for 2 clk cycles
//stage2_data -> shiftreg(CWL) -> OSERDES(DDR) -> ODELAY -> RAM
end
@ -532,7 +560,10 @@ module ddr3_controller #(
end
for(index = 1; index <= STAGE2_DATA_DEPTH; index = index+1) begin
stage2_data[index] <= stage2_data[index-1];
stage2_data[index] <= stage2_data[index-1];
end
for(index = 1; index <= STAGE2_DATA_DEPTH+1; index = index+1) begin
write_dqs[index] <= write_dqs[index-1];
end
end
end
@ -554,14 +585,19 @@ module ddr3_controller #(
//
//Pipeline Stages:
// wishbone inputs --> stage1 --> stage2 --> cmd
reg cmd_odt, cmd_ck_en, cmd_reset_n;
always @* begin
cmd_odt = 0;
cmd_ck_en = 1;
cmd_reset_n = 1;
o_wb_ack_d = 0; //ack goes high for every r/w request
o_wb_stall_d = 0; //wb_stall going high is determined on stage 1 (higher priority), wb_stall going low is determined at stage2 (lower priority)
pipe_stall = 0; //pipe_stall will follow i_wb_stall(so stall when stage 2 needs delay) but goes low after actual read/write request (move pipe forward when stage2 finishes request)
precharge_slot_busy = 0; //flag that determines if stage 2 is issuing precharge (thus stage 1 cannot issue precharge)
activate_slot_busy = 0; //flag that determines if stage 2 is issuing activate (thus stage 1 cannot issue activate)
write_dqs_d = write_dqs_q>>4;
write_dqs_d = 0;
for(index=0; index < (1<<BA_BITS); index=index+1) begin
bank_status_d[index] = bank_status_q[index];
bank_active_row_d[index] = bank_active_row_q[index];
@ -581,6 +617,8 @@ module ddr3_controller #(
delay_before_read_counter_d[index] = (delay_before_read_counter_q[index] == 0)? 0:delay_before_read_counter_q[index] - 1;
end
delay_before_odt_off_d = (delay_before_odt_off_q == 0)? 0 : delay_before_odt_off_q - 1;
delay_before_read_ack_d = (delay_before_read_ack_q == 0)? 0 : delay_before_read_ack_q - 1;
o_wb_ack_d = delay_before_read_ack_q == 1;
//if there is a pending request, issue the appropriate commands
if(stage2_pending) begin
o_wb_stall_d = o_wb_stall;
@ -592,42 +630,43 @@ module ddr3_controller #(
o_wb_stall_d = 0;
o_wb_ack_d = 1;
pipe_stall = 0; //move pipeline forward since write access is already done
cmd_odt = 1;
//set-up delay before precharge, read, and write
delay_before_precharge_counter_d[stage2_bank] = WRITE_TO_PRECHARGE_DELAY;
delay_before_read_counter_d[stage2_bank] = WRITE_TO_READ_DELAY;
delay_before_write_counter_d[stage2_bank] = WRITE_TO_WRITE_DELAY;
delay_before_odt_off_d = STAGE2_DATA_DEPTH + 1;
delay_before_odt_off_d = STAGE2_DATA_DEPTH;
//issue read command
if(COL_BITS <= 10) begin
cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], {{ROW_BITS+BA_BITS-4'd11}{1'b0}} , 1'b0 , stage2_col[9:0]};
cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, {{ROW_BITS+BA_BITS-4'd11}{1'b0}} , 1'b0 , stage2_col[9:0]};
end
else begin
cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], {{ROW_BITS+BA_BITS-4'd12}{1'b0}} , stage2_col[10] , 1'b0 , stage2_col[9:0]};
cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, {{ROW_BITS+BA_BITS-4'd12}{1'b0}} , stage2_col[10] , 1'b0 , stage2_col[9:0]};
end
//add ODT bit, turn on odt at same time as write cmd
cmd_d[0][CMD_ODT] = 1;
cmd_d[1][CMD_ODT] = 1;
cmd_d[2][CMD_ODT] = 1;
cmd_d[3][CMD_ODT] = 1;
write_dqs_d[(STAGE2_DATA_DEPTH+1)*4 +: 8] = 8'b0001_1111;
write_dqs_d=1;
// write_data = 1;
end
//read request
else if(!stage2_we && delay_before_read_counter_q[stage2_bank]==0) begin
o_wb_stall_d = 0;
o_wb_ack_d = 1;
pipe_stall = 0; //move pipeline forward since read access is already done
//set-up delay before precharge, read, and write
delay_before_precharge_counter_d[stage2_bank] = READ_TO_PRECHARGE_DELAY;
delay_before_read_counter_d[stage2_bank] = READ_TO_READ_DELAY;
delay_before_write_counter_d[stage2_bank] = READ_TO_WRITE_DELAY;
delay_before_read_ack_d = READ_DELAY + 1 + 2 + 1; ///1=issue command delay (OSERDES delay), 2 = ISERDES delay
//issue read command
if(COL_BITS <= 10) begin
cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], {{ROW_BITS+BA_BITS-4'd11}{1'b0}} , 1'b0 , stage2_col[9:0]};
cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, {{ROW_BITS+BA_BITS-4'd11}{1'b0}} , 1'b0 , stage2_col[9:0]};
end
else begin
cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], {{ROW_BITS+BA_BITS-4'd12}{1'b0}} , stage2_col[10] , 1'b0 , stage2_col[9:0]};
cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, {{ROW_BITS+BA_BITS-4'd12}{1'b0}} , stage2_col[10] , 1'b0 , stage2_col[9:0]};
end
end
end
@ -639,7 +678,7 @@ module ddr3_controller #(
delay_before_read_counter_d[stage2_bank] = ACTIVATE_TO_READ_DELAY;
delay_before_write_counter_d[stage2_bank] = ACTIVATE_TO_WRITE_DELAY;
//issue activate command
cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , stage2_bank , stage2_row};
cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank , stage2_row};
//update bank status and active row
bank_status_d[stage2_bank] = 1'b1;
bank_active_row_d[stage2_bank] = stage2_row;
@ -651,7 +690,7 @@ module ddr3_controller #(
//set-up delay before activate
delay_before_activate_counter_d[stage2_bank] = PRECHARGE_TO_ACTIVATE_DELAY;
//issue precharge command
cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], stage2_bank, { {{ROW_BITS-4'd11}{1'b0}} , 1'b0 , stage2_row[9:0] } };
cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, { {{ROW_BITS-4'd11}{1'b0}} , 1'b0 , stage2_row[9:0] } };
//update bank status and active row
bank_status_d[stage2_bank] = 1'b0;
end
@ -673,7 +712,7 @@ module ddr3_controller #(
//set-up delay before read and write
delay_before_read_counter_d[stage1_next_bank] = ACTIVATE_TO_READ_DELAY;
delay_before_write_counter_d[stage1_next_bank] = ACTIVATE_TO_WRITE_DELAY;
cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], stage1_next_bank, { {{ROW_BITS-4'd11}{1'b0}} , 1'b0 , stage1_next_row[9:0] } };
cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank, { {{ROW_BITS-4'd11}{1'b0}} , 1'b0 , stage1_next_row[9:0] } };
bank_status_d[stage1_next_bank] = 1'b0;
end //end of anticipate precharge
@ -682,7 +721,7 @@ module ddr3_controller #(
//set-up delay before read and write
delay_before_read_counter_d[stage1_next_bank] = ACTIVATE_TO_READ_DELAY;
delay_before_write_counter_d[stage1_next_bank] = ACTIVATE_TO_WRITE_DELAY;
cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , stage1_next_bank , stage1_next_row};
cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank , stage1_next_row};
bank_status_d[stage1_next_bank] = 1'b1;
bank_active_row_d[stage1_next_bank] = stage1_next_row;
end //end of anticipate activate
@ -707,46 +746,61 @@ module ddr3_controller #(
end //end of always block
//////////////////////////////////////////////////////////////////////// PHY Interface ////////////////////////////////////////////////////////////////////////////////////////////////////
wire[(DQ_BITS*LANES)-1:0] oserdes_data, odelay_data, read_dq;
wire[LANES-1:0] odelay_dqs, read_dqs;
wire[(DQ_BITS*LANES)-1:0] oserdes_data, odelay_data, idelay_data, read_dq;
wire[LANES-1:0] odelay_dqs, read_dqs, idelay_dqs;
wire[7:0] dqs_Q[LANES-1:0];//
wire idelayctrl_rdy;
reg[LANES-1:0] odelay_ce=0, odelay_inc=0, odelay_ld=0;
reg[LANES-1:0] idelay_ce=0, idelay_inc=0, idelay_ld=0;
reg write_data=0, write_dqs=0;
wire oserdes_dqs;
genvar gen_index;
reg[CMD_LEN-1:0] aligned_cmd;
wire[CMD_LEN-1:0] oserdes_cmd;
wire[CMD_LEN-1:0] cmd;
reg[1:0] serial_index,serial_index_q;
wire[DQ_BITS*LANES-1:0] Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8;
wire[7:0] test_Q[LANES-1:0];
wire test_OFB;
reg[LANES-1:0] bitslip;
/*
always @(posedge i_ddr3_clk) begin
if(!i_rst_n) begin
serial_index <=0;
write_dqs_q <= 0;
//set cmd to NOP
for( index=0; index < (1<<4); index=index+1) begin
cmd_q[index] <= -1;
end
end
else begin
case(serial_index)
0: begin
//update cmd
for( index=0; index < 4; index=index+1) begin
cmd_q[index] <= cmd_d[index];
end
aligned_cmd <= cmd_d[0];
end
1: aligned_cmd <= cmd_q[1];
2: aligned_cmd <= cmd_q[2];
3: aligned_cmd <= cmd_q[3];
endcase
serial_index <= serial_index + 1;
serial_index_q <= serial_index;
write_dqs <= write_dqs_q[serial_index_q];
end
end
for(gen_index = 0; gen_index < CMD_LEN; gen_index = gen_index + 1) begin
*/
//PHY cmd
generate
for(gen_index = 0; gen_index < CMD_LEN; gen_index = gen_index + 1) begin
// OSERDESE2: Output SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
OSERDESE2 #(
.DATA_RATE_OQ("SDR"), // DDR, SDR
.DATA_WIDTH(4), // Parallel data width (2-8,10,14)
.INIT_OQ(1'b0) // Initial value of OQ output (1'b0,1'b1)
)
OSERDESE2_cmd(
.OFB(oserdes_cmd[gen_index]), // 1-bit output: Feedback path for data
.OQ(), // 1-bit output: Data path output
.CLK(i_ddr3_clk), // 1-bit input: High speed clock
.CLKDIV(i_controller_clk), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1(cmd_d[0][gen_index]),
.D2(cmd_d[1][gen_index]),
.D3(cmd_d[2][gen_index]),
.D4(cmd_d[3][gen_index]),
.OCE(1), // 1-bit input: Output data clock enable
.RST(!i_rst_n) // 1-bit input: Reset
);
// End of OSERDESE2_inst instantiation
(* IODELAY_GROUP = 0 *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
//Delay the DQ
// Delay resolution: 1/(32 x 2 x F REF ) = 78.125ps
@ -770,14 +824,16 @@ module ddr3_controller #(
.LD(0), // 1-bit input: Loads ODELAY_VALUE tap delay in VARIABLE mode, in VAR_LOAD or
// VAR_LOAD_PIPE mode, loads the value of CNTVALUEIN
.LDPIPEEN(0), // 1-bit input: Enables the pipeline register to load data
.ODATAIN(aligned_cmd[gen_index]), // 1-bit input: Output delay data input
.ODATAIN(oserdes_cmd[gen_index]), // 1-bit input: Output delay data input
.REGRST(0) // 1-bit input: Active-high reset tap-delay input
);
end
assign {cs_n, ras_n, cas_n, we_n, ck_en, reset_n, odt, ba_addr, addr} = cmd;
end
endgenerate
assign {cs_n, ras_n, cas_n, we_n, odt, ck_en, reset_n, ba_addr, addr} = cmd;
assign o_wb_data = {Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8};
// End of OSERDESE2_inst instantiation
// PHY data
generate
// data: oserdes -> odelay -> iobuf
for(gen_index = 0; gen_index < (DQ_BITS*LANES); gen_index = gen_index + 1) begin
@ -854,9 +910,109 @@ module ddr3_controller #(
.O(read_dq[gen_index]),// Buffer output
.IO(dq[gen_index]), // Buffer inout port (connect directly to top-level port)
.I(odelay_data[gen_index]), // Buffer input
.T(write_data) // 3-state enable input, high=read, low=write
.T(!write_dqs[STAGE2_DATA_DEPTH+1]) // 3-state enable input, high=read, low=write
);
// End of IOBUF_inst instantiation
// IDELAYE2: Input Fixed or Variable Delay Element
// 7 Series
// Xilinx HDL Libraries Guide, version 13.4
(* IODELAY_GROUP = 0 *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYE2 #(
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), //Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VARIABLE"), //FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(4), //Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), //Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), //IDELAYCTRL clock input frequency in MHz (190.0-210.0).
.SIGNAL_PATTERN("DATA") //DATA, CLOCK input signal
)
IDELAYE2_data (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(idelay_data[gen_index]), // 1-bit output: Delayed data output
.C(i_controller_clk), // 1-bit input: Clock input
.CE(idelay_ce[$rtoi($floor(gen_index/8))]), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(0),// 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(0), // 5-bit input: Counter value input
.DATAIN(), //1-bit input: Internal delay data input
.IDATAIN(read_dq[gen_index]), // 1-bit input: Data input from the I/O
.INC(idelay_inc[$rtoi($floor(gen_index/8))]), // 1-bit input: Increment / Decrement tap delay input
.LD(idelay_ld[$rtoi($floor(gen_index/8))]), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(0) // 1-bit input: Active-high reset tap-delay input
);
// End of IDELAYE2_inst instantiation
// End of IOBUF_inst instantiation
// ISERDESE2: Input SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
ISERDESE2 #(
.DATA_RATE("DDR"), // DDR, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
// INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),
.INTERFACE_TYPE("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD
.NUM_CE(1),// Number of clock enables (1,2)
.OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE)
// SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_data (
.O(),
// 1-bit output: Combinatorial output
// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q1(Q1[gen_index]),
.Q2(Q2[gen_index]),
.Q3(Q3[gen_index]),
.Q4(Q4[gen_index]),
.Q5(Q5[gen_index]),
.Q6(Q6[gen_index]),
.Q7(Q7[gen_index]),
.Q8(Q8[gen_index]),
// SHIFTOUT1-SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1(),
.SHIFTOUT2(),
.BITSLIP(bitslip[$rtoi($floor(gen_index/8))]),
// 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
// CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
// to Q8 output ports will shift, as in a barrel-shifter operation, one
// position every time Bitslip is invoked (DDR operation is different from
// SDR).
// CE1, CE2: 1-bit (each) input: Data register clock enable inputs
.CE1(1),
.CE2(1),
.CLKDIVP(), // 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK(i_ddr3_clk), // 1-bit input: High-speed clock
.CLKB(!i_ddr3_clk), // 1-bit input: High-speed secondary clock
.CLKDIV(i_controller_clk), // 1-bit input: Divided clock
.OCLK(), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
// Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
.DYNCLKDIVSEL(), // 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL(), // 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D(idelay_data[gen_index]), // 1-bit input: Data input
.DDLY(), // 1-bit input: Serial data from IDELAYE2
.OFB(), // 1-bit input: Data feedback from OSERDESE2
.OCLKB(), // 1-bit input: High speed negative edge output clock
.RST(!i_rst_n), // 1-bit input: Active high asynchronous reset
// SHIFTIN1-SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1(),
.SHIFTIN2()
);
// End of ISERDESE2_inst instantiation
end
//800MHz =
// dqs: odelay -> iobuf
@ -906,11 +1062,203 @@ module ddr3_controller #(
.IO(dqs[gen_index]), // Diff_p inout (connect directly to top-level port)
.IOB(dqs_n[gen_index]), // Diff_n inout (connect directly to top-level port)
.I(odelay_dqs[gen_index]), // Buffer input
.T(!write_dqs_q[serial_index_q]) // 3-state enable input, high=input, low=output
.T(!write_dqs[STAGE2_DATA_DEPTH+1]) // 3-state enable input, high=input, low=output
); // End of IOBUFDS_inst instantiation
// IDELAYE2: Input Fixed or Variable Delay Element
// 7 Series
// Xilinx HDL Libraries Guide, version 13.4
(* IODELAY_GROUP = 0 *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYE2 #(
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), //Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VARIABLE"), //FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(8), //Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), //Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), //IDELAYCTRL clock input frequency in MHz (190.0-210.0).
.SIGNAL_PATTERN("DATA") //DATA, CLOCK input signal
)
IDELAYE2_dqs (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(idelay_dqs[gen_index]), // 1-bit output: Delayed data output
.C(i_controller_clk), // 1-bit input: Clock input
.CE(idelay_ce[gen_index]), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(0),// 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(0), // 5-bit input: Counter value input
.DATAIN(), //1-bit input: Internal delay data input
.IDATAIN(read_dqs[gen_index]), // 1-bit input: Data input from the I/O
.INC(idelay_inc[gen_index]), // 1-bit input: Increment / Decrement tap delay input
.LD(idelay_ld[gen_index]), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(0) // 1-bit input: Active-high reset tap-delay input
);
// End of IDELAYE2_inst instantiation
// End of IOBUF_inst instantiation
// ISERDESE2: Input SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
ISERDESE2 #(
.DATA_RATE("DDR"), // DDR, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
// INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),
.INTERFACE_TYPE("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD
.NUM_CE(1),// Number of clock enables (1,2)
.OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE)
// SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_dqs (
.O(),
// 1-bit output: Combinatorial output
// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q1(dqs_Q[gen_index][7]),
.Q2(dqs_Q[gen_index][6]),
.Q3(dqs_Q[gen_index][5]),
.Q4(dqs_Q[gen_index][4]),
.Q5(dqs_Q[gen_index][3]),
.Q6(dqs_Q[gen_index][2]),
.Q7(dqs_Q[gen_index][1]),
.Q8(dqs_Q[gen_index][0]),
// SHIFTOUT1-SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1(),
.SHIFTOUT2(),
.BITSLIP(bitslip),
// 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
// CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
// to Q8 output ports will shift, as in a barrel-shifter operation, one
// position every time Bitslip is invoked (DDR operation is different from
// SDR).
// CE1, CE2: 1-bit (each) input: Data register clock enable inputs
.CE1(1),
.CE2(1),
.CLKDIVP(), // 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK(i_ddr3_clk), // 1-bit input: High-speed clock
.CLKB(!i_ddr3_clk), // 1-bit input: High-speed secondary clock
.CLKDIV(i_controller_clk), // 1-bit input: Divided clock
.OCLK(), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
// Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
.DYNCLKDIVSEL(), // 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL(), // 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D(idelay_dqs[gen_index]), // 1-bit input: Data input
.DDLY(), // 1-bit input: Serial data from IDELAYE2
.OFB(), // 1-bit input: Data feedback from OSERDESE2
.OCLKB(), // 1-bit input: High speed negative edge output clock
.RST(!i_rst_n), // 1-bit input: Active high asynchronous reset
// SHIFTIN1-SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1(),
.SHIFTIN2()
);
// End of ISERDESE2_inst instantiation
//ISERDES train
// End of IOBUF_inst instantiation
// ISERDESE2: Input SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
ISERDESE2 #(
.DATA_RATE("DDR"), // DDR, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
// INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),
.INTERFACE_TYPE("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD
.NUM_CE(1),// Number of clock enables (1,2)
.OFB_USED("TRUE"), // Select OFB path (FALSE, TRUE)
// SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_train (
.O(),
// 1-bit output: Combinatorial output
// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q1(test_Q[gen_index][7]),
.Q2(test_Q[gen_index][6]),
.Q3(test_Q[gen_index][5]),
.Q4(test_Q[gen_index][4]),
.Q5(test_Q[gen_index][3]),
.Q6(test_Q[gen_index][2]),
.Q7(test_Q[gen_index][1]),
.Q8(test_Q[gen_index][0]),
// SHIFTOUT1-SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1(),
.SHIFTOUT2(),
.BITSLIP(bitslip[gen_index]),
// 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
// CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
// to Q8 output ports will shift, as in a barrel-shifter operation, one
// position every time Bitslip is invoked (DDR operation is different from
// SDR).
// CE1, CE2: 1-bit (each) input: Data register clock enable inputs
.CE1(1),
.CE2(1),
.CLKDIVP(), // 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK(i_ddr3_clk), // 1-bit input: High-speed clock
.CLKB(!i_ddr3_clk), // 1-bit input: High-speed secondary clock
.CLKDIV(i_controller_clk), // 1-bit input: Divided clock
.OCLK(), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
// Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
.DYNCLKDIVSEL(), // 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL(), // 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D(), // 1-bit input: Data input
.DDLY(), // 1-bit input: Serial data from IDELAYE2
.OFB(test_OFB), // 1-bit input: Data feedback from OSERDESE2
.OCLKB(), // 1-bit input: High speed negative edge output clock
.RST(!i_rst_n), // 1-bit input: Active high asynchronous reset
// SHIFTIN1-SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1(),
.SHIFTIN2()
);
// End of ISERDESE2_inst instantiation
end
endgenerate
// OSERDESE2: Output SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
OSERDESE2 #(
.DATA_RATE_OQ("DDR"), // DDR, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
.INIT_OQ(1'b1) // Initial value of OQ output (1'b0,1'b1)
)
OSERDESE2_train(
.OFB(test_OFB), // 1-bit output: Feedback path for data
.OQ(), // 1-bit output: Data path output
.CLK(i_ddr3_clk), // 1-bit input: High speed clock
.CLKDIV(i_controller_clk), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1(1'b0),
.D2(1'b0),
.D3(1'b0),
.D4(1'b0),
.D5(1'b1),
.D6(1'b1),
.D7(1'b1),
.D8(1'b1),
.OCE(1), // 1-bit input: Output data clock enable
.RST(!i_rst_n) // 1-bit input: Reset
);
// End of OSERDESE2_inst instantiation
// OSERDESE2: Output SERial/DESerializer with bitslip
//7 Series
// Xilinx HDL Libraries Guide, version 13.4
@ -948,6 +1296,152 @@ module ddr3_controller #(
.RST(!i_rst_n) // 1-bit input: Active high reset input, To ,Minimum Reset pulse width is 52ns
);
// End of IDELAYCTRL_inst instantiation
reg[3:0] state_calibrate;
localparam IDLE = 0,
BITSLIP_DQS_TRAIN = 1,
MPR_READ = 2,
READ_DQS = 3,
BITSLIP_DQ_TRAIN = 4,
DONE_CALIBRATE = 5;
reg[1:0] train_delay;
reg initial_read = 1;
reg[CMD_LEN-1:0] cmd_reset_seq[3:0];
reg[3:0] delay_before_read_data = 0;
reg[7:0] initial_dqs[LANES-1:0];
reg[7:0] calibrated_dqs[LANES-1:0];
reg[7:0] bitslip_pattern;
reg[LANES-1:0] lane = 0;
//set all commands to all 1's makig CS_n high (thus commands are initially NOP)
initial begin
for(index=0; index< 4; index=index+1) begin
cmd_reset_seq[index] = -1;
cmd_reset_seq[index][CMD_ODT] = 0;
end
end
always @(posedge i_controller_clk, negedge i_rst_n) begin
if(!i_rst_n) begin
state_calibrate <= IDLE;
train_delay <= 0;
for(index = 0; index < LANES; index = index + 1) begin
bitslip[index] <= 0;
end
initial_read <= 1;
lane <= 0;
end
else begin
train_delay <= (train_delay==0)? 0:(train_delay - 1);
delay_before_read_data <= (delay_before_read_data == 0)? 0: delay_before_read_data - 1;
for(index=0; index < LANES; index=index+1) begin
idelay_ce[index] <= 0;
idelay_inc[index] <= 0;
end
for(index=0; index < LANES; index=index+1) begin
cmd_reset_seq[index] <= -1;
cmd_reset_seq[index][CMD_ODT] <= 0;
end
//set all cmd_d to NOP
for(index=0; index < 4; index=index+1) begin
cmd_reset_seq[index] <= -1;
cmd_reset_seq[index][CMD_ODT] <= 0;
end
case(state_calibrate)
IDLE: if(idelayctrl_rdy) begin
state_calibrate <= BITSLIP_DQS_TRAIN;
lane <= 0;
end
BITSLIP_DQS_TRAIN: begin
/* Bitslip cannot be asserted for two consecutive CLKDIV cycles; Bitslip must be
deasserted for at least one CLKDIV cycle between two Bitslip assertions.The user
logic should wait for at least two CLKDIV cycles in SDR mode or three CLKDIV cycles
in DDR mode, before analyzing the received data pattern and potentially issuing
another Bitslip command. If the ISERDESE2 is reset, the Bitslip logic is also reset
and returns back to its initial state.
*/
bitslip[lane] <= 0;
if(test_Q[lane] != 8'b0111_1000 && train_delay == 0) begin
bitslip[lane] <= 1;
train_delay <= 3;
end
if(test_Q[lane] == 8'b0111_1000) begin
if(lane == 7) begin
state_calibrate <= MPR_READ;
lane <= 0;
end
else begin
lane <= lane + 1;
end
end
end
MPR_READ: if(instruction_address == 15) begin //align the incoming DQS during reads to the controller clock
cmd_reset_seq[0] <= {1'b0, CMD_RD[2:0], 1'b0, 1'b1, 1'b1, MR3_RD_ADDR}; //read command
delay_before_read_data <= READ_DELAY + 1 + 2 + 1; ///1=issue command delay (OSERDES delay), 2 = ISERDES delay
state_calibrate <= READ_DQS;
end
READ_DQS: if(delay_before_read_data == 0) begin
initial_read <= 0;
if(initial_read) begin
initial_dqs[lane] <= dqs_Q[lane];
state_calibrate <= MPR_READ;
end
else begin
//unless we match one of these conditions, continue delaying. It is possible that due to irreularities in tDQSL and tDQSH (0.45tCk - 0.55tCK), the captured DQS
//might be irregular so we need specific patterns to match so that we can be sure that the calibrated DQS is a regular and is aligned with clock
if((dqs_Q[lane] == 8'b10_10_10_00 || dqs_Q[lane] == 8'b10_10_00_00 || dqs_Q[lane] == 8'b10_00_00_00) && (dqs_Q[lane] != initial_dqs[lane])) begin
if(lane == 7) begin
state_calibrate <= BITSLIP_DQ_TRAIN;
for(index = 0; index < LANES; index = index + 1) begin
calibrated_dqs[index] <= dqs_Q[index]; //update the new dqs
end
lane <= 0;
end
else begin
initial_read <= 1;
lane <= lane + 1;
state_calibrate <= MPR_READ;
end
end
else begin
idelay_ce[lane] <= 1;
idelay_inc[lane] <= 1;
state_calibrate <= MPR_READ;
end
end
end
BITSLIP_DQ_TRAIN: begin //train again the ISERDES to capture the DQ correctly
case(calibrated_dqs[lane])
8'b10_10_10_00: bitslip_pattern = 8'b0001_1110;
8'b10_10_00_00: bitslip_pattern = 8'b1000_0111;
8'b10_00_00_00: bitslip_pattern = 8'b1110_0001;
default: bitslip_pattern = 8'b0000_0000;
endcase
bitslip[lane] <= 0;
if(test_Q[lane]!= bitslip_pattern && train_delay == 0) begin
bitslip[lane] <= 1;
train_delay <= 3;
end
if(test_Q[lane] == bitslip_pattern) begin
if(lane == 7) begin
state_calibrate <= DONE_CALIBRATE;
end
else begin
lane <= lane + 1;
end
end
end
DONE_CALIBRATE: state_calibrate <= DONE_CALIBRATE;
endcase
end
end
//////////////////////////////////////////////////////////////////////// End of PHY Interface ////////////////////////////////////////////////////////////////////////