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

Subversion Repositories wbddr3

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

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
        switch(cmd) {
52
                case DDR_PRECHARGE:
53 6 dgisselq
                        m_state = 6;
54 8 dgisselq
                        // While the specification allows precharging an already
55
                        // precharged bank, we can keep that from happening
56
                        // here:
57
                        // assert(m_state&7);
58
                        // Only problem is, this will currently break our
59
                        // refresh logic.
60 4 dgisselq
                        break;
61
                case DDR_ACTIVATE:
62 6 dgisselq
                        m_state = 1;
63 4 dgisselq
                        m_row = addr & 0x7fff;
64
                        break;
65
                case DDR_READ: case DDR_WRITE:
66 6 dgisselq
                        printf("BANK::R/W Request, m_state = %d\n", m_state);
67 4 dgisselq
                        assert((m_state&7) == 7);
68
                        break;
69
                case DDR_ZQS:
70
                        assert((m_state&7) == 0);
71
                        break;
72
                case DDR_NOOP:
73
                        m_state <<= 1;
74
                        m_state |= (m_state&2)>>1;
75
                        break;
76
                default:
77
                        break;
78
        }
79
}
80
 
81
int gbl_state, gbl_counts;
82
 
83
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
84
        m_memlen = (1<<(lglen-2));
85
        m_mem = new unsigned[m_memlen];
86
        m_reset_state = 0;
87
        m_reset_counts= 0;
88
        m_bus = new BUSTIMESLOT[NTIMESLOTS];
89
        for(int i=0; i<NTIMESLOTS; i++)
90
                m_bus[i].m_used = 0;
91
        m_busloc = 0;
92
}
93
 
94
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
95
                int csn, int rasn, int casn, int wen,
96
                int dqs, int dm, int odt, int busoe,
97
                int addr, int ba, int data) {
98
 
99
        int     cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
100
                        |(rasn?4:0)|(casn?2:0)|(wen?1:0);
101
        if ((m_reset_state!=0)&&(reset_n==0)) {
102
                m_reset_state = 0;
103
                m_reset_counts = 0;
104
        } else if (m_reset_state < 16) {
105
                switch(m_reset_state) {
106
                case 0:
107
                        m_reset_counts++;
108
                        if (reset_n) {
109
                                assert(m_reset_counts > 40000);
110
                                m_reset_counts = 0;
111
                                m_reset_state = 1;
112
                        } break;
113
                case 1:
114
                        m_reset_counts++;
115
                        if (cke) {
116
                                assert(m_reset_counts > 100000);
117
                                m_reset_counts = 0;
118
                                m_reset_state = 2;
119
                        } break;
120
                case 2:
121
                        m_reset_counts++;
122 6 dgisselq
                        assert(cke);
123 4 dgisselq
                        if (cmd != DDR_NOOP) {
124
                                assert(m_reset_counts > 147);
125
                                m_reset_counts = 0;
126
                                m_reset_state = 3;
127
                                assert(cmd == DDR_MRSET);
128
                                assert(ba == 2);
129
                                assert(addr == 0x040);
130
                        } break;
131
                case 3:
132
                        m_reset_counts++;
133 6 dgisselq
                        assert(cke);
134 4 dgisselq
                        if (cmd != DDR_NOOP) {
135 5 dgisselq
                                // assert(m_reset_counts > 3);
136 4 dgisselq
                                m_reset_counts = 0;
137
                                m_reset_state = 4;
138
                                assert(cmd == DDR_MRSET);
139 5 dgisselq
                                // assert(ba == 1);
140
                                // assert(addr == 0x847);
141 4 dgisselq
                        } break;
142
                case 4:
143
                        m_reset_counts++;
144 6 dgisselq
                        assert(cke);
145 4 dgisselq
                        if (cmd != DDR_NOOP) {
146 9 dgisselq
                                printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
147 4 dgisselq
                                assert(m_reset_counts > 3);
148
                                m_reset_counts = 0;
149
                                m_reset_state = 5;
150
                                assert(cmd == DDR_MRSET);
151
                                assert(ba == 0);
152
                                assert(addr == 0x210);
153
                        } break;
154
                case 5:
155
                        m_reset_counts++;
156 6 dgisselq
                        assert(cke);
157 4 dgisselq
                        if (cmd != DDR_NOOP) {
158 9 dgisselq
                                printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
159 5 dgisselq
                                assert(m_reset_counts > 11);
160 4 dgisselq
                                m_reset_counts = 0;
161
                                m_reset_state = 6;
162
                                assert(cmd == DDR_ZQS);
163 5 dgisselq
                                assert(addr == 0x400);
164 4 dgisselq
                        } break;
165
                case 6:
166
                        m_reset_counts++;
167 6 dgisselq
                        assert(cke);
168 4 dgisselq
                        if (cmd != DDR_NOOP) {
169 9 dgisselq
                                printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
170 4 dgisselq
                                assert(m_reset_counts > 512);
171
                                m_reset_counts = 0;
172
                                m_reset_state = 7;
173
                                assert(cmd == DDR_PRECHARGE);
174 5 dgisselq
                                assert(addr == 0x400);
175 4 dgisselq
                        } break;
176
                case 7:
177
                        m_reset_counts++;
178 6 dgisselq
                        assert(cke);
179 4 dgisselq
                        if (cmd != DDR_NOOP) {
180 9 dgisselq
                                printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
181 4 dgisselq
                                assert(m_reset_counts > 3);
182
                                m_reset_counts = 0;
183
                                m_reset_state = 8;
184
                                assert(cmd == DDR_REFRESH);
185 6 dgisselq
                                m_clocks_since_refresh = 0;
186 4 dgisselq
                        } break;
187
                case 8:
188
                        m_reset_counts++;
189 6 dgisselq
                        assert(cke);
190 4 dgisselq
                        assert(cmd == DDR_NOOP);
191 5 dgisselq
                        if (m_reset_counts > 140) {
192 4 dgisselq
                                m_reset_state = 16;
193 9 dgisselq
                                printf(PREFIX ": Leaving reset state\n");
194 5 dgisselq
                        }
195 4 dgisselq
                        break;
196
                default:
197
                        break;
198
                }
199
 
200
                gbl_state = m_reset_state;
201
                gbl_counts= m_reset_counts;
202 6 dgisselq
                m_nrefresh_issued = nREF;
203 7 dgisselq
                m_clocks_since_refresh++;
204 6 dgisselq
        } else if (!cke) {
205 4 dgisselq
                assert(0&&"Clock not enabled!");
206 6 dgisselq
        } else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
207
                if (DDR_REFRESH == cmd) {
208
                        m_clocks_since_refresh = 0;
209
                        if (m_nrefresh_issued >= (int)nREF)
210 7 dgisselq
                                m_nrefresh_issued = 1;
211 6 dgisselq
                        else
212
                                m_nrefresh_issued++;
213
                } else {
214
                        m_clocks_since_refresh++;
215
                        assert(DDR_NOOP == cmd);
216
                }
217
                for(int i=0; i<NBANKS; i++)
218
                        m_bank[i].tick(DDR_REFRESH,0);
219 7 dgisselq
 
220
                if (m_nrefresh_issued == nREF)
221 9 dgisselq
                        printf(PREFIX "::Refresh cycle complete\n");
222 6 dgisselq
        } else {
223
                // In operational mode!!
224
 
225
                m_clocks_since_refresh++;
226
                assert(m_clocks_since_refresh < (int)ckREFIn);
227
                switch(cmd) {
228 4 dgisselq
                case DDR_MRSET:
229
                        assert(0&&"Modes should only be set in reset startup");
230
                        for(int i=0; i<NBANKS; i++)
231
                                m_bank[i].tick(DDR_MRSET,0);
232
                        break;
233
                case DDR_REFRESH:
234
                        for(int i=0; i<NBANKS; i++)
235
                                m_bank[i].tick(DDR_REFRESH,0);
236 6 dgisselq
                        m_clocks_since_refresh = 0;
237
                        assert(0 && "Internal err: Refresh should be handled above");
238 4 dgisselq
                        break;
239
                case DDR_PRECHARGE:
240
                        if (addr & 0x40) {
241
                                // Precharge all
242
                                for(int i=0; i<NBANKS; i++)
243
                                        m_bank[i].tick(DDR_PRECHARGE,0);
244
                        } else {
245
                                m_bank[ba].tick(DDR_PRECHARGE,0);
246
                                for(int i=0; i<NBANKS; i++)
247
                                        if (ba != i)
248
                                                m_bank[i].tick(DDR_NOOP,0);
249
                        }
250
                        break;
251
                case DDR_ACTIVATE:
252 7 dgisselq
                        assert(m_clocks_since_refresh >= (int)ckRFC);
253 4 dgisselq
                        m_bank[ba].tick(DDR_ACTIVATE,addr);
254
                        for(int i=0; i<NBANKS; i++)
255
                                if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
256
                        break;
257
                case DDR_WRITE:
258
                        {
259 6 dgisselq
                                // This SIM doesn't handle out of order writes
260
                                assert((addr&7)==0);
261
                                m_bank[ba].tick(DDR_WRITE, addr);
262 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
263 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
264 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
265 8 dgisselq
                                caddr <<= 3;
266 7 dgisselq
                                caddr |= ba;
267
                                caddr <<= 10;
268
                                caddr |= addr;
269
                                caddr &= ~7;
270
                                caddr >>= 1;
271 4 dgisselq
 
272
                                BUSTIMESLOT *tp;
273 7 dgisselq
                                int     offset = m_busloc+ckCL+1;
274 4 dgisselq
 
275 7 dgisselq
                                tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
276 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);
277 7 dgisselq
                                tp->m_addr = caddr  ;
278 4 dgisselq
                                tp->m_used = 1;
279
                                tp->m_read = 0;
280
 
281 7 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
282
                                tp->m_addr = caddr+1;
283 4 dgisselq
                                tp->m_used = 1;
284
                                tp->m_read = 0;
285
 
286 7 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
287
                                tp->m_addr = caddr+2;
288 4 dgisselq
                                tp->m_used = 1;
289
                                tp->m_read = 0;
290
 
291 7 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
292
                                tp->m_addr = caddr+3;
293 4 dgisselq
                                tp->m_used = 1;
294
                                tp->m_read = 0;
295
                        } break;
296
                case DDR_READ:
297
                        {
298 6 dgisselq
                                // This SIM doesn't handle out of order reads
299
                                assert((addr&7)==0);
300
                                m_bank[ba].tick(DDR_READ, addr);
301 4 dgisselq
                                for(int i=0; i<NBANKS; i++)
302 6 dgisselq
                                        if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
303 7 dgisselq
                                unsigned caddr = m_bank[ba].m_row;
304 8 dgisselq
                                caddr <<= 3;
305 7 dgisselq
                                caddr |= ba;
306
                                caddr <<= 10;
307
                                caddr |= addr;
308
                                caddr &= ~7;
309
                                caddr >>= 1;
310 4 dgisselq
 
311
                                BUSTIMESLOT *tp;
312
 
313 8 dgisselq
                                int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
314
                                tp = &m_bus[(offset)&(NTIMESLOTS-1)];
315 7 dgisselq
                                tp->m_data = m_mem[caddr];
316
                                tp->m_addr = caddr;
317 4 dgisselq
                                tp->m_used = 1;
318
                                tp->m_read = 1;
319
 
320 8 dgisselq
                                tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
321 7 dgisselq
                                tp->m_data = m_mem[caddr+1];
322
                                tp->m_addr = caddr+1;
323 4 dgisselq
                                tp->m_used = 1;
324
                                tp->m_read = 1;
325
 
326 8 dgisselq
                                tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
327 7 dgisselq
                                tp->m_data = m_mem[caddr+2];
328
                                tp->m_addr = caddr+2;
329 4 dgisselq
                                tp->m_used = 1;
330
                                tp->m_read = 1;
331
 
332 8 dgisselq
                                tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
333 7 dgisselq
                                tp->m_data = m_mem[caddr+3];
334
                                tp->m_addr = caddr+3;
335 4 dgisselq
                                tp->m_used = 1;
336
                                tp->m_read = 1;
337
                        } break;
338
                case DDR_ZQS:
339
                        assert(0&&"Sim does not support ZQS outside of startup");
340
                        break;
341
                case DDR_NOOP:
342
                        for(int i=0; i<NBANKS; i++)
343
                                m_bank[i].tick(DDR_NOOP,addr);
344
                        break;
345
                default: // We are deselecteda
346
                        for(int i=0; i<NBANKS; i++)
347
                                m_bank[i].tick(DDR_NOOP,addr);
348
                        break;
349 6 dgisselq
                }
350 4 dgisselq
        }
351
 
352
        m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
353
 
354
        BUSTIMESLOT     *ts = &m_bus[m_busloc];
355
        unsigned vl = ts->m_data;
356
        assert( ((!ts->m_used)||(busoe))
357
                || ((ts->m_used)&&(ts->m_read)));
358
 
359
        assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
360 7 dgisselq
        if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
361 9 dgisselq
                printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
362 4 dgisselq
                m_mem[ts->m_addr] = data;
363 7 dgisselq
        }
364 4 dgisselq
        ts->m_used = 0;
365
        ts->m_read = 0;
366
        ts->m_addr = -1;
367
        return (!busoe)?vl:data;
368
}
369
 

powered by: WebSVN 2.1.0

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