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

Subversion Repositories wbddr3

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

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 13 dgisselq
        for(int i=0; i<NTIMESLOTS; i++)
99
                m_bus[i].m_rtt = 0;
100 4 dgisselq
        m_busloc = 0;
101
}
102
 
103
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
104
                int csn, int rasn, int casn, int wen,
105
                int dqs, int dm, int odt, int busoe,
106
                int addr, int ba, int data) {
107 13 dgisselq
        BUSTIMESLOT     *ts, *nxtts;
108 4 dgisselq
        int     cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
109
                        |(rasn?4:0)|(casn?2:0)|(wen?1:0);
110 13 dgisselq
 
111 4 dgisselq
        if ((m_reset_state!=0)&&(reset_n==0)) {
112
                m_reset_state = 0;
113
                m_reset_counts = 0;
114
        } else if (m_reset_state < 16) {
115
                switch(m_reset_state) {
116
                case 0:
117
                        m_reset_counts++;
118
                        if (reset_n) {
119
                                assert(m_reset_counts > 40000);
120
                                m_reset_counts = 0;
121
                                m_reset_state = 1;
122
                        } break;
123
                case 1:
124
                        m_reset_counts++;
125
                        if (cke) {
126
                                assert(m_reset_counts > 100000);
127
                                m_reset_counts = 0;
128
                                m_reset_state = 2;
129
                        } break;
130
                case 2:
131
                        m_reset_counts++;
132 6 dgisselq
                        assert(cke);
133 4 dgisselq
                        if (cmd != DDR_NOOP) {
134
                                assert(m_reset_counts > 147);
135
                                m_reset_counts = 0;
136
                                m_reset_state = 3;
137
                                assert(cmd == DDR_MRSET);
138
                                assert(ba == 2);
139
                                assert(addr == 0x040);
140
                        } break;
141
                case 3:
142
                        m_reset_counts++;
143 6 dgisselq
                        assert(cke);
144 4 dgisselq
                        if (cmd != DDR_NOOP) {
145 5 dgisselq
                                // assert(m_reset_counts > 3);
146 4 dgisselq
                                m_reset_counts = 0;
147
                                m_reset_state = 4;
148
                                assert(cmd == DDR_MRSET);
149 5 dgisselq
                                // assert(ba == 1);
150
                                // assert(addr == 0x847);
151 4 dgisselq
                        } break;
152
                case 4:
153
                        m_reset_counts++;
154 6 dgisselq
                        assert(cke);
155 4 dgisselq
                        if (cmd != DDR_NOOP) {
156 9 dgisselq
                                printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
157 4 dgisselq
                                assert(m_reset_counts > 3);
158
                                m_reset_counts = 0;
159
                                m_reset_state = 5;
160
                                assert(cmd == DDR_MRSET);
161
                                assert(ba == 0);
162
                                assert(addr == 0x210);
163
                        } break;
164
                case 5:
165
                        m_reset_counts++;
166 6 dgisselq
                        assert(cke);
167 4 dgisselq
                        if (cmd != DDR_NOOP) {
168 9 dgisselq
                                printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
169 5 dgisselq
                                assert(m_reset_counts > 11);
170 4 dgisselq
                                m_reset_counts = 0;
171
                                m_reset_state = 6;
172
                                assert(cmd == DDR_ZQS);
173 5 dgisselq
                                assert(addr == 0x400);
174 4 dgisselq
                        } break;
175
                case 6:
176
                        m_reset_counts++;
177 6 dgisselq
                        assert(cke);
178 4 dgisselq
                        if (cmd != DDR_NOOP) {
179 9 dgisselq
                                printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
180 4 dgisselq
                                assert(m_reset_counts > 512);
181
                                m_reset_counts = 0;
182
                                m_reset_state = 7;
183
                                assert(cmd == DDR_PRECHARGE);
184 5 dgisselq
                                assert(addr == 0x400);
185 4 dgisselq
                        } break;
186
                case 7:
187
                        m_reset_counts++;
188 6 dgisselq
                        assert(cke);
189 4 dgisselq
                        if (cmd != DDR_NOOP) {
190 9 dgisselq
                                printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
191 4 dgisselq
                                assert(m_reset_counts > 3);
192
                                m_reset_counts = 0;
193
                                m_reset_state = 8;
194
                                assert(cmd == DDR_REFRESH);
195 6 dgisselq
                                m_clocks_since_refresh = 0;
196 4 dgisselq
                        } break;
197
                case 8:
198
                        m_reset_counts++;
199 6 dgisselq
                        assert(cke);
200 4 dgisselq
                        assert(cmd == DDR_NOOP);
201 5 dgisselq
                        if (m_reset_counts > 140) {
202 4 dgisselq
                                m_reset_state = 16;
203 9 dgisselq
                                printf(PREFIX ": Leaving reset state\n");
204 5 dgisselq
                        }
205 4 dgisselq
                        break;
206
                default:
207
                        break;
208
                }
209
 
210
                gbl_state = m_reset_state;
211
                gbl_counts= m_reset_counts;
212 6 dgisselq
                m_nrefresh_issued = nREF;
213 7 dgisselq
                m_clocks_since_refresh++;
214 6 dgisselq
        } else if (!cke) {
215 4 dgisselq
                assert(0&&"Clock not enabled!");
216 6 dgisselq
        } else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
217
                if (DDR_REFRESH == cmd) {
218
                        m_clocks_since_refresh = 0;
219
                        if (m_nrefresh_issued >= (int)nREF)
220 7 dgisselq
                                m_nrefresh_issued = 1;
221 6 dgisselq
                        else
222
                                m_nrefresh_issued++;
223
                } else {
224
                        m_clocks_since_refresh++;
225
                        assert(DDR_NOOP == cmd);
226
                }
227
                for(int i=0; i<NBANKS; i++)
228
                        m_bank[i].tick(DDR_REFRESH,0);
229 7 dgisselq
 
230
                if (m_nrefresh_issued == nREF)
231 9 dgisselq
                        printf(PREFIX "::Refresh cycle complete\n");
232 6 dgisselq
        } else {
233
                // In operational mode!!
234
 
235
                m_clocks_since_refresh++;
236
                assert(m_clocks_since_refresh < (int)ckREFIn);
237
                switch(cmd) {
238 4 dgisselq
                case DDR_MRSET:
239
                        assert(0&&"Modes should only be set in reset startup");
240
                        for(int i=0; i<NBANKS; i++)
241
                                m_bank[i].tick(DDR_MRSET,0);
242
                        break;
243
                case DDR_REFRESH:
244
                        for(int i=0; i<NBANKS; i++)
245
                                m_bank[i].tick(DDR_REFRESH,0);
246 6 dgisselq
                        m_clocks_since_refresh = 0;
247
                        assert(0 && "Internal err: Refresh should be handled above");
248 4 dgisselq
                        break;
249
                case DDR_PRECHARGE:
250
                        if (addr & 0x40) {
251
                                // Precharge all
252
                                for(int i=0; i<NBANKS; i++)
253
                                        m_bank[i].tick(DDR_PRECHARGE,0);
254
                        } else {
255
                                m_bank[ba].tick(DDR_PRECHARGE,0);
256
                                for(int i=0; i<NBANKS; i++)
257
                                        if (ba != i)
258
                                                m_bank[i].tick(DDR_NOOP,0);
259
                        }
260
                        break;
261
                case DDR_ACTIVATE:
262 7 dgisselq
                        assert(m_clocks_since_refresh >= (int)ckRFC);
263 4 dgisselq
                        m_bank[ba].tick(DDR_ACTIVATE,addr);
264
                        for(int i=0; i<NBANKS; i++)
265
                                if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
266
                        break;
267
                case DDR_WRITE:
268
                        {
269 6 dgisselq
                                // This SIM doesn't handle out of order writes
270
                                assert((addr&7)==0);
271
                                m_bank[ba].tick(DDR_WRITE, addr);
272 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
273 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
274 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
275 8 dgisselq
                                caddr <<= 3;
276 7 dgisselq
                                caddr |= ba;
277
                                caddr <<= 10;
278
                                caddr |= addr;
279
                                caddr &= ~7;
280
                                caddr >>= 1;
281 4 dgisselq
 
282
                                BUSTIMESLOT *tp;
283 7 dgisselq
                                int     offset = m_busloc+ckCL+1;
284 4 dgisselq
 
285 7 dgisselq
                                tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
286 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);
287 7 dgisselq
                                tp->m_addr = caddr  ;
288 4 dgisselq
                                tp->m_used = 1;
289
                                tp->m_read = 0;
290
 
291 7 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
292
                                tp->m_addr = caddr+1;
293 4 dgisselq
                                tp->m_used = 1;
294
                                tp->m_read = 0;
295
 
296 7 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
297
                                tp->m_addr = caddr+2;
298 4 dgisselq
                                tp->m_used = 1;
299
                                tp->m_read = 0;
300
 
301 7 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
302
                                tp->m_addr = caddr+3;
303 4 dgisselq
                                tp->m_used = 1;
304
                                tp->m_read = 0;
305
                        } break;
306
                case DDR_READ:
307
                        {
308 6 dgisselq
                                // This SIM doesn't handle out of order reads
309
                                assert((addr&7)==0);
310
                                m_bank[ba].tick(DDR_READ, addr);
311 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
312 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
313 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
314 8 dgisselq
                                caddr <<= 3;
315 7 dgisselq
                                caddr |= ba;
316
                                caddr <<= 10;
317
                                caddr |= addr;
318
                                caddr &= ~7;
319
                                caddr >>= 1;
320 4 dgisselq
 
321
                                BUSTIMESLOT *tp;
322
 
323 8 dgisselq
                                int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
324
                                tp = &m_bus[(offset)&(NTIMESLOTS-1)];
325 7 dgisselq
                                tp->m_data = m_mem[caddr];
326
                                tp->m_addr = caddr;
327 4 dgisselq
                                tp->m_used = 1;
328
                                tp->m_read = 1;
329
 
330 8 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
331 7 dgisselq
                                tp->m_data = m_mem[caddr+1];
332
                                tp->m_addr = caddr+1;
333 4 dgisselq
                                tp->m_used = 1;
334
                                tp->m_read = 1;
335
 
336 8 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
337 7 dgisselq
                                tp->m_data = m_mem[caddr+2];
338
                                tp->m_addr = caddr+2;
339 4 dgisselq
                                tp->m_used = 1;
340
                                tp->m_read = 1;
341
 
342 8 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
343 7 dgisselq
                                tp->m_data = m_mem[caddr+3];
344
                                tp->m_addr = caddr+3;
345 4 dgisselq
                                tp->m_used = 1;
346
                                tp->m_read = 1;
347
                        } break;
348
                case DDR_ZQS:
349
                        assert(0&&"Sim does not support ZQS outside of startup");
350
                        break;
351
                case DDR_NOOP:
352
                        for(int i=0; i<NBANKS; i++)
353
                                m_bank[i].tick(DDR_NOOP,addr);
354
                        break;
355
                default: // We are deselecteda
356
                        for(int i=0; i<NBANKS; i++)
357
                                m_bank[i].tick(DDR_NOOP,addr);
358
                        break;
359 6 dgisselq
                }
360 13 dgisselq
 
361
                if (true) {
362
                        bool flag = false;
363
                        for(int i=0; i<5; i++) {
364
                                int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
365
                                nxtts = &m_bus[bl];
366
                                if (nxtts->m_used) {
367
                                        flag = true;
368
                                        break;
369
                                }
370
                        } if (flag) {
371
                        printf("DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
372
                        for(int i=0; i<5; i++) {
373
                                int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
374
                                nxtts = &m_bus[bl];
375
                                printf("BUS[%2d] ", bl);
376
                                if (nxtts->m_used)
377
                                        printf(" USED");
378
                                if (nxtts->m_read)
379
                                        printf(" READ");
380
                                if (nxtts->m_rtt)
381
                                        printf(" RTT");
382
                                printf("\n");
383
                        }}
384
                }
385
 
386
                ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
387
                if (dqs)
388
                        assert((ts->m_rtt)&&(m_last_rtt));
389
                else if (!m_last_dqs)
390
                        assert(!m_last_rtt);
391 4 dgisselq
        }
392
 
393
        m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
394
 
395 13 dgisselq
        ts = &m_bus[m_busloc];
396
        nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
397 4 dgisselq
        unsigned vl = ts->m_data;
398
        assert( ((!ts->m_used)||(busoe))
399 13 dgisselq
                || ((ts->m_used)&&(ts->m_read)&&(!busoe))
400
                || ((ts->m_used)&&(!ts->m_read)&&(busoe))
401
                );
402 4 dgisselq
 
403 13 dgisselq
        m_last_dqs = dqs;
404
        m_last_rtt = ts->m_rtt;
405
 
406
        if (ts->m_used) {
407
                if (ts->m_read)
408
                        assert((!dqs)&&(!m_last_dqs));
409
                else
410
                        assert((dqs) && (m_last_dqs));
411
        } else if (!nxtts->m_used)
412
                assert(!dqs);
413
 
414 4 dgisselq
        assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
415 7 dgisselq
        if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
416 9 dgisselq
                printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
417 4 dgisselq
                m_mem[ts->m_addr] = data;
418 7 dgisselq
        }
419 13 dgisselq
 
420
        m_bus[(m_busloc+3)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
421 4 dgisselq
        ts->m_used = 0;
422
        ts->m_read = 0;
423
        ts->m_addr = -1;
424 13 dgisselq
        ts->m_rtt  = 0;
425 4 dgisselq
        return (!busoe)?vl:data;
426
}
427
 

powered by: WebSVN 2.1.0

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