From c58a9d70e6d1a5ecf331def5a92053007564fb37 Mon Sep 17 00:00:00 2001 From: AngeloJacobo Date: Sun, 3 Nov 2024 14:52:32 +0800 Subject: [PATCH] add self-refresh feature (untested) --- rtl/ddr3_controller.v | 64 ++++++++++++++++++++++++++----- rtl/ddr3_top.v | 9 ++++- testbench/ddr3_dimm_micron_sim.sv | 10 +++-- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/rtl/ddr3_controller.v b/rtl/ddr3_controller.v index 3f86357..ed8f00b 100644 --- a/rtl/ddr3_controller.v +++ b/rtl/ddr3_controller.v @@ -135,9 +135,11 @@ module ddr3_controller #( // Done Calibration pin output wire o_calib_complete, // Debug port - output wire [31:0] o_debug1 + output wire [31:0] o_debug1, // output wire [31:0] o_debug2, // output wire [31:0] o_debug3 + // User enabled self-refresh + input wire i_user_self_refresh ); @@ -150,8 +152,10 @@ module ddr3_controller #( CMD_WR = 4'b0100, // Write (A10-AP: 0 = no Auto-Precharge) (A12-BC#: 1 = Burst Length 8) CMD_RD = 4'b0101, //Read (A10-AP: 0 = no Auto-Precharge) (A12-BC#: 1 = Burst Length 8) CMD_NOP = 4'b0111, // No Operation - CMD_ZQC = 4'b0110; // ZQ Calibration (A10-AP: 0 = ZQ Calibration Short, 1 = ZQ Calibration Long) - + CMD_ZQC = 4'b0110, // ZQ Calibration (A10-AP: 0 = ZQ Calibration Short, 1 = ZQ Calibration Long) + CMD_SREF_EN = 4'b0001, + CMD_SREF_XT = 4'b0111; + localparam RST_DONE = 27, // Command bit that determines if reset seqeunce had aready finished. non-persistent (only needs to be toggled once), REF_IDLE = 27, // No refresh is about to start and no ongoing refresh. (same bit as RST_DONE) USE_TIMER = 26, // Command bit that determines if timer will be used (if delay is zero, USE_TIMER must be LOW) @@ -248,7 +252,10 @@ module ddr3_controller #( localparam DELAY_MAX_VALUE = ps_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 CALIBRATION_DELAY = 2; // must be >= 2 - + localparam tXSDLL = nCK_to_cycles(512); // cycles (controller) Exit Self Refresh to commands requiring a locked DLL + localparam tXSDLL_tRFC = tXSDLL - ps_to_cycles(tRFC); // cycles (controller) Time before refresh after exit from self-refresh + localparam tCKE = max(3, ps_to_nCK(7500) ); // nCK CKE minimum pulse width + localparam tCKESR = nCK_to_cycles(tCKE + 1); // cycles (controller) Minimum time that the DDR3 SDRAM must remain in Self-Refresh mode is tCKESR /*********************************************************************************************************************************************/ @@ -586,7 +593,8 @@ module ddr3_controller #( wire db_err_o; wire[wb_data_bits - 1:0] o_wb_data_q_decoded; /* verilator lint_on UNDRIVEN */ - + reg user_self_refresh_q; // registered i_user_self_refresh + // initial block for all regs initial begin o_wb_stall = 1; @@ -727,7 +735,7 @@ module ddr3_controller #( 5'd18: read_rom_instruction = {5'b01011, CMD_NOP, tMOD[DELAY_SLOT_WIDTH-1:0]}; //18. Delay of tMOD between MRS command to a non-MRS command excluding NOP and DES - // Perform first refresh and any subsequent refresh (so instruction 12 to 15 will be re-used for the refresh sequence) + // Perform first refresh and any subsequent refresh (so instruction 19 to 22 will be re-used for the refresh sequence) 5'd19: read_rom_instruction = {5'b01111, CMD_PRE, ps_to_cycles(tRP)}; //19. 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. @@ -740,7 +748,19 @@ module ddr3_controller #( 5'd22: read_rom_instruction = {5'b01011, CMD_NOP, PRE_REFRESH_DELAY[DELAY_SLOT_WIDTH-1:0]}; // 22. 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) + // (this already sets the wishbone stall high to make sure no user request is on-going when refresh seqeunce starts) + + 5'd23: read_rom_instruction = {5'b01111, CMD_PRE, ps_to_cycles(tRP)}; + // 23. All banks must be precharged (A10-AP = high) and idle for a minimum of the precharge time tRP(min) before the Self-Refresh Command can be applied. + + 5'd24: read_rom_instruction = {5'b01011, CMD_SREF_EN, tCKESR[DELAY_SLOT_WIDTH-1:0]}; + // 24. Self-refresh entry + // JEDEC Standard No. 79-3E Page 79: The minimum time that the DDR3 SDRAM must remain in Self-Refresh mode is tCKESR + + 5'd25: read_rom_instruction = {5'b01011, CMD_SREF_XT, tXSDLL_tRFC[DELAY_SLOT_WIDTH-1:0]}; + // 25. From 24 (Self-refresh entry), wait until user-self_refresh is disabled then wait for tXSDLL - tRFC before going to 20 (Refresh) + // JEDEC Standard No. 79-3E Page 79: Before a command that requires a locked DLL can be applied, a delay of at least tXSDLL must be satisfied. + // JEDEC Standard No. 79-3E Page 80: Upon exit from Self-Refresh, the DDR3 SDRAM requires a minimum of one extra refresh command before it is put back into Self-Refresh Mode. default: read_rom_instruction = {5'b00011, CMD_NOP, {(DELAY_SLOT_WIDTH){1'b0}}}; endcase @@ -785,14 +805,37 @@ module ddr3_controller #( if(delay_counter == 1 || !instruction[USE_TIMER]/* || skip_reset_seq_delay*/) begin delay_counter_is_zero <= 1; instruction <= read_rom_instruction(instruction_address); - instruction_address <= (instruction_address == 5'd22)? 5'd19:instruction_address+1; //wrap back of address to repeat refresh sequence + if(instruction_address == 5'd22) begin // if user_self_refresh is disabled, wrap back to 19 (Precharge All before Refresh) + instruction_address <= 5'd19; + end + else if(instruction_address == 5'd25) begin // self-refresh exit always wraps back to 20 (Refresh) + instruction_address <= 5'd20; + end + else begin + instruction_address <= instruction_address + 5'd1; // just increment address + end end //we are now on the middle of a delay - else delay_counter_is_zero <=0; + else begin + delay_counter_is_zero <=0; + end + + if(instruction_address == 5'd22 && user_self_refresh_q) begin // if user_self_refresh is enabled, go straight to 23 + instruction_address <= 23; // go to Precharge All for Self-refresh + delay_counter_is_zero <= 1; + instruction <= read_rom_instruction(instruction_address); + end + + //instruction[RST_DONE] is non-persistent thus we need to register it once it goes high reset_done <= instruction[RST_DONE]? 1'b1:reset_done; end end + + // register user-enabled self-refresh + always @(posedge i_controller_clk) begin + user_self_refresh_q <= i_user_self_refresh && (user_self_refresh_q || (instruction_address != 5'd25)); //will not go high again if already at instruction_address 25 (self-refresh exit) + end /*********************************************************************************************************************************************/ @@ -2567,6 +2610,9 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin DONE_CALIBRATE: begin calib_stb <= 0; state_calibrate <= DONE_CALIBRATE; + if(instruction_address == 5'd25) begin // Self-refresh Exit + pause_counter <= user_self_refresh_q; // wait until user-self-refresh is disabled before continuing 25 (Self-refresh Exit) + end end endcase diff --git a/rtl/ddr3_top.v b/rtl/ddr3_top.v index cf9a651..ba63a85 100644 --- a/rtl/ddr3_top.v +++ b/rtl/ddr3_top.v @@ -108,11 +108,14 @@ module ddr3_top #( // Done Calibration pin output wire o_calib_complete, // Debug outputs - output wire[31:0] o_debug1 + output wire[31:0] o_debug1, // output wire[31:0] o_debug2, // output wire[31:0] o_debug3, // output wire[(DQ_BITS*BYTE_LANES)/8-1:0] o_ddr3_debug_read_dqs_p, // output wire[(DQ_BITS*BYTE_LANES)/8-1:0] o_ddr3_debug_read_dqs_n + // + // User enabled self-refresh + input wire i_user_self_refresh ); // Instantiation Template (DEFAULT VALUE IS FOR ARTY S7) @@ -281,9 +284,11 @@ ddr3_top #( // Done Calibration pin .o_calib_complete(o_calib_complete), // Debug outputs - .o_debug1(o_debug1) + .o_debug1(o_debug1), // .o_debug2(o_debug2), // .o_debug3(o_debug3) + // User enabled self-refresh + .i_user_self_refresh(i_user_self_refresh) ); ddr3_phy #( diff --git a/testbench/ddr3_dimm_micron_sim.sv b/testbench/ddr3_dimm_micron_sim.sv index 5313875..2de30b2 100644 --- a/testbench/ddr3_dimm_micron_sim.sv +++ b/testbench/ddr3_dimm_micron_sim.sv @@ -107,7 +107,8 @@ module ddr3_dimm_micron_sim; wire o_wb2_stall; //1 = busy, cannot accept requests wire o_wb2_ack; //1 = read/write request has completed wire[$bits(ddr3_top.o_wb2_data)-1:0] o_wb2_data; //read data - + // User enabled self-refresh + reg i_user_self_refresh; wire clk_locked; `ifdef USE_CLOCK_WIZARD @@ -211,9 +212,9 @@ ddr3_top #( .io_ddr3_dq(dq), .io_ddr3_dqs(dqs), .io_ddr3_dqs_n(dqs_n), - .o_ddr3_dm(ddr3_dm) - - //////////////////////////////////// + .o_ddr3_dm(ddr3_dm), + // User enabled self-refresh + .i_user_self_refresh(i_user_self_refresh) ); @@ -318,6 +319,7 @@ ddr3_top #( integer average_1, average_2, average_3, average_4; localparam MAX_READS = (2**COL_BITS)*(2**BA_BITS + 1)/8; //1 row = 2**(COL_BITS) addresses/8 burst = 128 words per row. Times 8 to pass all 8 banks initial begin + i_user_self_refresh = 0; //toggle reset for 1 slow clk @(posedge i_controller_clk) begin i_rst_n <= 0;