|
@@ -45,7 +45,8 @@ module sdram
|
|
|
// tRFC 60 ns 6 10 REFRESH to ACTIVE
|
|
|
// tRP 18 ns 2 3 PRECHARGE to ACTIVE/REFRESH
|
|
|
// tRAS 42 ns 5 7 ACTIVE to PRECHARGE
|
|
|
- // tRC 60 ns 6 10 ACTIVE to ACTIVE
|
|
|
+ // tRC 60 ns 6 10 ACTIVE to ACTIVE (same bank)
|
|
|
+ // tRRD 12 ns 2 2 ACTICE to ACTIVE (different bank)
|
|
|
// tWR 12 ns 2 2 Last write data to PRECHARGE
|
|
|
// tMRD 2 2 MODE REGISTER to ACTIVE/REFRESH
|
|
|
//
|
|
@@ -59,53 +60,54 @@ module sdram
|
|
|
t_rp = 3,
|
|
|
t_ras = 7,
|
|
|
t_rc = 10,
|
|
|
+ t_rrd = 2,
|
|
|
t_wr = 2,
|
|
|
t_mrd = 2,
|
|
|
|
|
|
- t_refi_lg2 = 9, // 512 cycles (extra conservative)
|
|
|
+ t_refi_lg2 = 10, // 1024 cycles
|
|
|
t_p_lg2 = 15, // 32768 cycles
|
|
|
|
|
|
- burst_lg2 = 3 // Burst length on port 1
|
|
|
+ burst_lg2 = 1 // Burst length on port 1
|
|
|
)
|
|
|
(
|
|
|
// Reset and clock
|
|
|
- input rst_n,
|
|
|
- input clk,
|
|
|
+ input rst_n,
|
|
|
+ input clk,
|
|
|
|
|
|
// SDRAM hardware interface
|
|
|
- output sr_clk, // SDRAM clock output buffer
|
|
|
- output sr_cke, // SDRAM clock enable
|
|
|
- output sr_cs_n, // SDRAM CS#
|
|
|
- output sr_ras_n, // SDRAM RAS#
|
|
|
- output sr_cas_n, // SDRAM CAS#
|
|
|
- output sr_we_n, // SDRAM WE#
|
|
|
- output [1:0] sr_dqm, // SDRAM DQM (per byte)
|
|
|
- output [1:0] sr_ba, // SDRAM bank selects
|
|
|
- output [12:0] sr_a, // SDRAM address bus
|
|
|
- inout [15:0] sr_dq, // SDRAM data bus
|
|
|
+ output sr_clk, // SDRAM clock output buffer
|
|
|
+ output sr_cke, // SDRAM clock enable
|
|
|
+ output sr_cs_n, // SDRAM CS#
|
|
|
+ output sr_ras_n, // SDRAM RAS#
|
|
|
+ output sr_cas_n, // SDRAM CAS#
|
|
|
+ output sr_we_n, // SDRAM WE#
|
|
|
+ output [1:0] sr_dqm, // SDRAM DQM (per byte)
|
|
|
+ output [1:0] sr_ba, // SDRAM bank selects
|
|
|
+ output [12:0] sr_a, // SDRAM address bus
|
|
|
+ inout [15:0] sr_dq, // SDRAM data bus
|
|
|
|
|
|
// Port 0: single byte, high priority
|
|
|
- input [24:0] a0, // Address, must be stable until ack
|
|
|
+ input [24:0] a0, // Address, must be stable until ack
|
|
|
|
|
|
- output [7:0] rd0, // Data from SDRAM
|
|
|
- input rrq0, // Read request
|
|
|
- output [t_rcd+t_cl+1:0] rack0, // Read ack
|
|
|
+ output reg [7:0] rd0, // Data from SDRAM
|
|
|
+ input rrq0, // Read request
|
|
|
+ output reg [t_rcd+t_cl+3:0] rack0, // Read ack
|
|
|
|
|
|
- input [7:0] wd0, // Data to SDRAM
|
|
|
- input wrq0, // Write request
|
|
|
- output [t_rcd:0] wack0, // Write ack
|
|
|
+ input [7:0] wd0, // Data to SDRAM
|
|
|
+ input wrq0, // Write request
|
|
|
+ output reg wack0, // Write ack (data latched)
|
|
|
|
|
|
// Port 1
|
|
|
- input [24:1] a1,
|
|
|
+ input [24:2] a1,
|
|
|
+ input [7:0] be1, // Write byte enable
|
|
|
|
|
|
- output [15:0] rd1,
|
|
|
- input rrq1,
|
|
|
- output [t_rcd+t_cl+1:0] rack1,
|
|
|
+ output reg [31:0] rd1,
|
|
|
+ input rrq1,
|
|
|
+ output reg [t_rcd+t_cl+3:0] rack1,
|
|
|
|
|
|
- input [15:0] wd1,
|
|
|
- input [1:0] wbe1, // Write byte enable
|
|
|
- input wrq1,
|
|
|
- output [t_rcd:0] wack1
|
|
|
+ input [31:0] wd1,
|
|
|
+ input wrq1,
|
|
|
+ output reg wack1
|
|
|
);
|
|
|
|
|
|
// Mode register data
|
|
@@ -142,7 +144,7 @@ module sdram
|
|
|
localparam cmd_ref = 5'b1_0001; // AUTO REFRESH
|
|
|
localparam cmd_mrd = 5'b0_0000; // LOAD MODE REGISTER
|
|
|
reg [4:0] dram_cmd;
|
|
|
- wire is_rfsh = dram_cmd[4];
|
|
|
+ wire is_rfsh = dram_cmd[4];
|
|
|
assign sr_cs_n = dram_cmd[3];
|
|
|
assign sr_ras_n = dram_cmd[2];
|
|
|
assign sr_cas_n = dram_cmd[1];
|
|
@@ -177,30 +179,21 @@ module sdram
|
|
|
reg dram_d_en; // Drive data out
|
|
|
assign sr_dq = dram_d_en ? dram_d : 16'hzzzz;
|
|
|
|
|
|
- // Input register for SDRAM data; a single register to make it
|
|
|
- // possible to put it in the I/O register
|
|
|
+ // Input register for SDRAM data
|
|
|
reg [15:0] dram_q;
|
|
|
|
|
|
- // Port 0 output signals
|
|
|
- assign rd0 = a0[0] ? dram_q[15:8] : dram_q[7:0];
|
|
|
- reg [t_rcd+t_cl+1:0] rack0_q;
|
|
|
- assign rack0 = rack0_q;
|
|
|
- reg [t_rcd:0] wack0_q;
|
|
|
- assign wack0 = wack0_q;
|
|
|
-
|
|
|
- // Port 1 output signals
|
|
|
- assign rd1 = dram_q;
|
|
|
- reg [t_rcd+t_cl+1:0] rack1_q;
|
|
|
- assign rack1 = rack1_q;
|
|
|
- reg [t_rcd:0] wack1_q;
|
|
|
- assign wack1 = wack1_q;
|
|
|
-
|
|
|
// State machine and counters
|
|
|
- reg [t_refi_lg2:0] rfsh_ctr; // Refresh timer
|
|
|
- reg [t_p_lg2:t_refi_lg2] init_ctr; // Reset to init counter
|
|
|
-
|
|
|
- // XXX: compute the necessary width of this field elsewhere
|
|
|
- reg [4:0] op_cycle; // Cycles into the current operation
|
|
|
+ reg [t_refi_lg2-2:0] rfsh_ctr; // Refresh timer
|
|
|
+ wire rfsh_ctr_msb = rfsh_ctr[t_refi_lg2-2];
|
|
|
+ reg rfsh_ctr_last_msb;
|
|
|
+ wire rfsh_tick = rfsh_ctr_last_msb & ~rfsh_ctr_msb;
|
|
|
+ reg [t_p_lg2:t_refi_lg2-1] init_ctr; // Reset to init counter
|
|
|
+ reg [1:0] rfsh_prio; // Refresh priority
|
|
|
+ // Bit 0 - refresh if opportune
|
|
|
+ // Bit 1 - refresh urgent
|
|
|
+ reg port; // Port being serviced
|
|
|
+
|
|
|
+ reg [3:0] op_cycle; // Cycles into the current operation
|
|
|
|
|
|
// The actual values are unimportant; the compiler will optimize
|
|
|
// the state machine implementation.
|
|
@@ -209,33 +202,60 @@ module sdram
|
|
|
st_init, // 1st refresh during initialization
|
|
|
st_idle, // Idle state: all banks precharged
|
|
|
st_rfsh,
|
|
|
- st_p0_rd,
|
|
|
- st_p0_wr,
|
|
|
- st_p1_rd,
|
|
|
- st_p1_wr
|
|
|
+ st_rd,
|
|
|
+ st_wr
|
|
|
} state_t;
|
|
|
state_t state = st_reset;
|
|
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- rfsh_ctr <= 1'b0;
|
|
|
- init_ctr <= 1'b0;
|
|
|
+ rfsh_ctr <= 1'b0;
|
|
|
+ init_ctr <= 1'b0;
|
|
|
+ rfsh_prio <= 2'b00;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- rfsh_ctr <= is_rfsh ? 1'b0 : rfsh_ctr + 1'b1;
|
|
|
+ rfsh_ctr <= rfsh_ctr + 1'b1;
|
|
|
+ rfsh_ctr_last_msb <= rfsh_ctr_msb;
|
|
|
+
|
|
|
+ // Refresh priority management
|
|
|
+ if (is_rfsh)
|
|
|
+ rfsh_prio <= 2'b00; // This is a refresh cycle
|
|
|
+ else if (rfsh_tick)
|
|
|
+ rfsh_prio <= { rfsh_prio[0], 1'b1 };
|
|
|
|
|
|
// The refresh counter is also used as a prescaler
|
|
|
// for the initialization counter.
|
|
|
- if (init_ctr[t_refi_lg2] ^ rfsh_ctr[t_refi_lg2])
|
|
|
+ // Note that means init_ctr is two cycles "behind"
|
|
|
+ // rfsh_ctr; this is totally fine.
|
|
|
+ init_ctr <= init_ctr + rfsh_tick;
|
|
|
+ end // else: !if(~rst_n)
|
|
|
+
|
|
|
+ // Handle bank wraparound
|
|
|
+ reg last_dword; // This is the last dword in this bank
|
|
|
+ reg [14:0] next_bank; // Row:bank for the next bank
|
|
|
+ reg [11:2] col_addr; // Current bank:column
|
|
|
+ reg latch_next_bank;
|
|
|
+
|
|
|
+ always @(negedge rst_n or posedge clk)
|
|
|
+ if (~rst_n)
|
|
|
+ begin
|
|
|
+ latch_next_bank <= 1'b0;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ latch_next_bank <= st_idle;
|
|
|
+ if (latch_next_bank)
|
|
|
begin
|
|
|
- init_ctr[t_p_lg2:t_refi_lg2+1]
|
|
|
- <= init_ctr[t_p_lg2:t_refi_lg2+1] + 1'b1;
|
|
|
- init_ctr[t_refi_lg2] <= rfsh_ctr[t_refi_lg2];
|
|
|
+ next_bank <= { dram_a, dram_ba } + 1'b1;
|
|
|
+ last_dword <= &col_addr[9:2]; // last dword in bank?
|
|
|
end
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
+ reg [31:0] wdata_q;
|
|
|
+ reg [ 6:0] be_q;
|
|
|
+
|
|
|
//
|
|
|
// Careful with the timing here... there is one cycle between
|
|
|
// registers and wires, and the DRAM observes the clock 1/2
|
|
@@ -246,38 +266,38 @@ module sdram
|
|
|
begin
|
|
|
dram_cke <= 1'b0;
|
|
|
dram_cmd <= cmd_desl;
|
|
|
- dram_a <= 13'h0000;
|
|
|
- dram_ba <= 2'b00;
|
|
|
+ dram_a <= 13'hxxxx;
|
|
|
+ dram_ba <= 2'bxx;
|
|
|
dram_dqm <= 2'b00;
|
|
|
- dram_d <= 16'h0000;
|
|
|
+ dram_d <= 16'hxxxx;
|
|
|
dram_d_en <= 1'b1; // Don't float except during read
|
|
|
op_cycle <= 1'b0;
|
|
|
state <= st_reset;
|
|
|
|
|
|
- rack0_q <= 1'b0;
|
|
|
- wack0_q <= 1'b0;
|
|
|
- rack1_q <= 1'b0;
|
|
|
- wack1_q <= 1'b0;
|
|
|
+ rack0 <= 1'b0;
|
|
|
+ wack0 <= 1'b0;
|
|
|
+ rack1 <= 1'b0;
|
|
|
+ wack1 <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
dram_cke <= 1'b1; // Always true once out of reset
|
|
|
|
|
|
// Default values
|
|
|
- dram_a <= 13'h0000;
|
|
|
- dram_ba <= 2'b00;
|
|
|
+ dram_ba <= 2'bxx;
|
|
|
dram_dqm <= 2'b11;
|
|
|
- dram_d <= 16'h0000;
|
|
|
+ dram_d <= 16'hxxxx;
|
|
|
+ dram_cmd <= cmd_nop;
|
|
|
|
|
|
- rack0_q <= 1'b0;
|
|
|
- wack0_q <= 1'b0;
|
|
|
- rack1_q <= 1'b0;
|
|
|
- wack1_q <= 1'b0;
|
|
|
+ rack0 <= rack0 >> 1;
|
|
|
+ wack0 <= 1'b0;
|
|
|
+ rack1 <= rack1 >> 1;
|
|
|
+ wack1 <= 1'b0;
|
|
|
|
|
|
dram_d_en <= 1'b1; // Don't float except during read
|
|
|
|
|
|
if (state == st_reset || state == st_idle)
|
|
|
- op_cycle <= 1'b1; // == 0 + 1
|
|
|
+ op_cycle <= 1'b0;
|
|
|
else
|
|
|
op_cycle <= op_cycle + 1'b1;
|
|
|
|
|
@@ -294,16 +314,18 @@ module sdram
|
|
|
end
|
|
|
st_init:
|
|
|
begin
|
|
|
- if ( op_cycle == t_rp || op_cycle == t_rp + t_rfc )
|
|
|
+ // Add 3 to the count to account for skew between rfsh_ctr
|
|
|
+ // and init_ctr
|
|
|
+ if ( rfsh_ctr[4:0] == t_rp+3 || rfsh_ctr[4:0] == t_rp+t_rfc+3 )
|
|
|
begin
|
|
|
dram_cmd <= cmd_ref;
|
|
|
end
|
|
|
- if ( op_cycle == t_rp + t_rfc*2 )
|
|
|
+ if ( rfsh_ctr[4:0] == t_rp+t_rfc*2+3 )
|
|
|
begin
|
|
|
dram_cmd <= cmd_mrd;
|
|
|
dram_a <= mrd_val;
|
|
|
end
|
|
|
- if ( op_cycle >= t_rp + t_rfc*2 + t_mrd - 1 )
|
|
|
+ if ( rfsh_ctr[4:0] >= t_rp+t_rfc*2+t_mrd-1+3 )
|
|
|
state <= st_idle;
|
|
|
end // case: st_init
|
|
|
st_idle:
|
|
@@ -315,42 +337,50 @@ module sdram
|
|
|
// is started opportunistically if nothing is
|
|
|
// pending and the refresh counter is no less than
|
|
|
// half expired.
|
|
|
- casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_ctr[t_refi_lg2:t_refi_lg2-1]} )
|
|
|
- 4'b1zzz:
|
|
|
+ casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_prio} )
|
|
|
+ 4'b1???:
|
|
|
begin
|
|
|
// Begin port 0 transaction
|
|
|
dram_cmd <= cmd_act;
|
|
|
dram_a <= a0[24:12];
|
|
|
dram_ba <= a0[11:10];
|
|
|
+ col_addr <= a0[11:2];
|
|
|
+ be_q <= 1'b1 << a0[1:0];
|
|
|
+ port <= 1'b0;
|
|
|
if ( wrq0 )
|
|
|
begin
|
|
|
- state <= st_p0_wr;
|
|
|
- wack0_q[t_rcd] <= 1'b1;
|
|
|
+ state <= st_wr;
|
|
|
+ wack0 <= 1'b1;
|
|
|
+ wdata_q <= {4{wd0}};
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- state <= st_p0_rd;
|
|
|
- rack0_q[t_rcd + t_cl + 1] <= 1'b1;
|
|
|
+ state <= st_rd;
|
|
|
+ rack0[t_rcd+t_cl+3] <= 1'b1;
|
|
|
end
|
|
|
end
|
|
|
- 4'b010z:
|
|
|
+ 4'b010?:
|
|
|
begin
|
|
|
// Begin port 1 transaction
|
|
|
dram_cmd <= cmd_act;
|
|
|
dram_a <= a1[24:12];
|
|
|
dram_ba <= a1[11:10];
|
|
|
+ col_addr <= a1[11:2];
|
|
|
+ be_q <= be1;
|
|
|
+ port <= 1'b1;
|
|
|
if ( wrq1 )
|
|
|
begin
|
|
|
- state <= st_p1_wr;
|
|
|
- wack1_q[t_rcd] <= 1'b1;
|
|
|
+ state <= st_wr;
|
|
|
+ wack1 <= 1'b1;
|
|
|
+ wdata_q <= wd1;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- state <= st_p1_rd;
|
|
|
- rack1_q[t_rcd + t_cl + 1] <= 1'b1;
|
|
|
+ state <= st_rd;
|
|
|
+ rack1[t_rcd+t_cl+3] <= 1'b1;
|
|
|
end
|
|
|
end
|
|
|
- 4'b0z1z, 4'b0001:
|
|
|
+ 4'b0?1?, 4'b0001:
|
|
|
begin
|
|
|
// Begin refresh transaction
|
|
|
dram_cmd <= cmd_ref;
|
|
@@ -365,115 +395,117 @@ module sdram
|
|
|
end // case: st_idle
|
|
|
st_rfsh:
|
|
|
begin
|
|
|
- if (op_cycle >= t_rfc-1)
|
|
|
+ if (op_cycle == t_rfc-2)
|
|
|
state <= st_idle;
|
|
|
end
|
|
|
- st_p0_rd:
|
|
|
+ st_rd:
|
|
|
begin
|
|
|
dram_d_en <= 1'b0; // Tristate our output
|
|
|
- dram_a[8:0] <= a0[9:1];
|
|
|
- dram_ba <= a0[11:10];
|
|
|
- dram_a[10] <= 1'b0; // No auto precharge
|
|
|
dram_dqm <= 2'b00;
|
|
|
|
|
|
- if ( op_cycle == t_rcd )
|
|
|
- dram_cmd <= cmd_rd;
|
|
|
-
|
|
|
- if ( op_cycle == t_pre_rd_when )
|
|
|
- dram_cmd <= cmd_pre; // Precharge and stop burst
|
|
|
-
|
|
|
- // Latch and ack input data. There is an implicit
|
|
|
- // due to bus turnaround.
|
|
|
- for (int i = 0; i <= t_rcd + t_cl; i++)
|
|
|
- begin
|
|
|
- rack0_q[i] <= (op_cycle == t_rcd + t_cl + 1 - i);
|
|
|
+ // Commands
|
|
|
+ //
|
|
|
+ // This assumes:
|
|
|
+ // tRCD = 3
|
|
|
+ // rRRD = 2
|
|
|
+ // CL = 3
|
|
|
+ // tRC = 10
|
|
|
+ case (op_cycle)
|
|
|
+ 1: begin
|
|
|
+ dram_a <= next_bank[14:2];
|
|
|
+ dram_ba <= next_bank[1:0];
|
|
|
+ dram_cmd <= last_dword ? cmd_act : cmd_nop;
|
|
|
end
|
|
|
-
|
|
|
- if ( op_cycle == t_rcd + t_cl + 1 )
|
|
|
- begin
|
|
|
- dram_q <= sr_dq;
|
|
|
- rack0_q <= 1'b1;
|
|
|
+ 2, 4: begin
|
|
|
+ dram_a[12:9] <= 4'b0000;
|
|
|
+ dram_a[8:1] <= col_addr[9:2];
|
|
|
+ dram_a[0] <= 1'b0;
|
|
|
+ dram_cmd <= cmd_rd;
|
|
|
+ col_addr <= col_addr + 1'b1;
|
|
|
end
|
|
|
-
|
|
|
- if ( op_cycle >= max(t_rc, t_pre_rd_when + t_rp) - 1 )
|
|
|
- state <= st_idle;
|
|
|
- end // case: st_p0_rd
|
|
|
- st_p0_wr:
|
|
|
- begin
|
|
|
- dram_a[8:0] <= a0[9:1];
|
|
|
- dram_ba <= a0[11:10];
|
|
|
- dram_a[10] <= 1'b0; // No auto precharge
|
|
|
- dram_d <= { wd0, wd0 };
|
|
|
-
|
|
|
- // Ack data
|
|
|
- for (int i = 0; i <= t_rcd; i++)
|
|
|
- begin
|
|
|
- wack0_q[i] <= (op_cycle == t_rcd - i);
|
|
|
+ 8: begin
|
|
|
+ // Precharge all banks
|
|
|
+ dram_a[12:9] <= 4'b0010;
|
|
|
+ dram_cmd <= cmd_pre;
|
|
|
end
|
|
|
-
|
|
|
- if ( op_cycle == t_rcd )
|
|
|
- begin
|
|
|
- dram_cmd <= cmd_wr;
|
|
|
- dram_dqm <= { ~a0[0], a0[0] };
|
|
|
+ 10: begin
|
|
|
+ state <= st_idle;
|
|
|
end
|
|
|
+ endcase // case (op_cycle)
|
|
|
|
|
|
- if ( op_cycle == t_pre_wr_when )
|
|
|
+ // +2 for bus turnaround latencies
|
|
|
+ if (op_cycle >= 2+t_cl+2)
|
|
|
begin
|
|
|
- dram_cmd <= cmd_pre;
|
|
|
- end
|
|
|
-
|
|
|
- if ( op_cycle >= max(t_rc, t_pre_wr_when + t_rp) - 1 )
|
|
|
- state <= st_idle;
|
|
|
- end // case: st_p0_wr
|
|
|
- st_p1_rd:
|
|
|
+ if (port == 1'b0)
|
|
|
+ begin
|
|
|
+ if (be_q[0])
|
|
|
+ rd0 <= dram_q[7:0];
|
|
|
+ if (be_q[1])
|
|
|
+ rd0 <= dram_q[15:8];
|
|
|
+ end
|
|
|
+ else if (op_cycle[0] ^ ((2+t_cl+2) & 1'b1))
|
|
|
+ begin
|
|
|
+ // Odd word
|
|
|
+ if (be_q[0])
|
|
|
+ rd1[23:16] <= dram_q[ 7:0];
|
|
|
+ if (be_q[1])
|
|
|
+ rd1[31:24] <= dram_q[15:8];
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ // Even word
|
|
|
+ if (be_q[0])
|
|
|
+ rd1[ 7:0] <= dram_q[ 7:0];
|
|
|
+ if (be_q[1])
|
|
|
+ rd1[15:8] <= dram_q[15:8];
|
|
|
+ end // else: !if(op_cycle[0] ^ ((t_rcd-1+t_cl+2) & 1'b1))
|
|
|
+ be_q >>= 2;
|
|
|
+ end // if (op_cycle >= 2+t_cl+2)
|
|
|
+ end // case: st_rd
|
|
|
+
|
|
|
+ st_wr:
|
|
|
begin
|
|
|
- dram_d_en <= 1'b0; // Tristate our output
|
|
|
- dram_a[8:0] <= a1[9:1];
|
|
|
- dram_ba <= a1[11:10];
|
|
|
- dram_a[10] <= 1'b1; // Auto precharge
|
|
|
- dram_dqm <= 2'b00;
|
|
|
-
|
|
|
- if ( op_cycle == t_rcd )
|
|
|
- dram_cmd <= cmd_rd;
|
|
|
-
|
|
|
- // Latch and ack input data. There is an implicit +1
|
|
|
- // due to bus turnaround.
|
|
|
- for (int i = 0; i <= t_rcd + t_cl + 1; i++)
|
|
|
- begin
|
|
|
- rack1_q[i] <= (op_cycle > t_rcd + t_cl - i &&
|
|
|
- op_cycle <= t_rcd + t_cl + burst_n - i);
|
|
|
+ // Commands
|
|
|
+ //
|
|
|
+ // This assumes:
|
|
|
+ // tRCD = 3
|
|
|
+ // tRRD = 2
|
|
|
+ // CL = 3
|
|
|
+ // tRC = 10
|
|
|
+ // tWR = 2
|
|
|
+ // tRP = 3
|
|
|
+ case (op_cycle)
|
|
|
+ 1: begin
|
|
|
+ dram_a <= next_bank[14:2];
|
|
|
+ dram_ba <= next_bank[1:0];
|
|
|
+ dram_cmd <= last_dword ? cmd_act : cmd_nop;
|
|
|
end
|
|
|
-
|
|
|
- if ( op_cycle > t_rcd + t_cl &&
|
|
|
- op_cycle <= t_rcd + t_cl + burst_n )
|
|
|
- begin
|
|
|
- dram_q <= sr_dq;
|
|
|
+ 2, 4: begin
|
|
|
+ dram_a[12:9] <= 4'b0000;
|
|
|
+ dram_a[8:1] <= col_addr[9:2];
|
|
|
+ dram_a[0] <= 1'b0;
|
|
|
+ dram_cmd <= cmd_wr;
|
|
|
+ col_addr <= col_addr + 1'b1;
|
|
|
+ end
|
|
|
+ 7: begin
|
|
|
+ // Precharge all banks
|
|
|
+ dram_a[12:9] <= 4'b0010;
|
|
|
+ dram_cmd <= cmd_pre;
|
|
|
+ end
|
|
|
+ 10: begin
|
|
|
+ state <= st_idle;
|
|
|
end
|
|
|
+ endcase // case (op_cycle)
|
|
|
|
|
|
- if ( op_cycle >= max(t_rc - 1, t_rcd + t_cl + burst_n) )
|
|
|
- state <= st_idle;
|
|
|
- end // case: st_p1_rd
|
|
|
- st_p1_wr:
|
|
|
- begin
|
|
|
- dram_a[8:0] <= a1[9:1];
|
|
|
- dram_ba <= a1[11:10];
|
|
|
- dram_a[10] <= 1'b1; // Auto precharge
|
|
|
- dram_dqm <= ~wbe1;
|
|
|
- dram_d <= wd1;
|
|
|
-
|
|
|
- // Ack data
|
|
|
- for (int i = 0; i <= t_rcd; i++)
|
|
|
+ if (op_cycle >= 2)
|
|
|
begin
|
|
|
- wack1_q[i] <= (op_cycle >= t_rcd - i &&
|
|
|
- op_cycle < t_rcd + burst_n);
|
|
|
+ dram_d <= wdata_q[15:0];
|
|
|
+ // Flip data between odd and even words
|
|
|
+ wdata_q <= { wdata_q[15:0], wdata_q[31:16] };
|
|
|
+ dram_dqm <= ~be_q[1:0];
|
|
|
+ be_q >>= 2;
|
|
|
end
|
|
|
-
|
|
|
- if ( op_cycle == t_rcd )
|
|
|
- dram_cmd <= cmd_wr;
|
|
|
-
|
|
|
- if ( op_cycle >= max(t_rcd + burst_n + t_wr + t_rp, t_rc) - 1 )
|
|
|
- state <= st_idle;
|
|
|
- end // case: st_p1_wr
|
|
|
+ end // case: st_wr
|
|
|
endcase // case(state)
|
|
|
end // else: !if(~rst_n)
|
|
|
endmodule // dram
|