diff --git a/rtl/ddr3_controller.v b/rtl/ddr3_controller.v index 13aea0b..1d38c24 100644 --- a/rtl/ddr3_controller.v +++ b/rtl/ddr3_controller.v @@ -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< 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< 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 ////////////////////////////////////////////////////////////////////////