Merge pull request #17 from AngeloJacobo/self_refresh_feature

Add self refresh feature (passing simulation, formal, and hardware test)
This commit is contained in:
Angelo Jacobo 2024-11-25 17:48:54 +08:00 committed by GitHub
commit 29ce61bcac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 401 additions and 112 deletions

View File

@ -49,6 +49,7 @@ module ddr3_top_axi #(
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)
@ -130,11 +131,14 @@ module ddr3_top_axi #(
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
);
wire wb_cyc;
@ -165,7 +169,8 @@ ddr3_top #(
.SKIP_INTERNAL_TEST(SKIP_INTERNAL_TEST), // skip built-in self test (would require >2 seconds of internal test right after calibration)
.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 )
.DIC(DIC), // Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms) (only change when you know what you are doing)
.RTT_NOM(RTT_NOM) //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)
.RTT_NOM(RTT_NOM), //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)
.SELF_REFRESH(SELF_REFRESH) // Self-refresh options (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_inst
(
//clock and reset
@ -222,11 +227,13 @@ ddr3_top #(
.o_calib_complete(o_calib_complete),
//
// Debug outputs
.o_debug1(o_debug1)
.o_debug1(o_debug1),
// .o_debug2(o_debug2),
// .o_debug3(o_debug3),
// .o_ddr3_debug_read_dqs_p(o_ddr3_debug_read_dqs_p),
// .o_ddr3_debug_read_dqs_n(o_ddr3_debug_read_dqs_n)
//
.i_user_self_refresh(i_user_self_refresh)
////////////////////////////////////
);

View File

@ -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,11 @@ 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)+ 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
/*********************************************************************************************************************************************/
@ -481,7 +489,8 @@ module ddr3_controller #(
initial begin
o_phy_bitslip = 0;
end
reg cmd_odt_q = 0, cmd_odt, cmd_ck_en, cmd_reset_n;
reg cmd_odt_q = 0, cmd_odt, cmd_reset_n;
(* mark_debug = "true" *) reg cmd_ck_en;
reg o_wb_stall_q = 1, o_wb_stall_d, o_wb_stall_calib = 1;
reg precharge_slot_busy;
reg activate_slot_busy;
@ -586,7 +595,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;
@ -660,7 +670,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)
@ -727,7 +737,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 +750,22 @@ 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'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'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.
default: read_rom_instruction = {5'b00011, CMD_NOP, {(DELAY_SLOT_WIDTH){1'b0}}};
endcase
@ -778,21 +803,45 @@ 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.
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'd26) 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;
delay_counter <= 0;
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'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
/*********************************************************************************************************************************************/
@ -879,7 +928,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
@ -2567,6 +2616,12 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
DONE_CALIBRATE: begin
calib_stb <= 0;
state_calibrate <= DONE_CALIBRATE;
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
@ -2581,7 +2636,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
@ -3463,9 +3518,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
@ -3490,11 +3560,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
@ -3511,12 +3581,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
@ -3537,15 +3607,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
@ -3562,7 +3635,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
@ -3575,9 +3648,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
@ -3595,6 +3677,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
@ -3890,10 +3973,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
@ -3908,7 +3991,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
@ -4053,6 +4136,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;
@ -4090,9 +4179,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;
@ -4143,7 +4240,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
@ -4344,7 +4441,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
@ -4518,12 +4615,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
@ -4534,7 +4631,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
@ -4576,7 +4673,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

View File

@ -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)
@ -108,11 +109,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)
@ -207,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
@ -281,9 +309,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(user_self_refresh)
);
ddr3_phy #(
@ -341,6 +371,29 @@ ddr3_top #(
.o_ddr3_debug_read_dqs_p(/*o_ddr3_debug_read_dqs_p*/),
.o_ddr3_debug_read_dqs_n(/*o_ddr3_debug_read_dqs_n*/)
);
endmodule
// display value of parameters for easy debugging
initial begin
$display("\nDDR3 TOP PARAMETERS:\n-----------------------------");
$display("CONTROLLER_CLK_PERIOD = %0d", CONTROLLER_CLK_PERIOD);
$display("DDR3_CLK_PERIOD = %0d", DDR3_CLK_PERIOD);
$display("ROW_BITS = %0d", ROW_BITS);
$display("COL_BITS = %0d", COL_BITS);
$display("BA_BITS = %0d", BA_BITS);
$display("BYTE_LANES = %0d", BYTE_LANES);
$display("AUX_WIDTH = %0d", AUX_WIDTH);
$display("WB2_ADDR_BITS = %0d", WB2_ADDR_BITS);
$display("WB2_DATA_BITS = %0d", WB2_DATA_BITS);
$display("MICRON_SIM = %0d", MICRON_SIM);
$display("ODELAY_SUPPORTED = %0d", ODELAY_SUPPORTED);
$display("SECOND_WISHBONE = %0d", SECOND_WISHBONE);
$display("WB_ERROR = %0d", WB_ERROR);
$display("SKIP_INTERNAL_TEST = %0d", SKIP_INTERNAL_TEST);
$display("ECC_ENABLE = %0d", ECC_ENABLE);
$display("DIC = %0d", DIC);
$display("RTT_NOM = %0d", RTT_NOM);
$display("SELF_REFRESH = %0d", SELF_REFRESH);
$display("End of DDR3 TOP PARAMETERS\n-----------------------------");
end
endmodule

View File

@ -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;
@ -107,7 +108,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
@ -163,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
@ -211,9 +215,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 +322,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;
@ -342,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;
@ -380,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;
@ -407,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",
@ -454,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;
@ -480,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",
@ -524,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;
@ -556,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
@ -600,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
@ -637,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)
@ -697,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);
@ -707,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
@ -986,4 +1020,3 @@ ddr3_top #(
*/
endmodule

View File

@ -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>

View File

@ -311,28 +311,6 @@
</spirit:portMap>
</spirit:portMaps>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>i_rst_n</spirit:name>
<spirit:busType spirit:vendor="xilinx.com" spirit:library="signal" spirit:name="reset" spirit:version="1.0"/>
<spirit:abstractionType spirit:vendor="xilinx.com" spirit:library="signal" spirit:name="reset_rtl" spirit:version="1.0"/>
<spirit:slave/>
<spirit:portMaps>
<spirit:portMap>
<spirit:logicalPort>
<spirit:name>RST</spirit:name>
</spirit:logicalPort>
<spirit:physicalPort>
<spirit:name>i_rst_n</spirit:name>
</spirit:physicalPort>
</spirit:portMap>
</spirit:portMaps>
<spirit:parameters>
<spirit:parameter>
<spirit:name>POLARITY</spirit:name>
<spirit:value spirit:id="BUSIFPARAM_VALUE.I_RST_N.POLARITY" spirit:choiceRef="choice_list_9d8b0d81">ACTIVE_LOW</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>i_controller_clk</spirit:name>
<spirit:busType spirit:vendor="xilinx.com" spirit:library="signal" spirit:name="clock" spirit:version="1.0"/>
@ -387,6 +365,28 @@
</spirit:portMap>
</spirit:portMaps>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>i_rst_n</spirit:name>
<spirit:busType spirit:vendor="xilinx.com" spirit:library="signal" spirit:name="reset" spirit:version="1.0"/>
<spirit:abstractionType spirit:vendor="xilinx.com" spirit:library="signal" spirit:name="reset_rtl" spirit:version="1.0"/>
<spirit:slave/>
<spirit:portMaps>
<spirit:portMap>
<spirit:logicalPort>
<spirit:name>RST</spirit:name>
</spirit:logicalPort>
<spirit:physicalPort>
<spirit:name>i_rst_n</spirit:name>
</spirit:physicalPort>
</spirit:portMap>
</spirit:portMaps>
<spirit:parameters>
<spirit:parameter>
<spirit:name>POLARITY</spirit:name>
<spirit:value spirit:id="BUSIFPARAM_VALUE.I_RST_N.POLARITY" spirit:choiceRef="choice_list_9d8b0d81">ACTIVE_LOW</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>ddr3</spirit:name>
<spirit:displayName>ddr3</spirit:displayName>
@ -561,7 +561,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>e9f63973</spirit:value>
<spirit:value>1dea7b87</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
@ -577,7 +577,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>e9f63973</spirit:value>
<spirit:value>1dea7b87</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
@ -591,7 +591,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>30e22270</spirit:value>
<spirit:value>ce7b9cf6</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
@ -1578,6 +1578,29 @@
</spirit:wireTypeDefs>
</spirit:wire>
</spirit:port>
<spirit:port>
<spirit:name>i_user_self_refresh</spirit:name>
<spirit:wire>
<spirit:direction>in</spirit:direction>
<spirit:wireTypeDefs>
<spirit:wireTypeDef>
<spirit:typeName>wire</spirit:typeName>
<spirit:viewNameRef>xilinx_anylanguagesynthesis</spirit:viewNameRef>
<spirit:viewNameRef>xilinx_anylanguagebehavioralsimulation</spirit:viewNameRef>
</spirit:wireTypeDef>
</spirit:wireTypeDefs>
<spirit:driver>
<spirit:defaultValue spirit:format="long">0</spirit:defaultValue>
</spirit:driver>
</spirit:wire>
<spirit:vendorExtensions>
<xilinx:portInfo>
<xilinx:enablement>
<xilinx:isEnabled xilinx:resolve="dependent" xilinx:id="PORT_ENABLEMENT.i_user_self_refresh" xilinx:dependency="$SELF_REFRESH = 0">true</xilinx:isEnabled>
</xilinx:enablement>
</xilinx:portInfo>
</spirit:vendorExtensions>
</spirit:port>
</spirit:ports>
<spirit:modelParameters>
<spirit:modelParameter xsi:type="spirit:nameValueTypeType" spirit:dataType="integer">
@ -1655,6 +1678,11 @@
<spirit:displayName>Ecc Enable</spirit:displayName>
<spirit:value spirit:format="long" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.ECC_ENABLE">0</spirit:value>
</spirit:modelParameter>
<spirit:modelParameter spirit:dataType="integer">
<spirit:name>SELF_REFRESH</spirit:name>
<spirit:displayName>Self-Refresh</spirit:displayName>
<spirit:value spirit:format="long" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.SELF_REFRESH">0</spirit:value>
</spirit:modelParameter>
<spirit:modelParameter spirit:dataType="integer">
<spirit:name>DIC</spirit:name>
<spirit:displayName>Dic</spirit:displayName>
@ -1723,6 +1751,20 @@
<spirit:enumeration>ACTIVE_HIGH</spirit:enumeration>
<spirit:enumeration>ACTIVE_LOW</spirit:enumeration>
</spirit:choice>
<spirit:choice>
<spirit:name>choice_pairs_933dc0fc</spirit:name>
<spirit:enumeration spirit:text="0 (ECC DIsabled)">0</spirit:enumeration>
<spirit:enumeration spirit:text="1 (Side-band ECC per burst)">1</spirit:enumeration>
<spirit:enumeration spirit:text="2 (Side-band ECC per 8 bursts)">2</spirit:enumeration>
<spirit:enumeration spirit:text="3 (Inline ECC)">3</spirit:enumeration>
</spirit:choice>
<spirit:choice>
<spirit:name>choice_pairs_96a879b9</spirit:name>
<spirit:enumeration spirit:text="0 (Enable self-refresh based on i_user_self_refresh)">0</spirit:enumeration>
<spirit:enumeration spirit:text="1 (Enable self-refresh after 64 clock cycles of inactivity)">1</spirit:enumeration>
<spirit:enumeration spirit:text="2 (Enable self-refresh after 128 clock cycles of inactivity)">2</spirit:enumeration>
<spirit:enumeration spirit:text="3 (Enable self-refresh after 256 clock cycles of inactivity)">3</spirit:enumeration>
</spirit:choice>
</spirit:choices>
<spirit:fileSets>
<spirit:fileSet>
@ -1778,7 +1820,7 @@
<spirit:file>
<spirit:name>../rtl/axi/ddr3_top_axi.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
<spirit:userFileType>CHECKSUM_4123fcc3</spirit:userFileType>
<spirit:userFileType>CHECKSUM_f4e2d855</spirit:userFileType>
</spirit:file>
</spirit:fileSet>
<spirit:fileSet>
@ -1841,7 +1883,7 @@
<spirit:file>
<spirit:name>xgui/uberddr3_axi_v1_0.tcl</spirit:name>
<spirit:fileType>tclSource</spirit:fileType>
<spirit:userFileType>CHECKSUM_30e22270</spirit:userFileType>
<spirit:userFileType>CHECKSUM_ce7b9cf6</spirit:userFileType>
<spirit:userFileType>XGUI_VERSION_2</spirit:userFileType>
</spirit:file>
</spirit:fileSet>
@ -1935,7 +1977,7 @@
<spirit:parameter>
<spirit:name>ECC_ENABLE</spirit:name>
<spirit:displayName>ECC Enable</spirit:displayName>
<spirit:value spirit:format="long" spirit:resolve="user" spirit:id="PARAM_VALUE.ECC_ENABLE" spirit:minimum="0" spirit:maximum="3" spirit:rangeType="long">0</spirit:value>
<spirit:value spirit:format="long" spirit:resolve="user" spirit:id="PARAM_VALUE.ECC_ENABLE" spirit:choiceRef="choice_pairs_933dc0fc">0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>DIC</spirit:name>
@ -2057,6 +2099,11 @@
<spirit:name>Component_Name</spirit:name>
<spirit:value spirit:resolve="user" spirit:id="PARAM_VALUE.Component_Name" spirit:order="1">uberddr3_axi_v1_0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>SELF_REFRESH</spirit:name>
<spirit:displayName>Self-Refresh</spirit:displayName>
<spirit:value spirit:resolve="user" spirit:id="PARAM_VALUE.SELF_REFRESH" spirit:choiceRef="choice_pairs_96a879b9">0</spirit:value>
</spirit:parameter>
</spirit:parameters>
<spirit:vendorExtensions>
<xilinx:coreExtensions>
@ -2090,20 +2137,20 @@
<xilinx:displayName>uberddr3_axi_v1_0</xilinx:displayName>
<xilinx:definitionSource>package_project</xilinx:definitionSource>
<xilinx:vendorURL>https://github.com/AngeloJacobo/UberDDR3</xilinx:vendorURL>
<xilinx:coreRevision>9</xilinx:coreRevision>
<xilinx:coreCreationDateTime>2024-10-19T05:33:11Z</xilinx:coreCreationDateTime>
<xilinx:coreRevision>11</xilinx:coreRevision>
<xilinx:coreCreationDateTime>2024-11-24T08:00:34Z</xilinx:coreCreationDateTime>
<xilinx:tags>
<xilinx:tag xilinx:name="nopcore"/>
</xilinx:tags>
</xilinx:coreExtensions>
<xilinx:packagingInfo>
<xilinx:xilinxVersion>2022.1</xilinx:xilinxVersion>
<xilinx:checksum xilinx:scope="busInterfaces" xilinx:value="a8e6cc4e"/>
<xilinx:checksum xilinx:scope="busInterfaces" xilinx:value="6c0c2bc0"/>
<xilinx:checksum xilinx:scope="memoryMaps" xilinx:value="cd65c31e"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="68e3a14b"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="a969876f"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="ba5aba03"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="abd96048"/>
<xilinx:checksum xilinx:scope="hdlParameters" xilinx:value="86f21185"/>
<xilinx:checksum xilinx:scope="parameters" xilinx:value="17670e8c"/>
<xilinx:checksum xilinx:scope="parameters" xilinx:value="5574e240"/>
</xilinx:packagingInfo>
</spirit:vendorExtensions>
</spirit:component>

View File

@ -15,6 +15,7 @@ proc init_gui { IPINST } {
ipgui::add_param $IPINST -name "DIC" -parent ${Page_0}
ipgui::add_param $IPINST -name "DQ_BITS" -parent ${Page_0}
ipgui::add_param $IPINST -name "ECC_ENABLE" -parent ${Page_0}
ipgui::add_param $IPINST -name "SELF_REFRESH" -parent ${Page_0}
ipgui::add_param $IPINST -name "MICRON_SIM" -parent ${Page_0}
ipgui::add_param $IPINST -name "ODELAY_SUPPORTED" -parent ${Page_0}
ipgui::add_param $IPINST -name "ROW_BITS" -parent ${Page_0}
@ -142,6 +143,15 @@ proc validate_PARAM_VALUE.ECC_ENABLE { PARAM_VALUE.ECC_ENABLE } {
return true
}
proc update_PARAM_VALUE.SELF_REFRESH { PARAM_VALUE.SELF_REFRESH } {
# Procedure called to update SELF_REFRESH when any of the dependent parameters in the arguments change
}
proc validate_PARAM_VALUE.SELF_REFRESH { PARAM_VALUE.SELF_REFRESH } {
# Procedure called to validate SELF_REFRESH
return true
}
proc update_PARAM_VALUE.MICRON_SIM { PARAM_VALUE.MICRON_SIM } {
# Procedure called to update MICRON_SIM when any of the dependent parameters in the arguments change
}
@ -353,6 +363,11 @@ proc update_MODELPARAM_VALUE.ECC_ENABLE { MODELPARAM_VALUE.ECC_ENABLE PARAM_VALU
set_property value [get_property value ${PARAM_VALUE.ECC_ENABLE}] ${MODELPARAM_VALUE.ECC_ENABLE}
}
proc update_MODELPARAM_VALUE.SELF_REFRESH { MODELPARAM_VALUE.SELF_REFRESH PARAM_VALUE.SELF_REFRESH } {
# Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value
set_property value [get_property value ${PARAM_VALUE.SELF_REFRESH}] ${MODELPARAM_VALUE.SELF_REFRESH}
}
proc update_MODELPARAM_VALUE.DIC { MODELPARAM_VALUE.DIC PARAM_VALUE.DIC } {
# Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value
set_property value [get_property value ${PARAM_VALUE.DIC}] ${MODELPARAM_VALUE.DIC}

View File

@ -19,8 +19,10 @@ proc init_gui { IPINST } {
set_property tooltip {Width of bank address} ${BA_BITS}
set BYTE_LANES [ipgui::add_param $IPINST -name "BYTE_LANES" -parent ${Page_0}]
set_property tooltip {Number of byte lanes of DDR3 RAM in the FPGA board (e.g. x16 DDR3 will have 2 byte lanes)} ${BYTE_LANES}
set ECC_ENABLE [ipgui::add_param $IPINST -name "ECC_ENABLE" -parent ${Page_0}]
set_property tooltip {0 = DIsabled, 1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC} ${ECC_ENABLE}
set ECC_ENABLE [ipgui::add_param $IPINST -name "ECC_ENABLE" -parent ${Page_0} -widget comboBox]
set_property tooltip {Type of ECC (0,1,2,3)} ${ECC_ENABLE}
set SELF_REFRESH [ipgui::add_param $IPINST -name "SELF_REFRESH" -parent ${Page_0} -widget comboBox]
set_property tooltip {Enable option for self-refresh} ${SELF_REFRESH}
set SKIP_INTERNAL_TEST [ipgui::add_param $IPINST -name "SKIP_INTERNAL_TEST" -parent ${Page_0}]
set_property tooltip {Check to skip built-in self-test (check this if UberDDR3 will be connected to Microblaze)} ${SKIP_INTERNAL_TEST}
set ODELAY_SUPPORTED [ipgui::add_param $IPINST -name "ODELAY_SUPPORTED" -parent ${Page_0}]
@ -284,6 +286,15 @@ proc validate_PARAM_VALUE.SECOND_WISHBONE { PARAM_VALUE.SECOND_WISHBONE } {
return true
}
proc update_PARAM_VALUE.SELF_REFRESH { PARAM_VALUE.SELF_REFRESH } {
# Procedure called to update SELF_REFRESH when any of the dependent parameters in the arguments change
}
proc validate_PARAM_VALUE.SELF_REFRESH { PARAM_VALUE.SELF_REFRESH } {
# Procedure called to validate SELF_REFRESH
return true
}
proc update_PARAM_VALUE.SKIP_INTERNAL_TEST { PARAM_VALUE.SKIP_INTERNAL_TEST } {
# Procedure called to update SKIP_INTERNAL_TEST when any of the dependent parameters in the arguments change
}
@ -405,6 +416,11 @@ proc update_MODELPARAM_VALUE.ECC_ENABLE { MODELPARAM_VALUE.ECC_ENABLE PARAM_VALU
set_property value [get_property value ${PARAM_VALUE.ECC_ENABLE}] ${MODELPARAM_VALUE.ECC_ENABLE}
}
proc update_MODELPARAM_VALUE.SELF_REFRESH { MODELPARAM_VALUE.SELF_REFRESH PARAM_VALUE.SELF_REFRESH } {
# Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value
set_property value [get_property value ${PARAM_VALUE.SELF_REFRESH}] ${MODELPARAM_VALUE.SELF_REFRESH}
}
proc update_MODELPARAM_VALUE.DIC { MODELPARAM_VALUE.DIC PARAM_VALUE.DIC } {
# Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value
set_property value [get_property value ${PARAM_VALUE.DIC}] ${MODELPARAM_VALUE.DIC}