Rev 896 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
668 | lvd | 1 | // ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014 |
4 | lvd | 2 | // |
3 | // DRAM controller. performs accesses to DRAM. |
||
668 | lvd | 4 | |
5 | /* |
||
6 | This file is part of ZX-Evo Base Configuration firmware. |
||
7 | |||
8 | ZX-Evo Base Configuration firmware is free software: |
||
9 | you can redistribute it and/or modify it under the terms of |
||
10 | the GNU General Public License as published by |
||
11 | the Free Software Foundation, either version 3 of the License, or |
||
12 | (at your option) any later version. |
||
13 | |||
14 | ZX-Evo Base Configuration firmware is distributed in the hope that |
||
15 | it will be useful, but WITHOUT ANY WARRANTY; without even |
||
16 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
17 | See the GNU General Public License for more details. |
||
18 | |||
19 | You should have received a copy of the GNU General Public License |
||
20 | along with ZX-Evo Base Configuration firmware. |
||
21 | If not, see <http://www.gnu.org/licenses/>. |
||
22 | */ |
||
23 | |||
24 | |||
4 | lvd | 25 | // |
668 | lvd | 26 | // |
4 | lvd | 27 | // state: | RD1 | RD2 | RD3 | RD4 | WR1 | WR2 | WR3 | WR4 | RFSH1 | RFSH2 | RFSH3 | RFSH4 | |
28 | // clk: ___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\__ |
||
29 | // | READ CYCLE | WRITE CYCLE | REFRESH CYCLE | |
||
30 | // ras: ```````````````````\_______________/```````````````\_______________/```````````````````````\_______________/ |
||
31 | // cas: ```````````````````````````\_______________/```````````````\_______________/```````\_______________/```````` |
||
32 | // ra: | row | column| | row | column| |
||
33 | // rd: XXXXXXXXXXXXXXXXXXXXXXXXX<read data read| write data write data write | |
||
34 | // rwe: `````````````````````````````````````````\_______________________________/```````````````````````````````` |
||
35 | // req: __/```````\_______________________/```````\________________________________________________________________ |
||
36 | // rnw: XX/```````\XXXXXXXXXXXXXXXXXXXXXXX\_______/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
||
37 | // cbeg: __________/```````\_______________________/```````\_______________________/```````\_______________________/ |
||
38 | // rrdy: __________________________________/```````\________________________________________________________________ |
||
39 | // addr: XX< addr >XXXXXXXXXXXXXXXXXXXXXXX< addr >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
||
40 | //wrdata:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX< write >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
||
41 | //rddata:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX< read >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
||
42 | // |
||
43 | // comments: |
||
44 | // rucas_n, rlcas_n, rras0_n, rras1_n, rwe_n could be made 'fast output register' |
||
45 | // ra[] couldn't be such in acex1k, because output registers could be all driven only by |
||
46 | // single clock polarity (and here they are driven by negative edge, while CAS/RAS by positive) |
||
47 | // |
||
48 | // rst_n is resynced before use and acts as req inhibit. so while in reset, dram regenerates and isn't corrupted |
||
49 | |||
668 | lvd | 50 | `include "../include/tune.v" |
51 | |||
4 | lvd | 52 | module dram( |
53 | |||
54 | input clk, |
||
55 | input rst_n, // shut down accesses, remain refresh |
||
56 | |||
57 | output reg [9:0] ra, // to the DRAM pins |
||
58 | inout [15:0] rd, // . . |
||
59 | // . . |
||
60 | output reg rwe_n, // . . |
||
61 | output reg rucas_n, // . . |
||
62 | output reg rlcas_n, // . . |
||
63 | output reg rras0_n, // . . |
||
64 | output reg rras1_n, // to the DRAM pins |
||
65 | |||
66 | input [20:0] addr, // access address of 16bit word: addr[0] selects between rras0_n and rras1_n, |
||
67 | // addr[10:1] goes to row address, addr[20:11] goes to column address |
||
68 | |||
69 | input req, // request for read/write cycle |
||
70 | input rnw, // READ/nWRITE (=1: read, =0: write) |
||
71 | |||
72 | output reg cbeg, // cycle begin (any including refresh), can be used for synchronizing |
||
73 | output reg rrdy, // Read data ReaDY |
||
74 | |||
75 | output reg [15:0] rddata, // data just read |
||
76 | |||
77 | input [15:0] wrdata, // data to be written |
||
78 | input [1:0] bsel // positive byte select for write: bsel[0] is for wrdata[7:0], bsel[1] is for wrdata[15:8] |
||
79 | |||
80 | |||
81 | ); |
||
82 | |||
83 | reg [1:0] rst_sync; |
||
84 | wire reset; |
||
85 | wire int_req; |
||
86 | |||
87 | reg [20:0] int_addr; |
||
88 | reg [15:0] int_wrdata; |
||
89 | reg [1:0] int_bsel; |
||
90 | |||
91 | |||
92 | reg rfsh_alt; // we must alternate chips in refresh cycles to lower total heating |
||
93 | |||
94 | |||
95 | |||
96 | reg [3:0] state; |
||
97 | reg [3:0] next_state; |
||
98 | |||
99 | localparam RD1 = 0; |
||
100 | localparam RD2 = 1; |
||
101 | localparam RD3 = 2; |
||
102 | localparam RD4 = 3; |
||
103 | localparam WR1 = 4; |
||
104 | localparam WR2 = 5; |
||
105 | localparam WR3 = 6; |
||
106 | localparam WR4 = 7; |
||
107 | localparam RFSH1 = 8; |
||
108 | localparam RFSH2 = 9; |
||
109 | localparam RFSH3 = 10; |
||
110 | localparam RFSH4 = 11; |
||
111 | |||
112 | |||
113 | |||
114 | initial |
||
115 | begin |
||
116 | state = RFSH1; // for simulation only! |
||
117 | rfsh_alt = 1'b0; |
||
118 | end |
||
119 | |||
425 | lvd | 120 | /* |
200 | lvd | 121 | `ifdef SIMULATE |
4 | lvd | 122 | always @(posedge clk) |
123 | begin |
||
200 | lvd | 124 | if( req && !rnw && (state==RD4 || state==WR4 || state==RFSH4) ) |
125 | begin |
||
126 | $display("written word %x mask %x to address %x",wrdata&{ {8{bsel[1]}}, {8{bsel[0]}} },{ {8{bsel[1]}}, {8{bsel[0]}} },addr); |
||
127 | end |
||
128 | end |
||
129 | `endif |
||
425 | lvd | 130 | */ |
200 | lvd | 131 | |
132 | always @(posedge clk) |
||
133 | begin |
||
4 | lvd | 134 | state <= next_state; |
135 | end |
||
136 | |||
137 | always @* |
||
138 | case( state ) |
||
139 | |||
140 | RD1: |
||
141 | next_state = RD2; |
||
142 | RD2: |
||
143 | next_state = RD3; |
||
144 | RD3: |
||
145 | next_state = RD4; |
||
146 | RD4: |
||
147 | if( !int_req ) |
||
148 | next_state = RFSH1; |
||
149 | else |
||
150 | next_state = rnw?RD1:WR1; |
||
151 | |||
152 | WR1: |
||
153 | next_state = WR2; |
||
154 | WR2: |
||
155 | next_state = WR3; |
||
156 | WR3: |
||
157 | next_state = WR4; |
||
158 | WR4: |
||
159 | if( !int_req ) |
||
160 | next_state = RFSH1; |
||
161 | else |
||
162 | next_state = rnw?RD1:WR1; |
||
163 | |||
164 | |||
165 | RFSH1: |
||
166 | next_state = RFSH2; |
||
167 | RFSH2: |
||
168 | next_state = RFSH3; |
||
169 | RFSH3: |
||
170 | next_state = RFSH4; |
||
171 | RFSH4: |
||
172 | if( !int_req ) |
||
173 | next_state = RFSH1; |
||
174 | else |
||
175 | next_state = rnw?RD1:WR1; |
||
176 | |||
177 | endcase |
||
178 | |||
179 | |||
180 | // incoming data latching |
||
181 | always @(posedge clk) |
||
182 | begin |
||
183 | if( (state==RD4) || (state==WR4) || (state==RFSH4) ) |
||
184 | begin |
||
185 | int_addr <= addr; |
||
186 | int_wrdata <= wrdata; |
||
187 | int_bsel <= bsel; |
||
188 | end |
||
189 | end |
||
190 | |||
191 | // WE control |
||
192 | always @(posedge clk) |
||
193 | begin |
||
194 | if( (next_state==WR1) || (next_state==WR2) || (next_state==WR3) || (next_state==WR4) ) |
||
195 | rwe_n <= 1'b0; |
||
196 | else |
||
197 | rwe_n <= 1'b1; |
||
198 | end |
||
199 | |||
200 | |||
201 | // RAS/CAS sequencing |
||
202 | always @(posedge clk) |
||
203 | begin |
||
204 | case( state ) |
||
205 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
206 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
207 | RD1: |
||
208 | begin |
||
209 | rras0_n <= int_addr[0]; |
||
210 | rras1_n <= ~int_addr[0]; |
||
211 | end |
||
212 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
213 | RD2: |
||
214 | begin |
||
215 | rucas_n <= 1'b0; |
||
216 | rlcas_n <= 1'b0; |
||
217 | end |
||
218 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
219 | RD3: |
||
220 | begin |
||
221 | rras0_n <= 1'b1; |
||
222 | rras1_n <= 1'b1; |
||
223 | end |
||
224 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
225 | RD4: |
||
226 | begin |
||
227 | rras0_n <= 1'b1; |
||
228 | rras1_n <= 1'b1; |
||
229 | rucas_n <= 1'b1; |
||
230 | rlcas_n <= 1'b1; |
||
231 | end |
||
232 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
233 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
234 | WR1: |
||
235 | begin |
||
236 | rras0_n <= int_addr[0]; |
||
237 | rras1_n <= ~int_addr[0]; |
||
238 | end |
||
239 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
240 | WR2: |
||
241 | begin |
||
242 | rucas_n <= ~int_bsel[1]; |
||
243 | rlcas_n <= ~int_bsel[0]; |
||
244 | end |
||
245 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
246 | WR3: |
||
247 | begin |
||
248 | rras0_n <= 1'b1; |
||
249 | rras1_n <= 1'b1; |
||
250 | end |
||
251 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
252 | WR4: |
||
253 | begin |
||
254 | rras0_n <= 1'b1; |
||
255 | rras1_n <= 1'b1; |
||
256 | rucas_n <= 1'b1; |
||
257 | rlcas_n <= 1'b1; |
||
258 | end |
||
259 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
260 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
261 | RFSH1: |
||
262 | begin |
||
263 | rucas_n <= 1'b0; |
||
264 | rlcas_n <= 1'b0; |
||
265 | end |
||
266 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
267 | RFSH2: |
||
268 | begin |
||
269 | rras0_n <= rfsh_alt; |
||
270 | rras1_n <= ~rfsh_alt; |
||
271 | |||
272 | rfsh_alt <= ~rfsh_alt; |
||
273 | end |
||
274 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
275 | RFSH3: |
||
276 | begin |
||
277 | rucas_n <= 1'b1; |
||
278 | rlcas_n <= 1'b1; |
||
279 | end |
||
280 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
281 | RFSH4: |
||
282 | begin |
||
283 | rras0_n <= 1'b1; |
||
284 | rras1_n <= 1'b1; |
||
285 | rucas_n <= 1'b1; |
||
286 | rlcas_n <= 1'b1; |
||
287 | end |
||
288 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
289 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
290 | endcase |
||
291 | end |
||
292 | |||
293 | |||
294 | // row/column address multiplexing |
||
295 | always @(negedge clk) |
||
296 | begin |
||
297 | if( (state==RD1) || (state==WR1) ) |
||
298 | ra <= int_addr[10:1]; |
||
299 | else |
||
300 | ra <= int_addr[20:11]; |
||
301 | end |
||
302 | |||
303 | |||
304 | // DRAM data bus control |
||
305 | assign rd = rwe_n ? 16'hZZZZ : int_wrdata; |
||
306 | |||
307 | |||
308 | // read data from DRAM |
||
309 | always @(posedge clk) |
||
310 | begin |
||
311 | if( state==RD3 ) |
||
312 | rddata <= rd; |
||
313 | end |
||
314 | |||
315 | |||
316 | // cbeg and rrdy control |
||
317 | always @(posedge clk) |
||
318 | begin |
||
319 | if( (state==RD4) || (state==WR4) || (state==RFSH4) ) |
||
320 | cbeg <= 1'b1; |
||
321 | else |
||
322 | cbeg <= 1'b0; |
||
323 | |||
324 | |||
325 | if( state==RD3 ) |
||
326 | rrdy <= 1'b1; |
||
327 | else |
||
328 | rrdy <= 1'b0; |
||
329 | end |
||
330 | |||
331 | |||
332 | // reset must be synchronous here in order to preserve |
||
333 | // DRAM state while other modules reset, but we have only |
||
334 | // asynchronous one globally. so we must re-synchronize it |
||
335 | // and use it as 'DRAM operation enable'. when in reset, |
||
336 | // controller ignores req signal and generates only refresh cycles |
||
337 | always @(posedge clk) |
||
338 | rst_sync[1:0] <= { rst_sync[0], ~rst_n }; |
||
339 | |||
340 | assign reset = rst_sync[1]; |
||
341 | |||
342 | assign int_req = req & (~reset); |
||
343 | |||
344 | endmodule |