OpenCores
URL https://opencores.org/ocsvn/wbddr3/wbddr3/trunk

Subversion Repositories wbddr3

[/] [wbddr3/] [trunk/] [bench/] [cpp/] [ddrsdramsim.cpp] - Blame information for rev 12

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    ddrsdramsim.cpp
4
//
5
// Project:     A wishbone controlled DDR3 SDRAM memory controller.
6
//
7
// Purpose:     
8
//
9
// Creator:     Dan Gisselquist, Ph.D.
10
//              Gisselquist Technology, LLC
11
//
12
////////////////////////////////////////////////////////////////////////////////
13
//
14
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
15
//
16
// This program is free software (firmware): you can redistribute it and/or
17
// modify it under the terms of  the GNU General Public License as published
18
// by the Free Software Foundation, either version 3 of the License, or (at
19
// your option) any later version.
20
//
21
// This program is distributed in the hope that it will be useful, but WITHOUT
22
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24
// for more details.
25
//
26
// You should have received a copy of the GNU General Public License along
27
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
28
// target there if the PDF file isn't present.)  If not, see
29
// <http://www.gnu.org/licenses/> for a copy.
30
//
31
// License:     GPL, v3, as defined and found on www.gnu.org,
32
//              http://www.gnu.org/licenses/gpl.html
33
//
34
//
35
////////////////////////////////////////////////////////////////////////////////
36
//
37
//
38
#include <stdio.h>
39
#include <assert.h>
40
 
41 9 dgisselq
#define PREFIX  "DDR3-SDRAM"
42 4 dgisselq
const unsigned ckCL = 5,
43 6 dgisselq
                ckRC = 3,
44
                ckRFC = 320, // Clocks from refresh to activate
45
                nREF = 4,
46
                ckREFI = 1560, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
47
                ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
48 4 dgisselq
 
49
#include "ddrsdramsim.h"
50
void    BANKINFO::tick(int cmd, unsigned addr) {
51 12 dgisselq
        if (m_wcounter)
52
                m_wcounter--;
53 4 dgisselq
        switch(cmd) {
54
                case DDR_PRECHARGE:
55 6 dgisselq
                        m_state = 6;
56 8 dgisselq
                        // While the specification allows precharging an already
57
                        // precharged bank, we can keep that from happening
58
                        // here:
59
                        // assert(m_state&7);
60
                        // Only problem is, this will currently break our
61
                        // refresh logic.
62 4 dgisselq
                        break;
63
                case DDR_ACTIVATE:
64 12 dgisselq
                        assert(m_wcounter == 0);
65 6 dgisselq
                        m_state = 1;
66 4 dgisselq
                        m_row = addr & 0x7fff;
67
                        break;
68
                case DDR_READ: case DDR_WRITE:
69 12 dgisselq
                        if (DDR_READ)
70
                                assert(m_wcounter == 0);
71
                        else
72
                                m_wcounter = 3+4+4;
73 6 dgisselq
                        printf("BANK::R/W Request, m_state = %d\n", m_state);
74 4 dgisselq
                        assert((m_state&7) == 7);
75
                        break;
76
                case DDR_ZQS:
77
                        assert((m_state&7) == 0);
78
                        break;
79
                case DDR_NOOP:
80
                        m_state <<= 1;
81
                        m_state |= (m_state&2)>>1;
82
                        break;
83
                default:
84
                        break;
85
        }
86
}
87
 
88
int gbl_state, gbl_counts;
89
 
90
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
91
        m_memlen = (1<<(lglen-2));
92
        m_mem = new unsigned[m_memlen];
93
        m_reset_state = 0;
94
        m_reset_counts= 0;
95
        m_bus = new BUSTIMESLOT[NTIMESLOTS];
96
        for(int i=0; i<NTIMESLOTS; i++)
97
                m_bus[i].m_used = 0;
98
        m_busloc = 0;
99
}
100
 
101
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
102
                int csn, int rasn, int casn, int wen,
103
                int dqs, int dm, int odt, int busoe,
104
                int addr, int ba, int data) {
105
 
106
        int     cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
107
                        |(rasn?4:0)|(casn?2:0)|(wen?1:0);
108
        if ((m_reset_state!=0)&&(reset_n==0)) {
109
                m_reset_state = 0;
110
                m_reset_counts = 0;
111
        } else if (m_reset_state < 16) {
112
                switch(m_reset_state) {
113
                case 0:
114
                        m_reset_counts++;
115
                        if (reset_n) {
116
                                assert(m_reset_counts > 40000);
117
                                m_reset_counts = 0;
118
                                m_reset_state = 1;
119
                        } break;
120
                case 1:
121
                        m_reset_counts++;
122
                        if (cke) {
123
                                assert(m_reset_counts > 100000);
124
                                m_reset_counts = 0;
125
                                m_reset_state = 2;
126
                        } break;
127
                case 2:
128
                        m_reset_counts++;
129 6 dgisselq
                        assert(cke);
130 4 dgisselq
                        if (cmd != DDR_NOOP) {
131
                                assert(m_reset_counts > 147);
132
                                m_reset_counts = 0;
133
                                m_reset_state = 3;
134
                                assert(cmd == DDR_MRSET);
135
                                assert(ba == 2);
136
                                assert(addr == 0x040);
137
                        } break;
138
                case 3:
139
                        m_reset_counts++;
140 6 dgisselq
                        assert(cke);
141 4 dgisselq
                        if (cmd != DDR_NOOP) {
142 5 dgisselq
                                // assert(m_reset_counts > 3);
143 4 dgisselq
                                m_reset_counts = 0;
144
                                m_reset_state = 4;
145
                                assert(cmd == DDR_MRSET);
146 5 dgisselq
                                // assert(ba == 1);
147
                                // assert(addr == 0x847);
148 4 dgisselq
                        } break;
149
                case 4:
150
                        m_reset_counts++;
151 6 dgisselq
                        assert(cke);
152 4 dgisselq
                        if (cmd != DDR_NOOP) {
153 9 dgisselq
                                printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
154 4 dgisselq
                                assert(m_reset_counts > 3);
155
                                m_reset_counts = 0;
156
                                m_reset_state = 5;
157
                                assert(cmd == DDR_MRSET);
158
                                assert(ba == 0);
159
                                assert(addr == 0x210);
160
                        } break;
161
                case 5:
162
                        m_reset_counts++;
163 6 dgisselq
                        assert(cke);
164 4 dgisselq
                        if (cmd != DDR_NOOP) {
165 9 dgisselq
                                printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
166 5 dgisselq
                                assert(m_reset_counts > 11);
167 4 dgisselq
                                m_reset_counts = 0;
168
                                m_reset_state = 6;
169
                                assert(cmd == DDR_ZQS);
170 5 dgisselq
                                assert(addr == 0x400);
171 4 dgisselq
                        } break;
172
                case 6:
173
                        m_reset_counts++;
174 6 dgisselq
                        assert(cke);
175 4 dgisselq
                        if (cmd != DDR_NOOP) {
176 9 dgisselq
                                printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
177 4 dgisselq
                                assert(m_reset_counts > 512);
178
                                m_reset_counts = 0;
179
                                m_reset_state = 7;
180
                                assert(cmd == DDR_PRECHARGE);
181 5 dgisselq
                                assert(addr == 0x400);
182 4 dgisselq
                        } break;
183
                case 7:
184
                        m_reset_counts++;
185 6 dgisselq
                        assert(cke);
186 4 dgisselq
                        if (cmd != DDR_NOOP) {
187 9 dgisselq
                                printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
188 4 dgisselq
                                assert(m_reset_counts > 3);
189
                                m_reset_counts = 0;
190
                                m_reset_state = 8;
191
                                assert(cmd == DDR_REFRESH);
192 6 dgisselq
                                m_clocks_since_refresh = 0;
193 4 dgisselq
                        } break;
194
                case 8:
195
                        m_reset_counts++;
196 6 dgisselq
                        assert(cke);
197 4 dgisselq
                        assert(cmd == DDR_NOOP);
198 5 dgisselq
                        if (m_reset_counts > 140) {
199 4 dgisselq
                                m_reset_state = 16;
200 9 dgisselq
                                printf(PREFIX ": Leaving reset state\n");
201 5 dgisselq
                        }
202 4 dgisselq
                        break;
203
                default:
204
                        break;
205
                }
206
 
207
                gbl_state = m_reset_state;
208
                gbl_counts= m_reset_counts;
209 6 dgisselq
                m_nrefresh_issued = nREF;
210 7 dgisselq
                m_clocks_since_refresh++;
211 6 dgisselq
        } else if (!cke) {
212 4 dgisselq
                assert(0&&"Clock not enabled!");
213 6 dgisselq
        } else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
214
                if (DDR_REFRESH == cmd) {
215
                        m_clocks_since_refresh = 0;
216
                        if (m_nrefresh_issued >= (int)nREF)
217 7 dgisselq
                                m_nrefresh_issued = 1;
218 6 dgisselq
                        else
219
                                m_nrefresh_issued++;
220
                } else {
221
                        m_clocks_since_refresh++;
222
                        assert(DDR_NOOP == cmd);
223
                }
224
                for(int i=0; i<NBANKS; i++)
225
                        m_bank[i].tick(DDR_REFRESH,0);
226 7 dgisselq
 
227
                if (m_nrefresh_issued == nREF)
228 9 dgisselq
                        printf(PREFIX "::Refresh cycle complete\n");
229 6 dgisselq
        } else {
230
                // In operational mode!!
231
 
232
                m_clocks_since_refresh++;
233
                assert(m_clocks_since_refresh < (int)ckREFIn);
234
                switch(cmd) {
235 4 dgisselq
                case DDR_MRSET:
236
                        assert(0&&"Modes should only be set in reset startup");
237
                        for(int i=0; i<NBANKS; i++)
238
                                m_bank[i].tick(DDR_MRSET,0);
239
                        break;
240
                case DDR_REFRESH:
241
                        for(int i=0; i<NBANKS; i++)
242
                                m_bank[i].tick(DDR_REFRESH,0);
243 6 dgisselq
                        m_clocks_since_refresh = 0;
244
                        assert(0 && "Internal err: Refresh should be handled above");
245 4 dgisselq
                        break;
246
                case DDR_PRECHARGE:
247
                        if (addr & 0x40) {
248
                                // Precharge all
249
                                for(int i=0; i<NBANKS; i++)
250
                                        m_bank[i].tick(DDR_PRECHARGE,0);
251
                        } else {
252
                                m_bank[ba].tick(DDR_PRECHARGE,0);
253
                                for(int i=0; i<NBANKS; i++)
254
                                        if (ba != i)
255
                                                m_bank[i].tick(DDR_NOOP,0);
256
                        }
257
                        break;
258
                case DDR_ACTIVATE:
259 7 dgisselq
                        assert(m_clocks_since_refresh >= (int)ckRFC);
260 4 dgisselq
                        m_bank[ba].tick(DDR_ACTIVATE,addr);
261
                        for(int i=0; i<NBANKS; i++)
262
                                if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
263
                        break;
264
                case DDR_WRITE:
265
                        {
266 6 dgisselq
                                // This SIM doesn't handle out of order writes
267
                                assert((addr&7)==0);
268
                                m_bank[ba].tick(DDR_WRITE, addr);
269 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
270 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
271 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
272 8 dgisselq
                                caddr <<= 3;
273 7 dgisselq
                                caddr |= ba;
274
                                caddr <<= 10;
275
                                caddr |= addr;
276
                                caddr &= ~7;
277
                                caddr >>= 1;
278 4 dgisselq
 
279
                                BUSTIMESLOT *tp;
280 7 dgisselq
                                int     offset = m_busloc+ckCL+1;
281 4 dgisselq
 
282 7 dgisselq
                                tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
283 9 dgisselq
                                // printf("Setting bus timeslots from (now=%d)+%d=%d to now+%d+3\n", m_busloc, ckCL,(m_busloc+ckCL)&(NTIMESLOTS-1), ckCL);
284 7 dgisselq
                                tp->m_addr = caddr  ;
285 4 dgisselq
                                tp->m_used = 1;
286
                                tp->m_read = 0;
287
 
288 7 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
289
                                tp->m_addr = caddr+1;
290 4 dgisselq
                                tp->m_used = 1;
291
                                tp->m_read = 0;
292
 
293 7 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
294
                                tp->m_addr = caddr+2;
295 4 dgisselq
                                tp->m_used = 1;
296
                                tp->m_read = 0;
297
 
298 7 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
299
                                tp->m_addr = caddr+3;
300 4 dgisselq
                                tp->m_used = 1;
301
                                tp->m_read = 0;
302
                        } break;
303
                case DDR_READ:
304
                        {
305 6 dgisselq
                                // This SIM doesn't handle out of order reads
306
                                assert((addr&7)==0);
307
                                m_bank[ba].tick(DDR_READ, addr);
308 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
309 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
310 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
311 8 dgisselq
                                caddr <<= 3;
312 7 dgisselq
                                caddr |= ba;
313
                                caddr <<= 10;
314
                                caddr |= addr;
315
                                caddr &= ~7;
316
                                caddr >>= 1;
317 4 dgisselq
 
318
                                BUSTIMESLOT *tp;
319
 
320 8 dgisselq
                                int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
321
                                tp = &m_bus[(offset)&(NTIMESLOTS-1)];
322 7 dgisselq
                                tp->m_data = m_mem[caddr];
323
                                tp->m_addr = caddr;
324 4 dgisselq
                                tp->m_used = 1;
325
                                tp->m_read = 1;
326
 
327 8 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
328 7 dgisselq
                                tp->m_data = m_mem[caddr+1];
329
                                tp->m_addr = caddr+1;
330 4 dgisselq
                                tp->m_used = 1;
331
                                tp->m_read = 1;
332
 
333 8 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
334 7 dgisselq
                                tp->m_data = m_mem[caddr+2];
335
                                tp->m_addr = caddr+2;
336 4 dgisselq
                                tp->m_used = 1;
337
                                tp->m_read = 1;
338
 
339 8 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
340 7 dgisselq
                                tp->m_data = m_mem[caddr+3];
341
                                tp->m_addr = caddr+3;
342 4 dgisselq
                                tp->m_used = 1;
343
                                tp->m_read = 1;
344
                        } break;
345
                case DDR_ZQS:
346
                        assert(0&&"Sim does not support ZQS outside of startup");
347
                        break;
348
                case DDR_NOOP:
349
                        for(int i=0; i<NBANKS; i++)
350
                                m_bank[i].tick(DDR_NOOP,addr);
351
                        break;
352
                default: // We are deselecteda
353
                        for(int i=0; i<NBANKS; i++)
354
                                m_bank[i].tick(DDR_NOOP,addr);
355
                        break;
356 6 dgisselq
                }
357 4 dgisselq
        }
358
 
359
        m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
360
 
361
        BUSTIMESLOT     *ts = &m_bus[m_busloc];
362
        unsigned vl = ts->m_data;
363
        assert( ((!ts->m_used)||(busoe))
364
                || ((ts->m_used)&&(ts->m_read)));
365
 
366
        assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
367 7 dgisselq
        if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
368 9 dgisselq
                printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
369 4 dgisselq
                m_mem[ts->m_addr] = data;
370 7 dgisselq
        }
371 4 dgisselq
        ts->m_used = 0;
372
        ts->m_read = 0;
373
        ts->m_addr = -1;
374
        return (!busoe)?vl:data;
375
}
376
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.