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

Subversion Repositories wbddr3

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

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 14 dgisselq
                ckRC = 10,
44
                ckRAS = 7,
45 6 dgisselq
                ckRFC = 320, // Clocks from refresh to activate
46 14 dgisselq
                ckREFI = 1560; // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
47
/*
48
const unsigned  nREF = 4,
49 6 dgisselq
                ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
50 14 dgisselq
*/
51
const unsigned  nREF = 1,
52
                ckREFIn = ckREFI;
53 4 dgisselq
 
54
#include "ddrsdramsim.h"
55 14 dgisselq
 
56
BANKINFO::BANKINFO(void) {
57
        m_state = 0; m_row = 0; m_wcounter = 0; m_min_time_before_precharge=0;
58
}
59
 
60 4 dgisselq
void    BANKINFO::tick(int cmd, unsigned addr) {
61 12 dgisselq
        if (m_wcounter)
62
                m_wcounter--;
63 4 dgisselq
        switch(cmd) {
64 14 dgisselq
                case DDR_REFRESH:
65
                        assert(m_state == 0);
66
                        break;
67 4 dgisselq
                case DDR_PRECHARGE:
68 6 dgisselq
                        m_state = 6;
69 8 dgisselq
                        // While the specification allows precharging an already
70
                        // precharged bank, we can keep that from happening
71
                        // here:
72
                        // assert(m_state&7);
73
                        // Only problem is, this will currently break our
74
                        // refresh logic.
75 14 dgisselq
                        if (m_min_time_before_precharge != 0) {
76
                                printf("BANK-FAIL: TIME-BEFORE-PRECHARGE = %d (should be zero)\n", m_min_time_before_precharge);
77
                                assert(m_min_time_before_precharge == 0);
78
                        } if (m_min_time_before_activate != 0) {
79
                                printf("BANK-FAIL: TIME-BEFORE-ACTIVATE = %d (should be zero)\n", m_min_time_before_activate);
80
                                assert(m_min_time_before_activate==0);
81
                        }
82 4 dgisselq
                        break;
83
                case DDR_ACTIVATE:
84 14 dgisselq
                        if (((m_state&7)!=0)&&((addr&0x7fff) != m_row)) {
85
                                printf("BANK-FAIL: Attempt to Activate an already active bank without closing it first (m_state = %x)\n", m_state);
86
                                assert((m_state&7)==0);
87
                        }
88
                        if (m_wcounter != 0) {
89
                                printf("BANK-FAIL: ACTIVATE too soon after write (wcounter = %d)\n", m_wcounter);
90
                                assert(m_wcounter == 0);
91
                        } if (m_min_time_before_activate!=0) {
92
                                printf("BANK-FAIL: ACTIVATE too soon after last activate, (ctr=%d)\n", m_min_time_before_activate);
93
                                assert(m_min_time_before_activate==0);
94
                        }
95 6 dgisselq
                        m_state = 1;
96 4 dgisselq
                        m_row = addr & 0x7fff;
97 14 dgisselq
                        m_min_time_before_precharge = ckRAS;
98
                        m_min_time_before_activate = ckRC;
99 4 dgisselq
                        break;
100
                case DDR_READ: case DDR_WRITE:
101 12 dgisselq
                        if (DDR_READ)
102
                                assert(m_wcounter == 0);
103
                        else
104
                                m_wcounter = 3+4+4;
105 4 dgisselq
                        assert((m_state&7) == 7);
106 14 dgisselq
                        if (m_min_time_before_precharge)
107
                                m_min_time_before_precharge--;
108
                        if (m_min_time_before_activate)
109
                                m_min_time_before_activate--;
110 4 dgisselq
                        break;
111
                case DDR_ZQS:
112
                        assert((m_state&7) == 0);
113 14 dgisselq
                        if (m_min_time_before_precharge)
114
                                m_min_time_before_precharge--;
115
                        if (m_min_time_before_activate)
116
                                m_min_time_before_activate--;
117 4 dgisselq
                        break;
118
                case DDR_NOOP:
119
                        m_state <<= 1;
120
                        m_state |= (m_state&2)>>1;
121 14 dgisselq
                        m_state &= 0x0f;
122
                        if (m_min_time_before_precharge)
123
                                m_min_time_before_precharge--;
124
                        if (m_min_time_before_activate)
125
                                m_min_time_before_activate--;
126 4 dgisselq
                        break;
127
                default:
128
                        break;
129
        }
130
}
131
 
132
int gbl_state, gbl_counts;
133
 
134
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
135
        m_memlen = (1<<(lglen-2));
136
        m_mem = new unsigned[m_memlen];
137
        m_reset_state = 0;
138
        m_reset_counts= 0;
139
        m_bus = new BUSTIMESLOT[NTIMESLOTS];
140
        for(int i=0; i<NTIMESLOTS; i++)
141
                m_bus[i].m_used = 0;
142 13 dgisselq
        for(int i=0; i<NTIMESLOTS; i++)
143
                m_bus[i].m_rtt = 0;
144 4 dgisselq
        m_busloc = 0;
145
}
146
 
147
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
148
                int csn, int rasn, int casn, int wen,
149
                int dqs, int dm, int odt, int busoe,
150
                int addr, int ba, int data) {
151 13 dgisselq
        BUSTIMESLOT     *ts, *nxtts;
152 4 dgisselq
        int     cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
153
                        |(rasn?4:0)|(casn?2:0)|(wen?1:0);
154 13 dgisselq
 
155 4 dgisselq
        if ((m_reset_state!=0)&&(reset_n==0)) {
156
                m_reset_state = 0;
157
                m_reset_counts = 0;
158
        } else if (m_reset_state < 16) {
159
                switch(m_reset_state) {
160
                case 0:
161
                        m_reset_counts++;
162
                        if (reset_n) {
163
                                assert(m_reset_counts > 40000);
164
                                m_reset_counts = 0;
165
                                m_reset_state = 1;
166
                        } break;
167
                case 1:
168
                        m_reset_counts++;
169
                        if (cke) {
170
                                assert(m_reset_counts > 100000);
171
                                m_reset_counts = 0;
172
                                m_reset_state = 2;
173
                        } break;
174
                case 2:
175
                        m_reset_counts++;
176 6 dgisselq
                        assert(cke);
177 4 dgisselq
                        if (cmd != DDR_NOOP) {
178
                                assert(m_reset_counts > 147);
179
                                m_reset_counts = 0;
180
                                m_reset_state = 3;
181
                                assert(cmd == DDR_MRSET);
182 14 dgisselq
                                // Set MR2
183 4 dgisselq
                                assert(ba == 2);
184
                                assert(addr == 0x040);
185
                        } break;
186
                case 3:
187
                        m_reset_counts++;
188 6 dgisselq
                        assert(cke);
189 4 dgisselq
                        if (cmd != DDR_NOOP) {
190 5 dgisselq
                                // assert(m_reset_counts > 3);
191 4 dgisselq
                                m_reset_counts = 0;
192
                                m_reset_state = 4;
193
                                assert(cmd == DDR_MRSET);
194 14 dgisselq
                                // Set MR1
195
                                assert(ba == 1);
196
                                assert(addr == 0x844);
197 4 dgisselq
                        } break;
198
                case 4:
199
                        m_reset_counts++;
200 6 dgisselq
                        assert(cke);
201 4 dgisselq
                        if (cmd != DDR_NOOP) {
202 9 dgisselq
                                printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
203 4 dgisselq
                                assert(m_reset_counts > 3);
204
                                m_reset_counts = 0;
205
                                m_reset_state = 5;
206
                                assert(cmd == DDR_MRSET);
207 14 dgisselq
                                // Set MR0
208 4 dgisselq
                                assert(ba == 0);
209
                                assert(addr == 0x210);
210
                        } break;
211
                case 5:
212
                        m_reset_counts++;
213 6 dgisselq
                        assert(cke);
214 4 dgisselq
                        if (cmd != DDR_NOOP) {
215 9 dgisselq
                                printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
216 5 dgisselq
                                assert(m_reset_counts > 11);
217 4 dgisselq
                                m_reset_counts = 0;
218
                                m_reset_state = 6;
219
                                assert(cmd == DDR_ZQS);
220 5 dgisselq
                                assert(addr == 0x400);
221 4 dgisselq
                        } break;
222
                case 6:
223
                        m_reset_counts++;
224 6 dgisselq
                        assert(cke);
225 4 dgisselq
                        if (cmd != DDR_NOOP) {
226 9 dgisselq
                                printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
227 4 dgisselq
                                assert(m_reset_counts > 512);
228
                                m_reset_counts = 0;
229
                                m_reset_state = 7;
230
                                assert(cmd == DDR_PRECHARGE);
231 5 dgisselq
                                assert(addr == 0x400);
232 4 dgisselq
                        } break;
233
                case 7:
234
                        m_reset_counts++;
235 6 dgisselq
                        assert(cke);
236 4 dgisselq
                        if (cmd != DDR_NOOP) {
237 9 dgisselq
                                printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
238 4 dgisselq
                                assert(m_reset_counts > 3);
239
                                m_reset_counts = 0;
240
                                m_reset_state = 8;
241
                                assert(cmd == DDR_REFRESH);
242 6 dgisselq
                                m_clocks_since_refresh = 0;
243 4 dgisselq
                        } break;
244
                case 8:
245
                        m_reset_counts++;
246 6 dgisselq
                        assert(cke);
247 4 dgisselq
                        assert(cmd == DDR_NOOP);
248 5 dgisselq
                        if (m_reset_counts > 140) {
249 4 dgisselq
                                m_reset_state = 16;
250 9 dgisselq
                                printf(PREFIX ": Leaving reset state\n");
251 5 dgisselq
                        }
252 4 dgisselq
                        break;
253
                default:
254
                        break;
255
                }
256
 
257
                gbl_state = m_reset_state;
258
                gbl_counts= m_reset_counts;
259 6 dgisselq
                m_nrefresh_issued = nREF;
260 7 dgisselq
                m_clocks_since_refresh++;
261 14 dgisselq
                for(int i=0; i<NBANKS; i++)
262
                        m_bank[i].tick(cmd, 0);
263 6 dgisselq
        } else if (!cke) {
264 4 dgisselq
                assert(0&&"Clock not enabled!");
265 6 dgisselq
        } else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
266
                if (DDR_REFRESH == cmd) {
267
                        m_clocks_since_refresh = 0;
268
                        if (m_nrefresh_issued >= (int)nREF)
269 7 dgisselq
                                m_nrefresh_issued = 1;
270 6 dgisselq
                        else
271
                                m_nrefresh_issued++;
272
                } else {
273
                        m_clocks_since_refresh++;
274
                        assert(DDR_NOOP == cmd);
275
                }
276
                for(int i=0; i<NBANKS; i++)
277 14 dgisselq
                        m_bank[i].tick(cmd,0);
278 7 dgisselq
 
279
                if (m_nrefresh_issued == nREF)
280 9 dgisselq
                        printf(PREFIX "::Refresh cycle complete\n");
281 6 dgisselq
        } else {
282
                // In operational mode!!
283
 
284
                m_clocks_since_refresh++;
285
                assert(m_clocks_since_refresh < (int)ckREFIn);
286
                switch(cmd) {
287 4 dgisselq
                case DDR_MRSET:
288
                        assert(0&&"Modes should only be set in reset startup");
289
                        for(int i=0; i<NBANKS; i++)
290
                                m_bank[i].tick(DDR_MRSET,0);
291
                        break;
292
                case DDR_REFRESH:
293
                        for(int i=0; i<NBANKS; i++)
294
                                m_bank[i].tick(DDR_REFRESH,0);
295 6 dgisselq
                        m_clocks_since_refresh = 0;
296
                        assert(0 && "Internal err: Refresh should be handled above");
297 4 dgisselq
                        break;
298
                case DDR_PRECHARGE:
299 14 dgisselq
                        if (addr & 0x400) {
300 4 dgisselq
                                // Precharge all
301
                                for(int i=0; i<NBANKS; i++)
302
                                        m_bank[i].tick(DDR_PRECHARGE,0);
303
                        } else {
304
                                m_bank[ba].tick(DDR_PRECHARGE,0);
305
                                for(int i=0; i<NBANKS; i++)
306
                                        if (ba != i)
307
                                                m_bank[i].tick(DDR_NOOP,0);
308
                        }
309
                        break;
310
                case DDR_ACTIVATE:
311 7 dgisselq
                        assert(m_clocks_since_refresh >= (int)ckRFC);
312 14 dgisselq
                        printf(PREFIX "::Activating bank %d, address %08x\n", ba, addr);
313 4 dgisselq
                        m_bank[ba].tick(DDR_ACTIVATE,addr);
314
                        for(int i=0; i<NBANKS; i++)
315
                                if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
316
                        break;
317
                case DDR_WRITE:
318
                        {
319 6 dgisselq
                                // This SIM doesn't handle out of order writes
320
                                assert((addr&7)==0);
321
                                m_bank[ba].tick(DDR_WRITE, addr);
322 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
323 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
324 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
325 8 dgisselq
                                caddr <<= 3;
326 7 dgisselq
                                caddr |= ba;
327
                                caddr <<= 10;
328
                                caddr |= addr;
329
                                caddr &= ~7;
330
                                caddr >>= 1;
331 4 dgisselq
 
332
                                BUSTIMESLOT *tp;
333 7 dgisselq
                                int     offset = m_busloc+ckCL+1;
334 4 dgisselq
 
335 7 dgisselq
                                tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
336 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);
337 7 dgisselq
                                tp->m_addr = caddr  ;
338 4 dgisselq
                                tp->m_used = 1;
339
                                tp->m_read = 0;
340
 
341 7 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
342
                                tp->m_addr = caddr+1;
343 4 dgisselq
                                tp->m_used = 1;
344
                                tp->m_read = 0;
345
 
346 7 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
347
                                tp->m_addr = caddr+2;
348 4 dgisselq
                                tp->m_used = 1;
349
                                tp->m_read = 0;
350
 
351 7 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
352
                                tp->m_addr = caddr+3;
353 4 dgisselq
                                tp->m_used = 1;
354
                                tp->m_read = 0;
355
                        } break;
356
                case DDR_READ:
357
                        {
358 6 dgisselq
                                // This SIM doesn't handle out of order reads
359
                                assert((addr&7)==0);
360
                                m_bank[ba].tick(DDR_READ, addr);
361 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
362 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
363 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
364 8 dgisselq
                                caddr <<= 3;
365 7 dgisselq
                                caddr |= ba;
366
                                caddr <<= 10;
367
                                caddr |= addr;
368
                                caddr &= ~7;
369
                                caddr >>= 1;
370 4 dgisselq
 
371
                                BUSTIMESLOT *tp;
372
 
373 8 dgisselq
                                int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
374
                                tp = &m_bus[(offset)&(NTIMESLOTS-1)];
375 7 dgisselq
                                tp->m_data = m_mem[caddr];
376
                                tp->m_addr = caddr;
377 4 dgisselq
                                tp->m_used = 1;
378
                                tp->m_read = 1;
379
 
380 8 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
381 7 dgisselq
                                tp->m_data = m_mem[caddr+1];
382
                                tp->m_addr = caddr+1;
383 4 dgisselq
                                tp->m_used = 1;
384
                                tp->m_read = 1;
385
 
386 8 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
387 7 dgisselq
                                tp->m_data = m_mem[caddr+2];
388
                                tp->m_addr = caddr+2;
389 4 dgisselq
                                tp->m_used = 1;
390
                                tp->m_read = 1;
391
 
392 8 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
393 7 dgisselq
                                tp->m_data = m_mem[caddr+3];
394
                                tp->m_addr = caddr+3;
395 4 dgisselq
                                tp->m_used = 1;
396
                                tp->m_read = 1;
397
                        } break;
398
                case DDR_ZQS:
399
                        assert(0&&"Sim does not support ZQS outside of startup");
400
                        break;
401
                case DDR_NOOP:
402
                        for(int i=0; i<NBANKS; i++)
403
                                m_bank[i].tick(DDR_NOOP,addr);
404
                        break;
405
                default: // We are deselecteda
406
                        for(int i=0; i<NBANKS; i++)
407
                                m_bank[i].tick(DDR_NOOP,addr);
408
                        break;
409 6 dgisselq
                }
410 13 dgisselq
 
411 14 dgisselq
                if (false) {
412 13 dgisselq
                        bool flag = false;
413
                        for(int i=0; i<5; i++) {
414
                                int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
415
                                nxtts = &m_bus[bl];
416
                                if (nxtts->m_used) {
417
                                        flag = true;
418
                                        break;
419
                                }
420
                        } if (flag) {
421
                        printf("DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
422
                        for(int i=0; i<5; i++) {
423
                                int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
424
                                nxtts = &m_bus[bl];
425
                                printf("BUS[%2d] ", bl);
426
                                if (nxtts->m_used)
427
                                        printf(" USED");
428
                                if (nxtts->m_read)
429
                                        printf(" READ");
430
                                if (nxtts->m_rtt)
431
                                        printf(" RTT");
432
                                printf("\n");
433
                        }}
434
                }
435
 
436
                ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
437
                if (dqs)
438
                        assert((ts->m_rtt)&&(m_last_rtt));
439
                else if (!m_last_dqs)
440
                        assert(!m_last_rtt);
441 4 dgisselq
        }
442
 
443
        m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
444
 
445 13 dgisselq
        ts = &m_bus[m_busloc];
446
        nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
447 4 dgisselq
        unsigned vl = ts->m_data;
448
        assert( ((!ts->m_used)||(busoe))
449 13 dgisselq
                || ((ts->m_used)&&(ts->m_read)&&(!busoe))
450
                || ((ts->m_used)&&(!ts->m_read)&&(busoe))
451
                );
452 4 dgisselq
 
453 13 dgisselq
        m_last_dqs = dqs;
454
        m_last_rtt = ts->m_rtt;
455
 
456
        if (ts->m_used) {
457
                if (ts->m_read)
458
                        assert((!dqs)&&(!m_last_dqs));
459
                else
460
                        assert((dqs) && (m_last_dqs));
461
        } else if (!nxtts->m_used)
462
                assert(!dqs);
463
 
464 4 dgisselq
        assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
465 7 dgisselq
        if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
466 9 dgisselq
                printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
467 4 dgisselq
                m_mem[ts->m_addr] = data;
468 7 dgisselq
        }
469 13 dgisselq
 
470
        m_bus[(m_busloc+3)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
471 4 dgisselq
        ts->m_used = 0;
472
        ts->m_read = 0;
473
        ts->m_addr = -1;
474 13 dgisselq
        ts->m_rtt  = 0;
475 4 dgisselq
        return (!busoe)?vl:data;
476
}
477
 

powered by: WebSVN 2.1.0

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