////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: ddrsdramsim.cpp
|
// Filename: ddrsdramsim.cpp
|
//
|
//
|
// Project: A wishbone controlled DDR3 SDRAM memory controller.
|
// Project: A wishbone controlled DDR3 SDRAM memory controller.
|
//
|
//
|
// Purpose:
|
// Purpose:
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// 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
|
// 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
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
//
|
//
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// 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
|
// 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
|
// target there if the PDF file isn't present.) If not, see
|
// <http://www.gnu.org/licenses/> for a copy.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <assert.h>
|
#include <assert.h>
|
|
|
#define PREFIX "DDR3-SDRAM"
|
#define PREFIX "DDR3-SDRAM"
|
const unsigned ckCL = 5,
|
const unsigned ckCL = 5,
|
ckRC = 3,
|
ckRC = 3,
|
ckRFC = 320, // Clocks from refresh to activate
|
ckRFC = 320, // Clocks from refresh to activate
|
nREF = 4,
|
nREF = 4,
|
ckREFI = 1560, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
|
ckREFI = 1560, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
|
ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
|
ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
|
|
|
#include "ddrsdramsim.h"
|
#include "ddrsdramsim.h"
|
void BANKINFO::tick(int cmd, unsigned addr) {
|
void BANKINFO::tick(int cmd, unsigned addr) {
|
if (m_wcounter)
|
if (m_wcounter)
|
m_wcounter--;
|
m_wcounter--;
|
switch(cmd) {
|
switch(cmd) {
|
case DDR_PRECHARGE:
|
case DDR_PRECHARGE:
|
m_state = 6;
|
m_state = 6;
|
// While the specification allows precharging an already
|
// While the specification allows precharging an already
|
// precharged bank, we can keep that from happening
|
// precharged bank, we can keep that from happening
|
// here:
|
// here:
|
// assert(m_state&7);
|
// assert(m_state&7);
|
// Only problem is, this will currently break our
|
// Only problem is, this will currently break our
|
// refresh logic.
|
// refresh logic.
|
break;
|
break;
|
case DDR_ACTIVATE:
|
case DDR_ACTIVATE:
|
assert(m_wcounter == 0);
|
assert(m_wcounter == 0);
|
m_state = 1;
|
m_state = 1;
|
m_row = addr & 0x7fff;
|
m_row = addr & 0x7fff;
|
break;
|
break;
|
case DDR_READ: case DDR_WRITE:
|
case DDR_READ: case DDR_WRITE:
|
if (DDR_READ)
|
if (DDR_READ)
|
assert(m_wcounter == 0);
|
assert(m_wcounter == 0);
|
else
|
else
|
m_wcounter = 3+4+4;
|
m_wcounter = 3+4+4;
|
printf("BANK::R/W Request, m_state = %d\n", m_state);
|
printf("BANK::R/W Request, m_state = %d\n", m_state);
|
assert((m_state&7) == 7);
|
assert((m_state&7) == 7);
|
break;
|
break;
|
case DDR_ZQS:
|
case DDR_ZQS:
|
assert((m_state&7) == 0);
|
assert((m_state&7) == 0);
|
break;
|
break;
|
case DDR_NOOP:
|
case DDR_NOOP:
|
m_state <<= 1;
|
m_state <<= 1;
|
m_state |= (m_state&2)>>1;
|
m_state |= (m_state&2)>>1;
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
int gbl_state, gbl_counts;
|
int gbl_state, gbl_counts;
|
|
|
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
|
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
|
m_memlen = (1<<(lglen-2));
|
m_memlen = (1<<(lglen-2));
|
m_mem = new unsigned[m_memlen];
|
m_mem = new unsigned[m_memlen];
|
m_reset_state = 0;
|
m_reset_state = 0;
|
m_reset_counts= 0;
|
m_reset_counts= 0;
|
m_bus = new BUSTIMESLOT[NTIMESLOTS];
|
m_bus = new BUSTIMESLOT[NTIMESLOTS];
|
for(int i=0; i<NTIMESLOTS; i++)
|
for(int i=0; i<NTIMESLOTS; i++)
|
m_bus[i].m_used = 0;
|
m_bus[i].m_used = 0;
|
|
for(int i=0; i<NTIMESLOTS; i++)
|
|
m_bus[i].m_rtt = 0;
|
m_busloc = 0;
|
m_busloc = 0;
|
}
|
}
|
|
|
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
|
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
|
int csn, int rasn, int casn, int wen,
|
int csn, int rasn, int casn, int wen,
|
int dqs, int dm, int odt, int busoe,
|
int dqs, int dm, int odt, int busoe,
|
int addr, int ba, int data) {
|
int addr, int ba, int data) {
|
|
BUSTIMESLOT *ts, *nxtts;
|
int cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
|
int cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
|
|(rasn?4:0)|(casn?2:0)|(wen?1:0);
|
|(rasn?4:0)|(casn?2:0)|(wen?1:0);
|
|
|
if ((m_reset_state!=0)&&(reset_n==0)) {
|
if ((m_reset_state!=0)&&(reset_n==0)) {
|
m_reset_state = 0;
|
m_reset_state = 0;
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
} else if (m_reset_state < 16) {
|
} else if (m_reset_state < 16) {
|
switch(m_reset_state) {
|
switch(m_reset_state) {
|
case 0:
|
case 0:
|
m_reset_counts++;
|
m_reset_counts++;
|
if (reset_n) {
|
if (reset_n) {
|
assert(m_reset_counts > 40000);
|
assert(m_reset_counts > 40000);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 1;
|
m_reset_state = 1;
|
} break;
|
} break;
|
case 1:
|
case 1:
|
m_reset_counts++;
|
m_reset_counts++;
|
if (cke) {
|
if (cke) {
|
assert(m_reset_counts > 100000);
|
assert(m_reset_counts > 100000);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 2;
|
m_reset_state = 2;
|
} break;
|
} break;
|
case 2:
|
case 2:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
assert(m_reset_counts > 147);
|
assert(m_reset_counts > 147);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 3;
|
m_reset_state = 3;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
assert(ba == 2);
|
assert(ba == 2);
|
assert(addr == 0x040);
|
assert(addr == 0x040);
|
} break;
|
} break;
|
case 3:
|
case 3:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
// assert(m_reset_counts > 3);
|
// assert(m_reset_counts > 3);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 4;
|
m_reset_state = 4;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
// assert(ba == 1);
|
// assert(ba == 1);
|
// assert(addr == 0x847);
|
// assert(addr == 0x847);
|
} break;
|
} break;
|
case 4:
|
case 4:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
assert(m_reset_counts > 3);
|
assert(m_reset_counts > 3);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 5;
|
m_reset_state = 5;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
assert(ba == 0);
|
assert(ba == 0);
|
assert(addr == 0x210);
|
assert(addr == 0x210);
|
} break;
|
} break;
|
case 5:
|
case 5:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
assert(m_reset_counts > 11);
|
assert(m_reset_counts > 11);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 6;
|
m_reset_state = 6;
|
assert(cmd == DDR_ZQS);
|
assert(cmd == DDR_ZQS);
|
assert(addr == 0x400);
|
assert(addr == 0x400);
|
} break;
|
} break;
|
case 6:
|
case 6:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
assert(m_reset_counts > 512);
|
assert(m_reset_counts > 512);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 7;
|
m_reset_state = 7;
|
assert(cmd == DDR_PRECHARGE);
|
assert(cmd == DDR_PRECHARGE);
|
assert(addr == 0x400);
|
assert(addr == 0x400);
|
} break;
|
} break;
|
case 7:
|
case 7:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if (cmd != DDR_NOOP) {
|
printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
|
assert(m_reset_counts > 3);
|
assert(m_reset_counts > 3);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 8;
|
m_reset_state = 8;
|
assert(cmd == DDR_REFRESH);
|
assert(cmd == DDR_REFRESH);
|
m_clocks_since_refresh = 0;
|
m_clocks_since_refresh = 0;
|
} break;
|
} break;
|
case 8:
|
case 8:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
assert(cmd == DDR_NOOP);
|
assert(cmd == DDR_NOOP);
|
if (m_reset_counts > 140) {
|
if (m_reset_counts > 140) {
|
m_reset_state = 16;
|
m_reset_state = 16;
|
printf(PREFIX ": Leaving reset state\n");
|
printf(PREFIX ": Leaving reset state\n");
|
}
|
}
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
|
|
gbl_state = m_reset_state;
|
gbl_state = m_reset_state;
|
gbl_counts= m_reset_counts;
|
gbl_counts= m_reset_counts;
|
m_nrefresh_issued = nREF;
|
m_nrefresh_issued = nREF;
|
m_clocks_since_refresh++;
|
m_clocks_since_refresh++;
|
} else if (!cke) {
|
} else if (!cke) {
|
assert(0&&"Clock not enabled!");
|
assert(0&&"Clock not enabled!");
|
} else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
|
} else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
|
if (DDR_REFRESH == cmd) {
|
if (DDR_REFRESH == cmd) {
|
m_clocks_since_refresh = 0;
|
m_clocks_since_refresh = 0;
|
if (m_nrefresh_issued >= (int)nREF)
|
if (m_nrefresh_issued >= (int)nREF)
|
m_nrefresh_issued = 1;
|
m_nrefresh_issued = 1;
|
else
|
else
|
m_nrefresh_issued++;
|
m_nrefresh_issued++;
|
} else {
|
} else {
|
m_clocks_since_refresh++;
|
m_clocks_since_refresh++;
|
assert(DDR_NOOP == cmd);
|
assert(DDR_NOOP == cmd);
|
}
|
}
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_REFRESH,0);
|
m_bank[i].tick(DDR_REFRESH,0);
|
|
|
if (m_nrefresh_issued == nREF)
|
if (m_nrefresh_issued == nREF)
|
printf(PREFIX "::Refresh cycle complete\n");
|
printf(PREFIX "::Refresh cycle complete\n");
|
} else {
|
} else {
|
// In operational mode!!
|
// In operational mode!!
|
|
|
m_clocks_since_refresh++;
|
m_clocks_since_refresh++;
|
assert(m_clocks_since_refresh < (int)ckREFIn);
|
assert(m_clocks_since_refresh < (int)ckREFIn);
|
switch(cmd) {
|
switch(cmd) {
|
case DDR_MRSET:
|
case DDR_MRSET:
|
assert(0&&"Modes should only be set in reset startup");
|
assert(0&&"Modes should only be set in reset startup");
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_MRSET,0);
|
m_bank[i].tick(DDR_MRSET,0);
|
break;
|
break;
|
case DDR_REFRESH:
|
case DDR_REFRESH:
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_REFRESH,0);
|
m_bank[i].tick(DDR_REFRESH,0);
|
m_clocks_since_refresh = 0;
|
m_clocks_since_refresh = 0;
|
assert(0 && "Internal err: Refresh should be handled above");
|
assert(0 && "Internal err: Refresh should be handled above");
|
break;
|
break;
|
case DDR_PRECHARGE:
|
case DDR_PRECHARGE:
|
if (addr & 0x40) {
|
if (addr & 0x40) {
|
// Precharge all
|
// Precharge all
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_PRECHARGE,0);
|
m_bank[i].tick(DDR_PRECHARGE,0);
|
} else {
|
} else {
|
m_bank[ba].tick(DDR_PRECHARGE,0);
|
m_bank[ba].tick(DDR_PRECHARGE,0);
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
if (ba != i)
|
if (ba != i)
|
m_bank[i].tick(DDR_NOOP,0);
|
m_bank[i].tick(DDR_NOOP,0);
|
}
|
}
|
break;
|
break;
|
case DDR_ACTIVATE:
|
case DDR_ACTIVATE:
|
assert(m_clocks_since_refresh >= (int)ckRFC);
|
assert(m_clocks_since_refresh >= (int)ckRFC);
|
m_bank[ba].tick(DDR_ACTIVATE,addr);
|
m_bank[ba].tick(DDR_ACTIVATE,addr);
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
|
if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
|
break;
|
break;
|
case DDR_WRITE:
|
case DDR_WRITE:
|
{
|
{
|
// This SIM doesn't handle out of order writes
|
// This SIM doesn't handle out of order writes
|
assert((addr&7)==0);
|
assert((addr&7)==0);
|
m_bank[ba].tick(DDR_WRITE, addr);
|
m_bank[ba].tick(DDR_WRITE, addr);
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
|
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
|
unsigned caddr = m_bank[ba].m_row;
|
unsigned caddr = m_bank[ba].m_row;
|
caddr <<= 3;
|
caddr <<= 3;
|
caddr |= ba;
|
caddr |= ba;
|
caddr <<= 10;
|
caddr <<= 10;
|
caddr |= addr;
|
caddr |= addr;
|
caddr &= ~7;
|
caddr &= ~7;
|
caddr >>= 1;
|
caddr >>= 1;
|
|
|
BUSTIMESLOT *tp;
|
BUSTIMESLOT *tp;
|
int offset = m_busloc+ckCL+1;
|
int offset = m_busloc+ckCL+1;
|
|
|
tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
|
// printf("Setting bus timeslots from (now=%d)+%d=%d to now+%d+3\n", m_busloc, ckCL,(m_busloc+ckCL)&(NTIMESLOTS-1), ckCL);
|
// printf("Setting bus timeslots from (now=%d)+%d=%d to now+%d+3\n", m_busloc, ckCL,(m_busloc+ckCL)&(NTIMESLOTS-1), ckCL);
|
tp->m_addr = caddr ;
|
tp->m_addr = caddr ;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 0;
|
tp->m_read = 0;
|
|
|
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
|
tp->m_addr = caddr+1;
|
tp->m_addr = caddr+1;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 0;
|
tp->m_read = 0;
|
|
|
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
|
tp->m_addr = caddr+2;
|
tp->m_addr = caddr+2;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 0;
|
tp->m_read = 0;
|
|
|
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
|
tp->m_addr = caddr+3;
|
tp->m_addr = caddr+3;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 0;
|
tp->m_read = 0;
|
} break;
|
} break;
|
case DDR_READ:
|
case DDR_READ:
|
{
|
{
|
// This SIM doesn't handle out of order reads
|
// This SIM doesn't handle out of order reads
|
assert((addr&7)==0);
|
assert((addr&7)==0);
|
m_bank[ba].tick(DDR_READ, addr);
|
m_bank[ba].tick(DDR_READ, addr);
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
|
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
|
unsigned caddr = m_bank[ba].m_row;
|
unsigned caddr = m_bank[ba].m_row;
|
caddr <<= 3;
|
caddr <<= 3;
|
caddr |= ba;
|
caddr |= ba;
|
caddr <<= 10;
|
caddr <<= 10;
|
caddr |= addr;
|
caddr |= addr;
|
caddr &= ~7;
|
caddr &= ~7;
|
caddr >>= 1;
|
caddr >>= 1;
|
|
|
BUSTIMESLOT *tp;
|
BUSTIMESLOT *tp;
|
|
|
int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
|
int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
|
tp = &m_bus[(offset)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset)&(NTIMESLOTS-1)];
|
tp->m_data = m_mem[caddr];
|
tp->m_data = m_mem[caddr];
|
tp->m_addr = caddr;
|
tp->m_addr = caddr;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 1;
|
tp->m_read = 1;
|
|
|
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
|
tp->m_data = m_mem[caddr+1];
|
tp->m_data = m_mem[caddr+1];
|
tp->m_addr = caddr+1;
|
tp->m_addr = caddr+1;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 1;
|
tp->m_read = 1;
|
|
|
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
|
tp->m_data = m_mem[caddr+2];
|
tp->m_data = m_mem[caddr+2];
|
tp->m_addr = caddr+2;
|
tp->m_addr = caddr+2;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 1;
|
tp->m_read = 1;
|
|
|
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
|
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
|
tp->m_data = m_mem[caddr+3];
|
tp->m_data = m_mem[caddr+3];
|
tp->m_addr = caddr+3;
|
tp->m_addr = caddr+3;
|
tp->m_used = 1;
|
tp->m_used = 1;
|
tp->m_read = 1;
|
tp->m_read = 1;
|
} break;
|
} break;
|
case DDR_ZQS:
|
case DDR_ZQS:
|
assert(0&&"Sim does not support ZQS outside of startup");
|
assert(0&&"Sim does not support ZQS outside of startup");
|
break;
|
break;
|
case DDR_NOOP:
|
case DDR_NOOP:
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_NOOP,addr);
|
m_bank[i].tick(DDR_NOOP,addr);
|
break;
|
break;
|
default: // We are deselecteda
|
default: // We are deselecteda
|
for(int i=0; i<NBANKS; i++)
|
for(int i=0; i<NBANKS; i++)
|
m_bank[i].tick(DDR_NOOP,addr);
|
m_bank[i].tick(DDR_NOOP,addr);
|
break;
|
break;
|
}
|
}
|
|
|
|
if (true) {
|
|
bool flag = false;
|
|
for(int i=0; i<5; i++) {
|
|
int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
|
|
nxtts = &m_bus[bl];
|
|
if (nxtts->m_used) {
|
|
flag = true;
|
|
break;
|
|
}
|
|
} if (flag) {
|
|
printf("DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
|
|
for(int i=0; i<5; i++) {
|
|
int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
|
|
nxtts = &m_bus[bl];
|
|
printf("BUS[%2d] ", bl);
|
|
if (nxtts->m_used)
|
|
printf(" USED");
|
|
if (nxtts->m_read)
|
|
printf(" READ");
|
|
if (nxtts->m_rtt)
|
|
printf(" RTT");
|
|
printf("\n");
|
|
}}
|
|
}
|
|
|
|
ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
|
if (dqs)
|
|
assert((ts->m_rtt)&&(m_last_rtt));
|
|
else if (!m_last_dqs)
|
|
assert(!m_last_rtt);
|
}
|
}
|
|
|
m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
|
m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
|
|
|
BUSTIMESLOT *ts = &m_bus[m_busloc];
|
ts = &m_bus[m_busloc];
|
|
nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
unsigned vl = ts->m_data;
|
unsigned vl = ts->m_data;
|
assert( ((!ts->m_used)||(busoe))
|
assert( ((!ts->m_used)||(busoe))
|
|| ((ts->m_used)&&(ts->m_read)));
|
|| ((ts->m_used)&&(ts->m_read)&&(!busoe))
|
|
|| ((ts->m_used)&&(!ts->m_read)&&(busoe))
|
|
);
|
|
|
|
m_last_dqs = dqs;
|
|
m_last_rtt = ts->m_rtt;
|
|
|
|
if (ts->m_used) {
|
|
if (ts->m_read)
|
|
assert((!dqs)&&(!m_last_dqs));
|
|
else
|
|
assert((dqs) && (m_last_dqs));
|
|
} else if (!nxtts->m_used)
|
|
assert(!dqs);
|
|
|
assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
|
assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
|
if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
|
if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
|
printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
|
printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
|
m_mem[ts->m_addr] = data;
|
m_mem[ts->m_addr] = data;
|
}
|
}
|
|
|
|
m_bus[(m_busloc+3)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
|
ts->m_used = 0;
|
ts->m_used = 0;
|
ts->m_read = 0;
|
ts->m_read = 0;
|
ts->m_addr = -1;
|
ts->m_addr = -1;
|
|
ts->m_rtt = 0;
|
return (!busoe)?vl:data;
|
return (!busoe)?vl:data;
|
}
|
}
|
|
|
|
|