diff --git a/rtl/ddr3_controller.v b/rtl/ddr3_controller.v index ed8f00b..3bdb9d9 100644 --- a/rtl/ddr3_controller.v +++ b/rtl/ddr3_controller.v @@ -255,7 +255,8 @@ module ddr3_controller #( 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 + localparam tCKESR = nCK_to_cycles(tCKE + 1)+ 5; // cycles (controller) Minimum time that the DDR3 SDRAM must remain in Self-Refresh mode is tCKESR + localparam tCPDED = 1; // cycle (tCPDED is at most 2nCK but we make it to 1cycle or 4nCK) Command pass disable delay , required cycles of NOP after CKE low /*********************************************************************************************************************************************/ @@ -668,7 +669,7 @@ module ddr3_controller #( else read_rom_instruction = {5'b01000 , CMD_NOP , ps_to_cycles(POWER_ON_RESET_HIGH)}; //0. RESET# needs to be maintained low for minimum 200us with power-up initialization. CKE is pulled - //“Low” anytime before RESET# being de-asserted (min. time 10 ns). . + //“Low�? anytime before RESET# being de-asserted (min. time 10 ns). . 5'd1: if (MICRON_SIM) @@ -752,13 +753,16 @@ module ddr3_controller #( 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 + + 5'd24: read_rom_instruction = {5'b01001, CMD_NOP, tCPDED[DELAY_SLOT_WIDTH-1:0]}; + // 24. CKE must go low to enter self-refresh, tCPDED cycles of NOP are required before CMD_SREF_EN + + 5'd25: read_rom_instruction = {5'b01001, CMD_SREF_EN, tCKESR[DELAY_SLOT_WIDTH-1:0]}; + // 25. 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) + 5'd26: read_rom_instruction = {5'b01011, CMD_SREF_XT, tXSDLL_tRFC[DELAY_SLOT_WIDTH-1:0]}; + // 26. From 25 (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. @@ -798,7 +802,7 @@ module ddr3_controller #( //delay_counter is 1 (for r/w calibration and prestall delay) //address will only move forward for these kinds of delay only //when skip_reset_seq_delay is toggled - else if(instruction[USE_TIMER] /*&& delay_counter != {(DELAY_COUNTER_WIDTH){1'b1}}*/ && !pause_counter) delay_counter <= delay_counter - 1; + else if(instruction[USE_TIMER] /*&& delay_counter != {(DELAY_COUNTER_WIDTH){1'b1}}*/ && !pause_counter && delay_counter != 0) delay_counter <= delay_counter - 1; //delay_counter of 1 means we will need to update the delay_counter next clock cycle (delay_counter of zero) so we need to retrieve //now the next instruction. The same thing needs to be done when current instruction does not need the timer delay. @@ -808,7 +812,7 @@ module ddr3_controller #( 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) + else if(instruction_address == 5'd26) begin // self-refresh exit always wraps back to 20 (Refresh) instruction_address <= 5'd20; end else begin @@ -823,6 +827,7 @@ module ddr3_controller #( 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; + delay_counter <= 0; instruction <= read_rom_instruction(instruction_address); end @@ -834,7 +839,7 @@ module ddr3_controller #( // 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) + user_self_refresh_q <= i_user_self_refresh && (user_self_refresh_q || (instruction_address != 5'd26)) && final_calibration_done; //will not go high again if already at instruction_address 26 (self-refresh exit), only go high when calibration is done end /*********************************************************************************************************************************************/ @@ -922,7 +927,7 @@ module ddr3_controller #( bank_active_row_q[index] <= bank_active_row_d[index]; end - if(instruction_address == 20) begin ///current instruction at precharge + if(instruction_address == 20 || instruction_address == 24) begin ///current instruction at precharge cmd_odt_q <= 1'b0; //all banks will be in idle after refresh for( index=0; index < (1<= 19 && f_read <= 22) ); //refresh sequence is only on instruction address 19,20,21,22 + assert((f_read >= 19 && f_read <= 26) ); //refresh sequence is only on instruction address 19,20,21,22 end // reset_done must retain high when it was already asserted once @@ -3608,7 +3634,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin if(reset_done && f_read_inst[REF_IDLE]) begin assert(f_read == 21); end - + end end @@ -3621,9 +3647,18 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin assert( a[DELAY_COUNTER_WIDTH - 1:0] > 0); end end - + // assertion on FSM calibration always @* begin + if(instruction_address == 19 || instruction_address == 23) begin //pre-stall delay before precharge all to finish all remaining requests + if(pause_counter == 1) begin // if there are still pending requests (pause_counter high) then delay_counter should still be at PRE_REFRESH_DELAY + assert(delay_counter == PRE_REFRESH_DELAY); + end + end + if(instruction_address >= 24 && instruction_address < 26) begin + assert(!pause_counter); // no pause counter from precharge to sel-refresh entry + end + if(instruction_address < 13) begin assert(state_calibrate == IDLE); end @@ -3641,6 +3676,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin if(pause_counter) begin assert(delay_counter != 0); + // will fix this soon end if(state_calibrate > ISSUE_WRITE_1 && state_calibrate <= ANALYZE_DATA) begin @@ -3936,10 +3972,10 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin end if(reset_done) begin - assert(cmd_d[PRECHARGE_SLOT][CMD_CKE] && cmd_d[PRECHARGE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done - assert(cmd_d[ACTIVATE_SLOT][CMD_CKE] && cmd_d[ACTIVATE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done - assert(cmd_d[READ_SLOT][CMD_CKE] && cmd_d[READ_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done - assert(cmd_d[WRITE_SLOT][CMD_CKE] && cmd_d[WRITE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done + assert(cmd_d[PRECHARGE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done + assert(cmd_d[ACTIVATE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done + assert(cmd_d[READ_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done + assert(cmd_d[WRITE_SLOT][CMD_RESET_N]); //cke and rst_n should stay high when reset sequence is already done end end if(state_calibrate == DONE_CALIBRATE) begin @@ -3954,7 +3990,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin if(!f_empty) begin assert(state_calibrate == DONE_CALIBRATE); end - if(train_delay == 0 && state_calibrate == FINISH_READ) begin//remove + if(train_delay == 0 && state_calibrate == FINISH_READ) begin//fix this soon assume(f_sum_of_pending_acks == 0); end end @@ -4099,6 +4135,12 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin end always @* begin assert(f_bank_status == bank_status_q); + if(instruction_address >= 25) begin // after precharge until end of refresh, all banks are idle + assert(bank_status_q == 0); + end + if(instruction_address == 23 && pause_counter) begin // if at PRE_REFRESH_DELAY and not yet done, then delay_counter should still be at original value + + end end (*keep*) reg[31:0] bank; @@ -4136,9 +4178,17 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin f_bank_status_2 = f_bank_status_2 | (1< ISSUE_WRITE_1); - assert(instruction_address == 22 || instruction_address == 19); + assert(instruction_address == 22 || instruction_address == 19 || instruction_address == 23); end if(instruction_address < 13) begin @@ -4622,7 +4672,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin assert(o_wb_stall_calib); end if(reset_done) begin - assert(instruction_address >= 19 && instruction_address <= 22); + assert(instruction_address >= 19 && instruction_address <= 26); end //delay_counter is zero at first clock of new instruction address, the actual delay_clock wil start at next clock cycle if(instruction_address == 19 && delay_counter != 0) begin diff --git a/rtl/ddr3_top.v b/rtl/ddr3_top.v index ba63a85..350778d 100644 --- a/rtl/ddr3_top.v +++ b/rtl/ddr3_top.v @@ -48,6 +48,7 @@ module ddr3_top #( parameter[1:0] ECC_ENABLE = 0, // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC ) parameter[1:0] DIC = 2'b00, //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms) (only change when you know what you are doing) parameter[2:0] RTT_NOM = 3'b011, //RTT Nominal (3'b000 = disabled, 3'b001 = RZQ/4, 3'b010 = RZQ/2 , 3'b011 = RZQ/6, RZQ = 240ohms) (only change when you know what you are doing) + parameter[1:0] SELF_REFRESH = 2'b00, // 0 = use i_user_self_refresh input, 1 = Self-refresh mode is enabled after 64 controller clock cycles of no requests, 2 = 128 cycles, 3 = 256 cycles parameter // The next parameters act more like a localparam (since user does not have to set this manually) but was added here to simplify port declaration DQ_BITS = 8, //device width (fixed to 8, if DDR3 is x16 then BYTE_LANES will be 2 while ) serdes_ratio = 4, // this controller is fixed as a 4:1 memory controller (CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD = 4) @@ -210,6 +211,30 @@ ddr3_top #( wire write_leveling_calib; wire reset; + // logic for self-refresh + reg[8:0] refresh_counter = 0; + reg user_self_refresh; + // refresh counter + always @(posedge i_controller_clk) begin + if(i_wb_stb && i_wb_cyc) begin // if there is Wishbone request, then reset counter + refresh_counter <= 0; + end + else if(!o_wb_stall || user_self_refresh) begin // if no request (but not stalled) OR already on self-refresh, then increment counter + refresh_counter <= refresh_counter + 1; + end + end + // choose self-refresh options + always @* begin + case(SELF_REFRESH) + 2'b00: user_self_refresh = i_user_self_refresh; // use input i_user_self_refresh (high = enter self-refresh, low = exit self-refresh) + 2'b01: user_self_refresh = refresh_counter[6]; // Self-refresh mode is enabled after 64 controller clock cycles of no requests, then exit Self-refresh after another 64 controller clk cycles + 2'b10: user_self_refresh = refresh_counter[7]; // Self-refresh mode is enabled after 128 controller clock cycles of no requests, then exit Self-refresh after another 128 controller clk cycles + 2'b11: user_self_refresh = refresh_counter[8]; // Self-refresh mode is enabled after 256 controller clock cycles of no requests, then exit Self-refresh after another 256 controller clk cycles + endcase + end + + + //module instantiations ddr3_controller #( .CONTROLLER_CLK_PERIOD(CONTROLLER_CLK_PERIOD), //ps, clock period of the controller interface @@ -288,7 +313,7 @@ ddr3_top #( // .o_debug2(o_debug2), // .o_debug3(o_debug3) // User enabled self-refresh - .i_user_self_refresh(i_user_self_refresh) + .i_user_self_refresh(user_self_refresh) ); ddr3_phy #( @@ -348,4 +373,3 @@ ddr3_top #( ); endmodule - diff --git a/testbench/ddr3_dimm_micron_sim.sv b/testbench/ddr3_dimm_micron_sim.sv index 2de30b2..3640673 100644 --- a/testbench/ddr3_dimm_micron_sim.sv +++ b/testbench/ddr3_dimm_micron_sim.sv @@ -64,7 +64,8 @@ module ddr3_dimm_micron_sim; localparam CONTROLLER_CLK_PERIOD = 10_000, //ps, period of clock input to this DDR3 controller module DDR3_CLK_PERIOD = 2500, //ps, period of clock input to DDR3 RAM device AUX_WIDTH = 16, // AUX lines - ECC_ENABLE = 0; // ECC enable + ECC_ENABLE = 0, // ECC enable + SELF_REFRESH = 2'b11; reg i_controller_clk, i_ddr3_clk, i_ref_clk, i_ddr3_clk_90; reg i_rst_n; @@ -164,7 +165,9 @@ ddr3_top #( .ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 if ODELAYE2 is supported .SECOND_WISHBONE(0), //set to 1 if 2nd wishbone for debugging is needed .ECC_ENABLE(ECC_ENABLE), // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC ) - .WB_ERROR(1) // set to 1 to support Wishbone error (asserts at ECC double bit error) + .WB_ERROR(1), // set to 1 to support Wishbone error (asserts at ECC double bit error) + .SKIP_INTERNAL_TEST(0), // skip built-in self test (would require >2 seconds of internal test right after calibration) + .SELF_REFRESH(SELF_REFRESH) // 0 = use i_user_self_refresh input, 1 = Self-refresh mode is enabled after 64 controller clock cycles of no requests, 2 = 128 cycles, 3 = 256 cycles ) ddr3_top ( //clock and reset @@ -344,7 +347,11 @@ ddr3_top #( i_rst_n <= 1; end wait(ddr3_top.ddr3_controller_inst.state_calibrate == ddr3_top.ddr3_controller_inst.DONE_CALIBRATE); - + + // test self refresh after calibration + // test self refresh + self_refresh(); + // test 1 phase 1: Write random word sequentially // write to row 1 number_of_op <= 0; @@ -382,8 +389,8 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here - + // test self refresh + self_refresh(); //Read sequentially address <= start_address; @@ -409,7 +416,8 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here + // test self refresh + self_refresh(); average_1 = ($time-time_started)/(number_of_op*1000); $display("\n--------------------------------\nDONE TEST 1: FIRST ROW\nNumber of Operations: %0d\nTime Started: %0d ns\nTime Done: %0d ns\nAverage Rate: %0d ns/request\n--------------------------------\n\n", @@ -456,7 +464,8 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here + // test self refresh + self_refresh(); // Read sequentially address <= start_address; @@ -482,7 +491,8 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here + // test self refresh + self_refresh(); average_2 = ($time-time_started)/(number_of_op*1000); $display("\n--------------------------------\nDONE TEST 1: MIDDLE ROW\nNumber of Operations: %0d\nTime Started: %0d ns\nTime Done: %0d ns\nAverage Rate: %0d ns/request\n--------------------------------\n\n", @@ -526,7 +536,8 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here + // test self refresh + self_refresh(); // Read sequentially address <= start_address; @@ -558,15 +569,14 @@ ddr3_top #( // i_wb_stb <= 0; // end // end - #1000_000; //rest here + // test self refresh + self_refresh(); average_3 = ($time-time_started)/(number_of_op*1000); $display("\n--------------------------------\nDONE TEST 1: LAST ROW\nNumber of Operations: %0d\nTime Started: %0d ns\nTime Done: %0d ns\nAverage Rate: %0d ns/request\n--------------------------------\n\n", number_of_op,time_started/1000, $time/1000, ($time-time_started)/(number_of_op*1000)); //#100_000; - - // Test 2:Random Access // write randomly address <= random_start; //this will just be used as the seed to generate a random number @@ -602,7 +612,9 @@ ddr3_top #( if (!o_wb_stall) i_wb_stb <= 1'b0; end end - #1000_000; //rest here + + // test self refresh + self_refresh(); // Read sequentially // Read the random words written at the random addresses @@ -639,8 +651,10 @@ ddr3_top #( average_4 = ($time-time_started)/(number_of_op*1000); $display("\n--------------------------------\nDONE TEST 2: RANDOM\nNumber of Operations: %0d\nTime Started: %0d ns\nTime Done: %0d ns\nAverage Rate: %0d ns/request\n--------------------------------\n\n", number_of_op,time_started/1000, $time/1000, ($time-time_started)/(number_of_op*1000)); - - #100_000; + + // test self refresh + self_refresh(); + // Test 3: Read from wishbone 2 (PHY) // Wishbone 2 i_wb2_cyc <= 0; //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled) @@ -699,7 +713,11 @@ ddr3_top #( end end - #1000_000; + #1000_000; //rest here + // test self refresh + self_refresh(); + #1000_000; // rest + $display("\n\n------- SUMMARY -------\nNumber of Writes = %0d\nNumber of Reads = %0d\nNumber of Success = %0d\nNumber of Fails = %0d\nNumber of Injected Errors = %0d\n", number_of_writes, number_of_reads,number_of_successful, number_of_failed, number_of_injected_errors); $display("\n\nTEST CALIBRATION\n[-]: write_test_address_counter = %0d", ddr3_top.ddr3_controller_inst.write_test_address_counter); @@ -709,6 +727,20 @@ ddr3_top #( $stop; end + task self_refresh; + if(SELF_REFRESH == 2'b00) begin + // test self refresh + @(posedge i_controller_clk) + i_user_self_refresh = 1; + #40_000_000; //40_000 ns of self-refresh + @(posedge i_controller_clk) + i_user_self_refresh = 0; + end + else begin + #10_000_000; // 10_000 ns of rest + end + endtask + //check read data initial begin start_read_address = 0; //start at first row @@ -988,4 +1020,3 @@ ddr3_top #( */ endmodule - diff --git a/testbench/ddr3_dimm_micron_sim_behav.wcfg b/testbench/ddr3_dimm_micron_sim_behav.wcfg index 0091286..b29ede8 100644 --- a/testbench/ddr3_dimm_micron_sim_behav.wcfg +++ b/testbench/ddr3_dimm_micron_sim_behav.wcfg @@ -11,15 +11,15 @@ - - - + + + - + - + Clocks and Reset label @@ -45,16 +45,37 @@ i_ref_clk - Calibration + Self-refresh label - - sb_err - sb_err + + i_user_self_refresh + i_user_self_refresh - - db_err - db_err + + user_self_refresh_q + user_self_refresh_q + + + o_ddr3_cke + o_ddr3_cke + + + refresh_counter[8:0] + refresh_counter[8:0] + UNSIGNEDDECRADIX + + + o_wb_stall + o_wb_stall + + + i_wb_stb + i_wb_stb + + + Calibration + label initial_calibration_done