1 |
2 |
ndumitrach |
`timescale 1ns / 100ps
|
2 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
3 |
|
|
//
|
4 |
|
|
// This file is part of the Next186 Soc PC project
|
5 |
|
|
// http://opencores.org/project,next186
|
6 |
|
|
//
|
7 |
|
|
// Filename: sdram.v
|
8 |
|
|
// Description: Part of the Next186 SoC PC project, SDRAM controller
|
9 |
|
|
// Version 1.0
|
10 |
|
|
// Creation date: Feb2014
|
11 |
|
|
//
|
12 |
|
|
// Author: Nicolae Dumitrache
|
13 |
|
|
// e-mail: ndumitrache@opencores.org
|
14 |
|
|
//
|
15 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
16 |
|
|
//
|
17 |
|
|
// Copyright (C) 2014 Nicolae Dumitrache
|
18 |
|
|
//
|
19 |
|
|
// This source file may be used and distributed without
|
20 |
|
|
// restriction provided that this copyright statement is not
|
21 |
|
|
// removed from the file and that any derivative work contains
|
22 |
|
|
// the original copyright notice and the associated disclaimer.
|
23 |
|
|
//
|
24 |
|
|
// This source file is free software; you can redistribute it
|
25 |
|
|
// and/or modify it under the terms of the GNU Lesser General
|
26 |
|
|
// Public License as published by the Free Software Foundation;
|
27 |
|
|
// either version 2.1 of the License, or (at your option) any
|
28 |
|
|
// later version.
|
29 |
|
|
//
|
30 |
|
|
// This source is distributed in the hope that it will be
|
31 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
32 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
33 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more
|
34 |
|
|
// details.
|
35 |
|
|
//
|
36 |
|
|
// You should have received a copy of the GNU Lesser General
|
37 |
|
|
// Public License along with this source; if not, download it
|
38 |
|
|
// from http://www.opencores.org/lgpl.shtml
|
39 |
|
|
//
|
40 |
|
|
///////////////////////////////////////////////////////////////////////////////////
|
41 |
|
|
// Additional Comments:
|
42 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
43 |
|
|
|
44 |
|
|
`define RD1 8'h10 // 32 bytes - cmd 10
|
45 |
|
|
`define RD2 8'h80 // 256 bytes - cmd 11
|
46 |
|
|
`define WR2 8'h80 // 256 bytes - cmd 01
|
47 |
|
|
`define PitchBits 1
|
48 |
|
|
|
49 |
|
|
`define ColBits 8 // column bits
|
50 |
|
|
`define RowBits 12 // row bits
|
51 |
|
|
`define BankBits 2 // bank bits
|
52 |
|
|
|
53 |
|
|
`define tRP 3
|
54 |
|
|
`define tMRD 2
|
55 |
|
|
`define tRCD 3
|
56 |
|
|
`define tRC 9
|
57 |
|
|
`define CL 3 // CAS latency
|
58 |
|
|
`define tREF 64 // ms
|
59 |
|
|
|
60 |
|
|
`define RFB 11 // refresh bit = floor(log2(CLK*`tREF/(2^RowBits)))
|
61 |
|
|
|
62 |
|
|
|
63 |
|
|
module SDRAM_16bit(
|
64 |
|
|
input sys_CLK, // clock
|
65 |
|
|
input [1:0]sys_CMD, // 00=nop, 01 = write WR2 bytes, 10=read RD1 bytes, 11=read RD2 bytes
|
66 |
|
|
input [`RowBits+`BankBits+`ColBits-`PitchBits-1:0]sys_ADDR, // word address, multiple of 2^PitchBits words
|
67 |
|
|
input [15:0]sys_DIN, // data input
|
68 |
|
|
output reg [15:0]sys_DOUT,
|
69 |
|
|
output reg sys_rd_data_valid = 0, // data valid out
|
70 |
|
|
output reg sys_wr_data_valid = 0, // data valid in
|
71 |
|
|
output reg [1:0]sys_cmd_ack = 0, // command acknowledged
|
72 |
|
|
|
73 |
|
|
output reg [3:0]sdr_n_CS_WE_RAS_CAS = 4'b1111, // SDRAM #CS, #WE, #RAS, #CAS
|
74 |
|
|
output reg [1:0]sdr_BA, // SDRAM bank address
|
75 |
|
|
output reg [12:0]sdr_ADDR, // SDRAM address
|
76 |
|
|
inout [15:0]sdr_DATA, // SDRAM data
|
77 |
|
|
output reg [1:0]sdr_DQM = 2'b11 // SDRAM DQM
|
78 |
|
|
);
|
79 |
|
|
|
80 |
|
|
reg [`RowBits-1:0]actLine[3:0];
|
81 |
|
|
reg [(1<<`BankBits)-1:0]actBank = 0;
|
82 |
|
|
reg [2:0]STATE = 0;
|
83 |
|
|
reg [2:0]RET; // return state
|
84 |
|
|
reg [6:0]DLY; // delay
|
85 |
|
|
reg [15:0]counter = 0; // refresh counter
|
86 |
|
|
reg rfsh = 1; // refresh bit
|
87 |
|
|
reg [`ColBits-`PitchBits-1:0]colAddr;
|
88 |
|
|
reg [`BankBits-1:0]bAddr;
|
89 |
|
|
reg [`RowBits-1:0]linAddr;
|
90 |
|
|
reg [15:0]reg_din;
|
91 |
|
|
reg [2:0]out_data_valid = 0;
|
92 |
|
|
|
93 |
|
|
assign sdr_DATA = out_data_valid[2] ? reg_din : 16'hzzzz;
|
94 |
|
|
|
95 |
|
|
always @(posedge sys_CLK) begin
|
96 |
|
|
counter <= counter + 1;
|
97 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b1xxx; // NOP
|
98 |
|
|
STATE <= 1;
|
99 |
|
|
reg_din <= sys_DIN;
|
100 |
|
|
out_data_valid <= {out_data_valid[1:0], sys_wr_data_valid};
|
101 |
|
|
DLY <= DLY - 1;
|
102 |
|
|
sys_DOUT <= sdr_DATA;
|
103 |
|
|
|
104 |
|
|
case(STATE)
|
105 |
|
|
0: begin
|
106 |
|
|
sys_rd_data_valid <= 1'b0;
|
107 |
|
|
if(sdr_DQM[0]) STATE <= counter[15] ? 2 : 0; // initialization, wait >200uS
|
108 |
|
|
else begin // wait new command
|
109 |
|
|
if(rfsh != counter[`RFB]) begin
|
110 |
|
|
rfsh <= counter[`RFB];
|
111 |
|
|
STATE <= 2; // precharge all
|
112 |
|
|
end else if(|sys_CMD) begin
|
113 |
|
|
sys_cmd_ack <= sys_CMD;
|
114 |
|
|
{linAddr, bAddr, colAddr} <= sys_ADDR;
|
115 |
|
|
STATE <= 5;
|
116 |
|
|
end else STATE <= 0;
|
117 |
|
|
end
|
118 |
|
|
end
|
119 |
|
|
|
120 |
|
|
1: begin
|
121 |
|
|
if(DLY == 2) sys_wr_data_valid <= 1'b0;
|
122 |
|
|
if(DLY == 0) STATE <= RET; // NOP for DLY clocks, return to RET state
|
123 |
|
|
end
|
124 |
|
|
|
125 |
|
|
2: begin // precharge all
|
126 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0001;
|
127 |
|
|
sdr_ADDR[10] <= 1'b1;
|
128 |
|
|
RET <= sdr_DQM[0] ? 3 : 4;
|
129 |
|
|
DLY <= `tRP - 2;
|
130 |
|
|
actBank <= 0;
|
131 |
|
|
end
|
132 |
|
|
|
133 |
|
|
3: begin // Mode Register Set
|
134 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0000;
|
135 |
|
|
sdr_ADDR <= 13'b00_0_0_00_000_0_111 + (`CL<<4); // burst read/burst write _ normal mode _ `CL CAS latency _ sequential _ full page burst
|
136 |
|
|
sdr_BA <= 2'b00;
|
137 |
|
|
RET <= 4;
|
138 |
|
|
DLY <= `tMRD - 2;
|
139 |
|
|
end
|
140 |
|
|
|
141 |
|
|
4: begin // autorefresh
|
142 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0100;
|
143 |
|
|
if(rfsh != counter[`RFB]) RET <= 4;
|
144 |
|
|
else begin
|
145 |
|
|
sdr_DQM <= 2'b00;
|
146 |
|
|
RET <= 0;
|
147 |
|
|
end
|
148 |
|
|
DLY <= `tRC - 2;
|
149 |
|
|
end
|
150 |
|
|
|
151 |
|
|
5: begin // read/write
|
152 |
|
|
sdr_BA <= bAddr;
|
153 |
|
|
if(actBank[bAddr]) // bank active
|
154 |
|
|
if(actLine[bAddr] == linAddr) begin // line already active
|
155 |
|
|
sdr_ADDR[10] <= 1'b0; // no auto precharge
|
156 |
|
|
sdr_ADDR[`ColBits-1:0] <= {colAddr, {`PitchBits{1'b0}}};
|
157 |
|
|
RET <= 7;
|
158 |
|
|
if(sys_cmd_ack[1]) begin // read
|
159 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0110; // read command
|
160 |
|
|
DLY <= `CL - 1;
|
161 |
|
|
end else begin // write
|
162 |
|
|
DLY <= 1;
|
163 |
|
|
sys_wr_data_valid <= 1'b1;
|
164 |
|
|
end
|
165 |
|
|
end else begin // bank precharge
|
166 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0001;
|
167 |
|
|
sdr_ADDR[10] <= 1'b0;
|
168 |
|
|
actBank[bAddr] <= 1'b0;
|
169 |
|
|
RET <= 5;
|
170 |
|
|
DLY <= `tRP - 2;
|
171 |
|
|
end
|
172 |
|
|
else begin // bank activate
|
173 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0101;
|
174 |
|
|
sdr_ADDR[`RowBits-1:0] <= linAddr;
|
175 |
|
|
actBank[bAddr] <= 1'b1;
|
176 |
|
|
actLine[bAddr] <= linAddr;
|
177 |
|
|
RET <= 5;
|
178 |
|
|
DLY <= `tRCD - 2;
|
179 |
|
|
end
|
180 |
|
|
end
|
181 |
|
|
|
182 |
|
|
6: begin // end read/write phase
|
183 |
|
|
sys_cmd_ack <= 2'b00;
|
184 |
|
|
sdr_n_CS_WE_RAS_CAS <= 4'b0011; // burst stop
|
185 |
|
|
STATE <= sys_cmd_ack[1] ? 1 : 0; // read write
|
186 |
|
|
RET <= 0;
|
187 |
|
|
DLY <= 2;
|
188 |
|
|
end
|
189 |
|
|
|
190 |
|
|
7: begin // init read/write phase
|
191 |
|
|
if(sys_cmd_ack[1]) sys_rd_data_valid <= 1'b1;
|
192 |
|
|
else sdr_n_CS_WE_RAS_CAS <= 4'b0010; // write command
|
193 |
|
|
RET <= 6;
|
194 |
|
|
DLY <= sys_cmd_ack[1] ? sys_cmd_ack[0] ? `RD2 - 6 : `RD1 - 6 : `WR2 - 2;
|
195 |
|
|
end
|
196 |
|
|
|
197 |
|
|
endcase
|
198 |
|
|
end
|
199 |
|
|
|
200 |
|
|
endmodule
|