self-refresh feature done, passing simulation and formal
This commit is contained in:
parent
1078e2ffe0
commit
e08612658b
|
|
@ -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<EFBFBD>? 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<<BA_BITS); index=index+1) begin
|
||||
|
|
@ -2610,9 +2615,12 @@ 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
|
||||
if(instruction_address == 5'd26) begin // Self-refresh Exit
|
||||
pause_counter <= user_self_refresh_q; // wait until user-self-refresh is disabled before continuing 25 (Self-refresh Exit)
|
||||
end
|
||||
else begin
|
||||
pause_counter <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
|
|
@ -2627,7 +2635,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
if(odelay_data_cntvaluein[lane] == 15) begin
|
||||
odelay_cntvalue_halfway <= 1;
|
||||
end
|
||||
if(instruction_address == 19) begin //pre-stall delay to finish all remaining requests
|
||||
if(instruction_address == 19 || instruction_address == 23) begin //pre-stall delay before precharge all to finish all remaining requests
|
||||
pause_counter <= 1; // pause instruction address until pre-stall delay before refresh sequence finishes
|
||||
//skip to instruction address 20 (precharge all before refresh) when no pending requests anymore
|
||||
//toggle it for 1 clk cycle only
|
||||
|
|
@ -3509,9 +3517,24 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
end
|
||||
//move the pipeline forward when counter is about to go zero and we are not yet at end of reset sequence
|
||||
else if((delay_counter == 1 || !instruction[USE_TIMER])) begin
|
||||
f_addr <= (f_addr == 22)? 19:f_addr + 1;
|
||||
if(f_addr == 22 && user_self_refresh_q) begin // if self refresh, move forward
|
||||
f_addr <= 23;
|
||||
end
|
||||
else if(f_addr == 22 & !user_self_refresh_q) begin // if not self refresh, move backward
|
||||
f_addr <= 19;
|
||||
end
|
||||
else if (f_addr == 26) begin // 26 (self-refresh exit) always wraps back to 20 (refresh)
|
||||
f_addr <= 20;
|
||||
end
|
||||
else begin // else, just increment
|
||||
f_addr <= f_addr + 1;
|
||||
end
|
||||
f_read <= f_addr;
|
||||
end
|
||||
else if(f_addr == 22 && user_self_refresh_q) begin // if self refresh, move forward immediately (no need to wait for delay zero)
|
||||
f_addr <= 23;
|
||||
f_read <= f_addr;
|
||||
end
|
||||
end
|
||||
|
||||
// assert f_addr and f_read as shadows of next and current instruction address
|
||||
|
|
@ -3536,11 +3559,11 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
end
|
||||
else if(f_past_valid) begin
|
||||
//if counter is zero previously and current instruction needs timer delay, then this cycle should now have the new updated counter value
|
||||
if( $past(delay_counter_is_zero) && $past(f_read_inst[USE_TIMER]) ) begin
|
||||
if( $past(delay_counter_is_zero) && $past(f_read_inst[USE_TIMER]) && !$past(user_self_refresh_q) ) begin
|
||||
assert(delay_counter == f_read_inst[DELAY_COUNTER_WIDTH - 1:0]);
|
||||
end
|
||||
//delay_counter_is_zero can be high when counter is zero and current instruction needs delay
|
||||
if($past(f_read_inst[USE_TIMER]) && !$past(pause_counter) ) begin
|
||||
if($past(f_read_inst[USE_TIMER]) && !$past(pause_counter) && !$past(user_self_refresh_q)) begin
|
||||
assert( delay_counter_is_zero == (delay_counter == 0) );
|
||||
end
|
||||
//delay_counter_is_zero will go high this cycle when we received a don't-use-timer instruction
|
||||
|
|
@ -3557,12 +3580,12 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
|
||||
//if delay is not yet zero and timer delay is enabled, then delay_counter should decrement
|
||||
if(!$past(delay_counter_is_zero) && $past(f_read_inst[USE_TIMER]) && !$past(pause_counter) ) begin
|
||||
assert(delay_counter == $past(delay_counter) - 1);
|
||||
assert((delay_counter == $past(delay_counter) - 1) || (delay_counter == 0 && $past(user_self_refresh_q)));
|
||||
assert(delay_counter < $past(delay_counter) ); //just to make sure delay_counter will never overflow back to all 1's
|
||||
end
|
||||
|
||||
//sanity checking for the comment "delay_counter will be zero AT NEXT CLOCK CYCLE when counter is now one"
|
||||
if($past(delay_counter) == 1) begin
|
||||
if($past(delay_counter) == 1 && !$past(pause_counter)) begin
|
||||
assert(delay_counter == 0 && delay_counter_is_zero);
|
||||
end
|
||||
//assert the relationship between the stages FOR RESET SEQUENCE
|
||||
|
|
@ -3583,15 +3606,18 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
//assert the relationship between the stages FOR REFRESH SEQUENCE
|
||||
else begin
|
||||
if(f_read == 22) begin
|
||||
assert(f_addr == 19); //if current instruction is 22, then next instruction must be at 19 (instruction address wraps from 15 to 12)
|
||||
assert( (f_addr == 19) || (f_addr == 23 ) ); //if current instruction is 22, then next instruction must be at 19 or 23 (instruction address wraps from 22 to 19 if not self refresh, else 22 to 23)
|
||||
end
|
||||
else if(f_addr == 19) begin
|
||||
assert(f_read == 22); //if next instruction is at 12, then current instruction must be at 15 (instruction address wraps from 15 to 12)
|
||||
else if(f_addr == 19 || f_addr == 23) begin
|
||||
assert(f_read == 22); //if next instruction is at 19 or 23, then current instruction must be at 22 (instruction address wraps from 22 to 19)
|
||||
end
|
||||
else if(f_read == 26) begin
|
||||
assert(f_addr == 20); // if current instruction is 26 (exit self-refresh) then go to 20 (refresh)
|
||||
end
|
||||
else begin
|
||||
assert(f_read + 1 == f_addr); //if there is no need to wrap around, then instruction address must increment
|
||||
end
|
||||
assert((f_read >= 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<<bank); //bank will be turned active
|
||||
f_bank_active_row[bank] <= cmd_d[ACTIVATE_SLOT][CMD_ADDRESS_START:0]; //save row to be activated
|
||||
end
|
||||
|
||||
if(instruction_address == 20 || instruction_address == 24) begin ///current instruction at precharge
|
||||
//all banks will be in idle after refresh
|
||||
for( index=0; index < (1<<BA_BITS); index=index+1) begin
|
||||
f_bank_status_2[index] <= 0;
|
||||
end
|
||||
end
|
||||
f_bank_status <= f_bank_status_2;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
assign f_write_slot = WRITE_SLOT;
|
||||
|
|
@ -4189,7 +4239,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
end
|
||||
|
||||
always @* begin
|
||||
if(instruction_address != 22 && instruction_address != 19) begin
|
||||
if(instruction_address != 22 && instruction_address != 19 && instruction_address != 23) begin
|
||||
assert(!stage1_pending && !stage2_pending); //must be pending except in tREFI and in prestall delay
|
||||
end
|
||||
|
||||
|
|
@ -4390,7 +4440,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
end
|
||||
always @(posedge i_controller_clk) begin
|
||||
if(f_past_valid) begin
|
||||
if(instruction_address != 22 && instruction_address != 19 && $past(i_wb_cyc) && !past_sync_rst_controller) begin
|
||||
if(instruction_address != 22 && instruction_address != 19 && instruction_address != 23 && $past(i_wb_cyc) && !past_sync_rst_controller) begin
|
||||
assert(f_nreqs == $past(f_nreqs));
|
||||
end
|
||||
if(state_calibrate == DONE_CALIBRATE && $past(state_calibrate) != DONE_CALIBRATE && !past_sync_rst_controller) begin//just started DONE_CALBRATION
|
||||
|
|
@ -4564,12 +4614,12 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
// extra assertions to make sure engine starts properly
|
||||
always @* begin
|
||||
//if(!past_sync_rst_controller) begin
|
||||
assert(instruction_address <= 22);
|
||||
assert(instruction_address <= 26);
|
||||
assert(state_calibrate <= DONE_CALIBRATE);
|
||||
|
||||
if(!o_wb_stall) begin
|
||||
assert(state_calibrate == DONE_CALIBRATE);
|
||||
assert(instruction_address == 22 || (instruction_address == 19 && delay_counter == 0));
|
||||
assert(instruction_address == 22 || (instruction_address == 19 && delay_counter == 0) || (instruction_address == 23));
|
||||
end
|
||||
|
||||
if(instruction_address == 19 && delay_counter != 0 && state_calibrate == DONE_CALIBRATE) begin
|
||||
|
|
@ -4580,7 +4630,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
|
|||
|
||||
if(stage1_pending || stage2_pending) begin
|
||||
assert(state_calibrate > 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@
|
|||
</db_ref>
|
||||
</db_ref_list>
|
||||
<zoom_setting>
|
||||
<ZoomStartTime time="749.583 ns"></ZoomStartTime>
|
||||
<ZoomEndTime time="6,229.584 ns"></ZoomEndTime>
|
||||
<Cursor1Time time="1,130.000 ns"></Cursor1Time>
|
||||
<ZoomStartTime time="0.000000 us"></ZoomStartTime>
|
||||
<ZoomEndTime time="55.000001 us"></ZoomEndTime>
|
||||
<Cursor1Time time="33.460000 us"></Cursor1Time>
|
||||
</zoom_setting>
|
||||
<column_width_setting>
|
||||
<NameColumnWidth column_width="272"></NameColumnWidth>
|
||||
<ValueColumnWidth column_width="129"></ValueColumnWidth>
|
||||
<ValueColumnWidth column_width="125"></ValueColumnWidth>
|
||||
</column_width_setting>
|
||||
<WVObjectSize size="47" />
|
||||
<WVObjectSize size="52" />
|
||||
<wvobject fp_name="divider869" type="divider">
|
||||
<obj_property name="label">Clocks and Reset</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
|
|
@ -45,16 +45,37 @@
|
|||
<obj_property name="ObjectShortName">i_ref_clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject fp_name="divider869" type="divider">
|
||||
<obj_property name="label">Calibration</obj_property>
|
||||
<obj_property name="label">Self-refresh</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/\sideband_ECC_per_8_bursts.ecc_dec_inst /sb_err">
|
||||
<obj_property name="ElementShortName">sb_err</obj_property>
|
||||
<obj_property name="ObjectShortName">sb_err</obj_property>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/i_user_self_refresh">
|
||||
<obj_property name="ElementShortName">i_user_self_refresh</obj_property>
|
||||
<obj_property name="ObjectShortName">i_user_self_refresh</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/\sideband_ECC_per_8_bursts.ecc_dec_inst /db_err">
|
||||
<obj_property name="ElementShortName">db_err</obj_property>
|
||||
<obj_property name="ObjectShortName">db_err</obj_property>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/user_self_refresh_q">
|
||||
<obj_property name="ElementShortName">user_self_refresh_q</obj_property>
|
||||
<obj_property name="ObjectShortName">user_self_refresh_q</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/o_ddr3_cke">
|
||||
<obj_property name="ElementShortName">o_ddr3_cke</obj_property>
|
||||
<obj_property name="ObjectShortName">o_ddr3_cke</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/ddr3_dimm_micron_sim/ddr3_top/refresh_counter">
|
||||
<obj_property name="ElementShortName">refresh_counter[8:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">refresh_counter[8:0]</obj_property>
|
||||
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/o_wb_stall">
|
||||
<obj_property name="ElementShortName">o_wb_stall</obj_property>
|
||||
<obj_property name="ObjectShortName">o_wb_stall</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/i_wb_stb">
|
||||
<obj_property name="ElementShortName">i_wb_stb</obj_property>
|
||||
<obj_property name="ObjectShortName">i_wb_stb</obj_property>
|
||||
</wvobject>
|
||||
<wvobject fp_name="divider869" type="divider">
|
||||
<obj_property name="label">Calibration</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/initial_calibration_done">
|
||||
<obj_property name="ElementShortName">initial_calibration_done</obj_property>
|
||||
|
|
|
|||
Loading…
Reference in New Issue