Line 49... |
Line 49... |
//`define DDR_DESELECT 4'b1???
|
//`define DDR_DESELECT 4'b1???
|
//
|
//
|
// In this controller, 24-bit commands tend to be passed around. These
|
// In this controller, 24-bit commands tend to be passed around. These
|
// 'commands' are bit fields. Here we specify the bits associated with
|
// 'commands' are bit fields. Here we specify the bits associated with
|
// the bit fields.
|
// the bit fields.
|
`define DDR_RSTDONE 26 // End the reset sequence?
|
`define DDR_RSTDONE 24 // End the reset sequence?
|
`define DDR_RSTTIMER 25 // Does this reset command take multiple clocks?
|
`define DDR_RSTTIMER 23 // Does this reset command take multiple clocks?
|
`define DDR_RSTBIT 24 // Value to place on reset_n
|
`define DDR_RSTBIT 22 // Value to place on reset_n
|
`define DDR_CKEBIT 23 // Should this reset command set CKE?
|
`define DDR_CKEBIT 21 // Should this reset command set CKE?
|
`define DDR_CMDLEN 23
|
`define DDR_CMDLEN 21
|
`define DDR_CSBIT 22
|
`define DDR_CSBIT 20
|
`define DDR_RASBIT 21
|
`define DDR_RASBIT 19
|
`define DDR_CASBIT 20
|
`define DDR_CASBIT 18
|
`define DDR_WEBIT 19
|
`define DDR_WEBIT 17
|
`define DDR_NOPTIMER 18 // Steal this from BA bits
|
`define DDR_NOPTIMER 16 // Steal this from BA bits
|
`define DDR_BABITS 3 // BABITS are really from 18:16, they are 3 bits
|
`define DDR_BABITS 3 // BABITS are really from 18:16, they are 3 bits
|
`define DDR_ADDR_BITS 14
|
`define DDR_ADDR_BITS 14
|
|
|
module wbddrsdram(i_clk, i_reset,
|
module wbddrsdram(i_clk, i_reset,
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
Line 107... |
Line 107... |
|
|
// The pending transaction
|
// The pending transaction
|
reg [31:0] r_data;
|
reg [31:0] r_data;
|
reg r_pending, r_we;
|
reg r_pending, r_we;
|
reg [25:0] r_addr;
|
reg [25:0] r_addr;
|
reg [14:0] r_row;
|
reg [13:0] r_row;
|
reg [2:0] r_bank;
|
reg [2:0] r_bank;
|
reg [9:0] r_col;
|
reg [9:0] r_col;
|
reg [1:0] r_sub;
|
reg [1:0] r_sub;
|
reg r_move; // It was accepted, and can move to next stage
|
reg r_move; // It was accepted, and can move to next stage
|
|
|
// Can the pending transaction be satisfied with the current (ongoing)
|
// Can the pending transaction be satisfied with the current (ongoing)
|
// transaction?
|
// transaction?
|
reg m_move, m_match, m_continue, m_pending, m_we;
|
reg m_move, m_match, m_continue, m_pending, m_we;
|
reg [25:0] m_addr;
|
reg [25:0] m_addr;
|
reg [14:0] m_row;
|
reg [13:0] m_row;
|
reg [2:0] m_bank;
|
reg [2:0] m_bank;
|
reg [9:0] m_col;
|
reg [9:0] m_col;
|
reg [1:0] m_sub;
|
reg [1:0] m_sub;
|
|
|
// Can we preload the next bank?
|
// Can we preload the next bank?
|
reg [14:0] r_nxt_row;
|
reg [13:0] r_nxt_row;
|
reg [2:0] r_nxt_bank;
|
reg [2:0] r_nxt_bank;
|
|
|
//
|
//
|
// tWTR = 7.5
|
// tWTR = 7.5
|
// tRRD = 7.5
|
// tRRD = 7.5
|
Line 167... |
Line 167... |
// timer commands indicate whether or not the command during the timer is to
|
// timer commands indicate whether or not the command during the timer is to
|
// be set to idle, or whether the command is instead left as it was.
|
// be set to idle, or whether the command is instead left as it was.
|
reg reset_override, reset_ztimer;
|
reg reset_override, reset_ztimer;
|
reg [3:0] reset_address;
|
reg [3:0] reset_address;
|
reg [(`DDR_CMDLEN-1):0] reset_cmd, cmd, refresh_cmd;
|
reg [(`DDR_CMDLEN-1):0] reset_cmd, cmd, refresh_cmd;
|
reg [26:0] reset_instruction;
|
reg [24:0] reset_instruction;
|
reg [16:0] reset_timer;
|
reg [16:0] reset_timer;
|
initial reset_override = 1'b1;
|
initial reset_override = 1'b1;
|
initial reset_address = 4'h0;
|
initial reset_address = 4'h0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_reset)
|
if (i_reset)
|
begin
|
begin
|
reset_override <= 1'b1;
|
reset_override <= 1'b1;
|
reset_cmd <= { `DDR_NOOP, reset_instruction[18:0]};
|
reset_cmd <= { `DDR_NOOP, reset_instruction[16:0]};
|
end else if (!reset_ztimer)
|
end else if (reset_ztimer)
|
;
|
begin
|
else if (reset_instruction[`DDR_RSTDONE])
|
if (reset_instruction[`DDR_RSTDONE])
|
reset_override <= 1'b0;
|
reset_override <= 1'b0;
|
else
|
reset_cmd <= reset_instruction[20:0];
|
reset_cmd <= reset_instruction[22:0];
|
end
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_reset)
|
if (i_reset)
|
o_ddr_cke <= 1'b0;
|
o_ddr_cke <= 1'b0;
|
else if ((reset_override)&&(reset_ztimer))
|
else if ((reset_override)&&(reset_ztimer))
|
o_ddr_cke <= reset_instruction[`DDR_CKEBIT];
|
o_ddr_cke <= reset_instruction[`DDR_CKEBIT];
|
|
|
initial reset_ztimer = 1'b0; // Is the timer zero?
|
initial reset_ztimer = 1'b0; // Is the timer zero?
|
initial reset_timer = 17'h01;
|
initial reset_timer = 17'h02;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_reset)
|
if (i_reset)
|
begin
|
begin
|
reset_ztimer <= 1'b0;
|
reset_ztimer <= 1'b0;
|
reset_timer <= 17'd1;
|
reset_timer <= 17'd2;
|
end else if (!reset_ztimer)
|
end else if (!reset_ztimer)
|
begin
|
begin
|
reset_ztimer <= (reset_timer == 17'h01);
|
reset_ztimer <= (reset_timer == 17'h01);
|
reset_timer <= reset_timer - 17'h01;
|
reset_timer <= reset_timer - 17'h01;
|
end else if (reset_instruction[`DDR_RSTTIMER])
|
end else if (reset_instruction[`DDR_RSTTIMER])
|
begin
|
begin
|
reset_ztimer <= 1'b0;
|
reset_ztimer <= 1'b0;
|
reset_timer <= reset_instruction[16:0];
|
reset_timer <= reset_instruction[16:0];
|
end
|
end
|
|
|
wire [18:0] w_ckXPR = CKXPR, w_ckRST = 4, w_ckRP = 3,
|
wire [16:0] w_ckXPR = CKXPR, w_ckRST = 4, w_ckRP = 3,
|
w_ckRFC = CKRFC;
|
w_ckRFC = CKRFC;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_reset)
|
if (i_reset)
|
reset_instruction <= { 4'h4, `DDR_NOOP, 19'd40_000 };
|
reset_instruction <= { 4'h4, `DDR_NOOP, 17'd40_000 };
|
else case(reset_address) // RSTDONE, TIMER, CKE, ??
|
else if (reset_ztimer) case(reset_address) // RSTDONE, TIMER, CKE, ??
|
// 1. Reset asserted (active low) for 200 us. (@200MHz)
|
// 1. Reset asserted (active low) for 200 us. (@200MHz)
|
4'h0: reset_instruction <= { 4'h4, `DDR_NOOP, 19'd40_000 };
|
4'h0: reset_instruction <= { 4'h4, `DDR_NOOP, 17'd40_000 };
|
// 2. Reset de-asserted, wait 500 us before asserting CKE
|
// 2. Reset de-asserted, wait 500 us before asserting CKE
|
4'h1: reset_instruction <= { 4'h6, `DDR_NOOP, 19'd100_000 };
|
4'h1: reset_instruction <= { 4'h6, `DDR_NOOP, 17'd100_000 };
|
// 3. Assert CKE, wait minimum of Reset CKE Exit time
|
// 3. Assert CKE, wait minimum of Reset CKE Exit time
|
4'h2: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckXPR };
|
4'h2: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckXPR };
|
// 4. Look MR2. (1CK, no TIMER)
|
// 4. Look MR2. (1CK, no TIMER)
|
4'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2,
|
4'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2,
|
5'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2
|
3'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2
|
// 3. Wait 4 clocks (tMRD)
|
// 3. Wait 4 clocks (tMRD)
|
4'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h04 };
|
4'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
|
// 5. Set MR1
|
// 5. Set MR1
|
4'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1,
|
4'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1,
|
3'h0, // Reserved for Future Use (RFU)
|
1'h0, // Reserved for Future Use (RFU)
|
1'b0, // Qoff - output buffer enabled
|
1'b0, // Qoff - output buffer enabled
|
1'b1, // TDQS ... enabled
|
1'b1, // TDQS ... enabled
|
1'b0, // RFU
|
1'b0, // RFU
|
1'b0, // High order bit, Rtt_Nom (3'b011)
|
1'b0, // High order bit, Rtt_Nom (3'b011)
|
1'b0, // RFU
|
1'b0, // RFU
|
Line 239... |
Line 239... |
2'b0, // Additive latency = 0
|
2'b0, // Additive latency = 0
|
1'b1, // Low order bit of Rtt_Nom
|
1'b1, // Low order bit of Rtt_Nom
|
1'b1, // DIC set to 2'b01
|
1'b1, // DIC set to 2'b01
|
1'b1 }; // MRS1, DLL enable
|
1'b1 }; // MRS1, DLL enable
|
// 7. Wait another 4 clocks
|
// 7. Wait another 4 clocks
|
4'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h04 };
|
4'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
|
// 8. Send MRS0
|
// 8. Send MRS0
|
4'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0,
|
4'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0,
|
3'b0, // Reserved for future use
|
1'b0, // Reserved for future use
|
1'b0, // PPD control, (slow exit(DLL off))
|
1'b0, // PPD control, (slow exit(DLL off))
|
3'b1, // Write recovery for auto precharge
|
3'b1, // Write recovery for auto precharge
|
1'b0, // DLL Reset (No)
|
1'b0, // DLL Reset (No)
|
//
|
//
|
1'b0, // TM mode normal
|
1'b0, // TM mode normal
|
3'b01, // High 3-bits, CAS latency (=4'b0010 = 4'd5)
|
3'b01, // High 3-bits, CAS latency (=4'b0010 = 4'd5)
|
1'b0, // Read burst type = nibble sequential
|
1'b0, // Read burst type = nibble sequential
|
1'b0, // Low bit of cas latency
|
1'b0, // Low bit of cas latency
|
2'b0 }; // Burst length = 8 (Fixed)
|
2'b0 }; // Burst length = 8 (Fixed)
|
// 9. Wait tMOD, is max(12 clocks, 15ns)
|
// 9. Wait tMOD, is max(12 clocks, 15ns)
|
4'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h0c };
|
4'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h0a };
|
// 10. Issue a ZQCL command to start ZQ calibration, A10 is high
|
// 10. Issue a ZQCL command to start ZQ calibration, A10 is high
|
4'h9: reset_instruction <= { 4'h7, `DDR_ZQS, 8'h0, 1'b1, 10'h0};
|
4'h9: reset_instruction <= { 4'h3, `DDR_ZQS, 6'h0, 1'b1, 10'h0};
|
//11.Wait for both tDLLK and tZQinit completed, both are 512 cks
|
//11.Wait for both tDLLK and tZQinit completed, both are 512 cks
|
4'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 19'd512 };
|
4'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd512 };
|
// 12. Precharge all command
|
// 12. Precharge all command
|
4'hb: reset_instruction <= { 4'h7, `DDR_PRECHARGE, 8'h0, 1'b1, 10'h0 };
|
4'hb: reset_instruction <= { 4'h3, `DDR_PRECHARGE, 6'h0, 1'b1, 10'h0 };
|
// 13. Wait for the precharge to complete
|
// 13. Wait for the precharge to complete
|
4'hc: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP };
|
4'hc: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP };
|
// 14. A single Auto Refresh commands
|
// 14. A single Auto Refresh commands
|
4'hd: reset_instruction <= { 4'h7, `DDR_REFRESH, 19'h00 };
|
4'hd: reset_instruction <= { 4'h3, `DDR_REFRESH, 17'h00 };
|
// 15. Wait for the auto refresh to complete
|
// 15. Wait for the auto refresh to complete
|
4'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC };
|
4'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC };
|
// Two Auto Refresh commands
|
// Two Auto Refresh commands
|
default:
|
default:
|
reset_instruction <={4'hb, `DDR_NOOP, 19'd00_000 };
|
reset_instruction <={4'hb, `DDR_NOOP, 17'd00_000 };
|
endcase
|
endcase
|
// reset_instruction <= reset_mem[reset_address];
|
// reset_instruction <= reset_mem[reset_address];
|
|
|
initial reset_address = 4'h0;
|
initial reset_address = 4'h0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_reset)
|
if (i_reset)
|
reset_address <= 4'h0;
|
reset_address <= 4'h1;
|
else if (reset_ztimer)
|
else if (reset_ztimer)
|
reset_address <= reset_address + 4'h1;
|
reset_address <= reset_address + 4'h1;
|
//
|
//
|
// initial reset_mem =
|
// initial reset_mem =
|
// 0. !DONE, TIMER,RESET_N=0, CKE=0, CMD = NOOP, TIMER = 200us ( 40,000)
|
// 0. !DONE, TIMER,RESET_N=0, CKE=0, CMD = NOOP, TIMER = 200us ( 40,000)
|
Line 354... |
Line 354... |
end
|
end
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
// if (cmd[22:19] == `DDR_ACTIVATE)
|
// if (cmd[22:19] == `DDR_ACTIVATE)
|
if (need_open_bank)
|
if (need_open_bank)
|
bank_address[activate_bank_cmd[18:16]]
|
bank_address[activate_bank_cmd[16:14]]
|
<= activate_bank_cmd[14:0];
|
<= activate_bank_cmd[13:0];
|
|
|
//
|
//
|
//
|
//
|
// Okay, let's investigate when we need to do a refresh. Our plan will be to
|
// Okay, let's investigate when we need to do a refresh. Our plan will be to
|
// do 4 refreshes every tREFI*4 seconds. tREFI = 7.8us, but its a parameter
|
// do 4 refreshes every tREFI*4 seconds. tREFI = 7.8us, but its a parameter
|
Line 386... |
Line 386... |
refresh_clk <= refresh_clk-1;
|
refresh_clk <= refresh_clk-1;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
need_refresh <= (refresh_clk == 0)||(midrefresh);
|
need_refresh <= (refresh_clk == 0)||(midrefresh);
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (!need_refresh)
|
if (!need_refresh)
|
refresh_cmd <= { `DDR_NOOP, 19'h00 };
|
refresh_cmd <= { `DDR_NOOP, 17'h00 };
|
else if (~banks_are_closing)
|
else if (~banks_are_closing)
|
refresh_cmd <= { `DDR_PRECHARGE, 3'h0, 5'h0, 1'b1, 10'h00 };
|
refresh_cmd <= { `DDR_PRECHARGE, 3'h0, 3'h0, 1'b1, 10'h00 };
|
else if (~all_banks_closed)
|
else if (~all_banks_closed)
|
refresh_cmd <= { `DDR_NOOP, 19'h00 };
|
refresh_cmd <= { `DDR_NOOP, 17'h00 };
|
else
|
else
|
refresh_cmd <= { `DDR_REFRESH, 19'h00 };
|
refresh_cmd <= { `DDR_REFRESH, 17'h00 };
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
midrefresh <= (need_refresh)&&(all_banks_closed)&&(~refresh_clear);
|
midrefresh <= (need_refresh)&&(all_banks_closed)&&(~refresh_clear);
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (!midrefresh)
|
if (!midrefresh)
|
Line 479... |
Line 479... |
if (~o_wb_stall)
|
if (~o_wb_stall)
|
begin
|
begin
|
r_we <= i_wb_we;
|
r_we <= i_wb_we;
|
r_addr <= i_wb_addr;
|
r_addr <= i_wb_addr;
|
r_data <= i_wb_data;
|
r_data <= i_wb_data;
|
r_row <= i_wb_addr[25:11];
|
r_row <= i_wb_addr[25:12];
|
r_bank <= i_wb_addr[10:8];
|
r_bank <= i_wb_addr[11:9];
|
r_col <= { i_wb_addr[7:0], 2'b00 }; // 9:2
|
r_col <= { i_wb_addr[8:2], 3'b000 }; // 9:2
|
r_sub <= i_wb_addr[1:0];
|
r_sub <= i_wb_addr[1:0];
|
|
|
// pre-emptive work
|
// pre-emptive work
|
r_nxt_row <= i_wb_addr[25:11]+15'h1;
|
r_nxt_row <= i_wb_addr[25:12]+14'h1;
|
r_nxt_bank <= i_wb_addr[10:8]+3'h1;
|
r_nxt_bank <= i_wb_addr[11:9]+3'h1;
|
end
|
end
|
end
|
end
|
|
|
reg [2:0] bank_active[7:0];
|
reg [2:0] bank_active[7:0];
|
reg [14:0] bank_address[7:0];
|
reg [13:0] bank_address[7:0];
|
|
|
reg [(`DDR_CMDLEN-1):0] close_bank_cmd, activate_bank_cmd, rw_cmd;
|
reg [(`DDR_CMDLEN-1):0] close_bank_cmd, activate_bank_cmd, rw_cmd;
|
reg need_close_bank, need_close_this_bank,
|
reg need_close_bank, need_close_this_bank,
|
last_close_bank, maybe_close_next_bank,
|
last_close_bank, maybe_close_next_bank,
|
need_open_bank, last_open_bank, maybe_open_next_bank,
|
need_open_bank, last_open_bank, maybe_open_next_bank,
|
Line 512... |
Line 512... |
&&(bank_active[r_nxt_bank][0])
|
&&(bank_active[r_nxt_bank][0])
|
&&(r_nxt_row != bank_address[r_nxt_bank])
|
&&(r_nxt_row != bank_address[r_nxt_bank])
|
&&(!need_close_this_bank);
|
&&(!need_close_this_bank);
|
|
|
close_bank_cmd <= (maybe_close_next_bank)
|
close_bank_cmd <= (maybe_close_next_bank)
|
? { `DDR_PRECHARGE, r_nxt_bank, r_nxt_row[14:10], 1'b0, r_nxt_row[9:0] }
|
? { `DDR_PRECHARGE, r_nxt_bank, r_nxt_row[13:11], 1'b0, r_nxt_row[9:0] }
|
: { `DDR_PRECHARGE, r_bank, r_row[14:10], 1'b0, r_row[9:0] };
|
: { `DDR_PRECHARGE, r_bank, r_row[13:11], 1'b0, r_row[9:0] };
|
|
|
|
|
need_open_bank <= (r_pending)&&(bank_active[r_bank][1:0]==2'b00)
|
need_open_bank <= (r_pending)&&(bank_active[r_bank][1:0]==2'b00)
|
&&(!last_open_bank);
|
&&(!last_open_bank);
|
last_open_bank <= need_open_bank;
|
last_open_bank <= need_open_bank;
|
Line 525... |
Line 525... |
maybe_open_next_bank <= (r_pending)
|
maybe_open_next_bank <= (r_pending)
|
&&(bank_active[r_nxt_bank][1:0] == 2'b00)
|
&&(bank_active[r_nxt_bank][1:0] == 2'b00)
|
&&(!need_open_bank)&&(!need_close_bank);
|
&&(!need_open_bank)&&(!need_close_bank);
|
|
|
activate_bank_cmd <= (maybe_open_next_bank)
|
activate_bank_cmd <= (maybe_open_next_bank)
|
? { `DDR_ACTIVATE,r_nxt_bank,1'b0,r_nxt_row[14:0] }
|
? { `DDR_ACTIVATE,r_nxt_bank, r_nxt_row[13:0] }
|
: { `DDR_ACTIVATE, r_bank, 1'b0,r_row[14:0] };
|
: { `DDR_ACTIVATE, r_bank, r_row[13:0] };
|
|
|
|
|
|
|
valid_bank <= (r_pending)&&(bank_active[r_bank][1:0]==2'b11)
|
valid_bank <= (r_pending)&&(bank_active[r_bank][1:0]==2'b11)
|
&&(bank_address[r_bank]==r_row)
|
&&(bank_address[r_bank]==r_row)
|
&&(!last_valid_bank);
|
&&(!last_valid_bank);
|
last_valid_bank <= valid_bank;
|
last_valid_bank <= valid_bank;
|
|
|
rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= (~r_pending)?`DDR_NOOP:((r_we)?`DDR_WRITE:`DDR_READ);
|
rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= (~r_pending)?`DDR_NOOP:((r_we)?`DDR_WRITE:`DDR_READ);
|
rw_cmd[`DDR_WEBIT-1:0] <= { r_bank, 5'h0, 1'b0, r_col };
|
rw_cmd[`DDR_WEBIT-1:0] <= { r_bank, 3'h0, 1'b0, r_col };
|
end
|
end
|
|
|
|
|
// Match registers, to see if we can move forward without sending a
|
// Match registers, to see if we can move forward without sending a
|
// new command
|
// new command
|