URL
https://opencores.org/ocsvn/wbddr3/wbddr3/trunk
Subversion Repositories wbddr3
[/] [wbddr3/] [trunk/] [bench/] [cpp/] [ddrsdramsim.cpp] - Rev 6
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: ddrsdramsim.cpp // // Project: A wishbone controlled DDR3 SDRAM memory controller. // // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2016, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program. (It's in the $(ROOT)/doc directory, run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // #include <stdio.h> #include <assert.h> const unsigned ckCL = 5, ckRC = 3, ckRFC = 320, // Clocks from refresh to activate nREF = 4, ckREFI = 1560, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560 ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC; #include "ddrsdramsim.h" void BANKINFO::tick(int cmd, unsigned addr) { switch(cmd) { case DDR_PRECHARGE: m_state = 6; break; case DDR_ACTIVATE: m_state = 1; m_row = addr & 0x7fff; break; case DDR_READ: case DDR_WRITE: printf("BANK::R/W Request, m_state = %d\n", m_state); assert((m_state&7) == 7); break; case DDR_ZQS: assert((m_state&7) == 0); break; case DDR_NOOP: m_state <<= 1; m_state |= (m_state&2)>>1; break; default: break; } } int gbl_state, gbl_counts; DDRSDRAMSIM::DDRSDRAMSIM(int lglen) { m_memlen = (1<<(lglen-2)); m_mem = new unsigned[m_memlen]; m_reset_state = 0; m_reset_counts= 0; m_bus = new BUSTIMESLOT[NTIMESLOTS]; for(int i=0; i<NTIMESLOTS; i++) m_bus[i].m_used = 0; m_busloc = 0; } unsigned DDRSDRAMSIM::operator()(int reset_n, int cke, int csn, int rasn, int casn, int wen, int dqs, int dm, int odt, int busoe, int addr, int ba, int data) { int cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0) |(rasn?4:0)|(casn?2:0)|(wen?1:0); if ((m_reset_state!=0)&&(reset_n==0)) { m_reset_state = 0; m_reset_counts = 0; } else if (m_reset_state < 16) { switch(m_reset_state) { case 0: m_reset_counts++; if (reset_n) { assert(m_reset_counts > 40000); m_reset_counts = 0; m_reset_state = 1; } break; case 1: m_reset_counts++; if (cke) { assert(m_reset_counts > 100000); m_reset_counts = 0; m_reset_state = 2; } break; case 2: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { assert(m_reset_counts > 147); m_reset_counts = 0; m_reset_state = 3; assert(cmd == DDR_MRSET); assert(ba == 2); assert(addr == 0x040); } break; case 3: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { // assert(m_reset_counts > 3); m_reset_counts = 0; m_reset_state = 4; assert(cmd == DDR_MRSET); // assert(ba == 1); // assert(addr == 0x847); } break; case 4: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { printf("DDR3-SDRAM::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr); assert(m_reset_counts > 3); m_reset_counts = 0; m_reset_state = 5; assert(cmd == DDR_MRSET); assert(ba == 0); assert(addr == 0x210); } break; case 5: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { printf("DDR3-SDRAM::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr); assert(m_reset_counts > 11); m_reset_counts = 0; m_reset_state = 6; assert(cmd == DDR_ZQS); assert(addr == 0x400); } break; case 6: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { printf("DDR3-SDRAM::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr); assert(m_reset_counts > 512); m_reset_counts = 0; m_reset_state = 7; assert(cmd == DDR_PRECHARGE); assert(addr == 0x400); } break; case 7: m_reset_counts++; assert(cke); if (cmd != DDR_NOOP) { printf("DDR3-SDRAM::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr); assert(m_reset_counts > 3); m_reset_counts = 0; m_reset_state = 8; assert(cmd == DDR_REFRESH); m_clocks_since_refresh = 0; } break; case 8: m_reset_counts++; assert(cke); assert(cmd == DDR_NOOP); if (m_reset_counts > 140) { m_reset_state = 16; printf("DDR3-SDRAM: Leaving reset state\n"); } break; default: break; } gbl_state = m_reset_state; gbl_counts= m_reset_counts; m_nrefresh_issued = nREF; } else if (!cke) { assert(0&&"Clock not enabled!"); } else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) { if (DDR_REFRESH == cmd) { m_clocks_since_refresh = 0; if (m_nrefresh_issued >= (int)nREF) m_nrefresh_issued = 0; else m_nrefresh_issued++; } else { m_clocks_since_refresh++; assert(DDR_NOOP == cmd); } for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_REFRESH,0); } else { // In operational mode!! m_clocks_since_refresh++; assert(m_clocks_since_refresh < (int)ckREFIn); switch(cmd) { case DDR_MRSET: assert(0&&"Modes should only be set in reset startup"); for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_MRSET,0); break; case DDR_REFRESH: for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_REFRESH,0); m_clocks_since_refresh = 0; assert(0 && "Internal err: Refresh should be handled above"); break; case DDR_PRECHARGE: if (addr & 0x40) { // Precharge all for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_PRECHARGE,0); } else { m_bank[ba].tick(DDR_PRECHARGE,0); for(int i=0; i<NBANKS; i++) if (ba != i) m_bank[i].tick(DDR_NOOP,0); } break; case DDR_ACTIVATE: m_bank[ba].tick(DDR_ACTIVATE,addr); for(int i=0; i<NBANKS; i++) if (i!=ba) m_bank[i].tick(DDR_NOOP,0); break; case DDR_WRITE: { // This SIM doesn't handle out of order writes assert((addr&7)==0); m_bank[ba].tick(DDR_WRITE, addr); for(int i=0; i<NBANKS; i++) if (i!=ba)m_bank[i].tick(DDR_NOOP,addr); unsigned addr = m_bank[ba].m_row; addr <<= 13; addr |= ba; addr <<= 10; addr |= addr; addr &= ~3; BUSTIMESLOT *tp; tp = &m_bus[(m_busloc+ckCL+0)&(NTIMESLOTS-1)]; tp->m_addr = addr ; tp->m_used = 1; tp->m_read = 0; tp = &m_bus[(m_busloc+ckCL+1)&(NTIMESLOTS-1)]; tp->m_addr = addr+1; tp->m_used = 1; tp->m_read = 0; tp = &m_bus[(m_busloc+ckCL+2)&(NTIMESLOTS-1)]; tp->m_addr = addr+2; tp->m_used = 1; tp->m_read = 0; tp = &m_bus[(m_busloc+ckCL+3)&(NTIMESLOTS-1)]; tp->m_addr = addr+3; tp->m_used = 1; tp->m_read = 0; } break; case DDR_READ: { // This SIM doesn't handle out of order reads assert((addr&7)==0); m_bank[ba].tick(DDR_READ, addr); for(int i=0; i<NBANKS; i++) if (i!=ba)m_bank[i].tick(DDR_NOOP,addr); unsigned addr = m_bank[ba].m_row; addr <<= 13; addr |= ba; addr <<= 10; addr |= addr; addr &= ~3; BUSTIMESLOT *tp; tp = &m_bus[(m_busloc+ckCL+0)&(NTIMESLOTS-1)]; tp->m_data = m_mem[addr]; tp->m_addr = addr; tp->m_used = 1; tp->m_read = 1; tp = &m_bus[(m_busloc+ckCL+1)&(NTIMESLOTS-1)]; tp->m_data = m_mem[addr+1]; tp->m_addr = addr+1; tp->m_used = 1; tp->m_read = 1; tp = &m_bus[(m_busloc+ckCL+2)&(NTIMESLOTS-1)]; tp->m_data = m_mem[addr+2]; tp->m_addr = addr+2; tp->m_used = 1; tp->m_read = 1; tp = &m_bus[(m_busloc+ckCL+3)&(NTIMESLOTS-1)]; tp->m_data = m_mem[addr+3]; tp->m_addr = addr+3; tp->m_used = 1; tp->m_read = 1; } break; case DDR_ZQS: assert(0&&"Sim does not support ZQS outside of startup"); break; case DDR_NOOP: for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_NOOP,addr); break; default: // We are deselecteda for(int i=0; i<NBANKS; i++) m_bank[i].tick(DDR_NOOP,addr); break; } } m_busloc = (m_busloc+1)&(NTIMESLOTS-1); BUSTIMESLOT *ts = &m_bus[m_busloc]; unsigned vl = ts->m_data; assert( ((!ts->m_used)||(busoe)) || ((ts->m_used)&&(ts->m_read))); assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen)); if ((ts->m_used)&&(!ts->m_read)&&(!dm)) m_mem[ts->m_addr] = data; ts->m_used = 0; ts->m_read = 0; ts->m_addr = -1; return (!busoe)?vl:data; }
Go to most recent revision | Compare with Previous | Blame | View Log