Line 39... |
Line 39... |
#include <assert.h>
|
#include <assert.h>
|
|
|
#include "ddrsdramsim.h"
|
#include "ddrsdramsim.h"
|
|
|
#define PREFIX "DDR3-SDRAM"
|
#define PREFIX "DDR3-SDRAM"
|
const unsigned ckCL = 6,
|
const unsigned
|
|
ckRESET = 64000, // 200us @ 320MHz
|
|
ckCKE = 160000, // 500us @ 320MHz
|
|
ckCL = 5,
|
ckCWL = 5,
|
ckCWL = 5,
|
ckRP = 6,
|
ckRP = 5,
|
ckWR = 6,
|
ckWR = 5,
|
ckRAS = 15,
|
ckRAS = 12,
|
ckRC = 20,
|
ckRC = 16,
|
ckMRD = 4,
|
ckMRD = 4,
|
ckMOD = 12,
|
ckMOD = 12,
|
ckZQinit = 512,
|
ckZQinit = 512,
|
ckODT = ckCWL-2,
|
ckODT = ckCWL-2,
|
ckRFC = 64, // Clocks from refresh to activate
|
ckXPR = 56, // Exit reset clocks from CKE HIGH to valid command
|
ckREFI = 1560*NWIDTH, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
|
ckRFC = 52, // Clocks from refresh to activate
|
|
ckREFI = 2496, // 7.8us @ 320MHz
|
DDR_MR2 = 0x0040 | (((ckCWL-5)&7)<<3),
|
DDR_MR2 = 0x0040 | (((ckCWL-5)&7)<<3),
|
DDR_MR1 = 0x0044,
|
DDR_MR1 = 0x0044,
|
DDR_MR0 = 0x0000 | (((ckCL-4)&0x07)<<4) | ((ckCL>11)?0x4:0)
|
DDR_MR0 = 0x0000 | (((ckCL-4)&0x07)<<4) | ((ckCL>11)?0x4:0)
|
|((ckWR==16)?0
|
|((ckWR==16)?0
|
:(ckWR>=8)?((((ckWR-8)>>1)+8)<<9)
|
:(ckWR>=8)?((((ckWR-8)>>1)+8)<<9)
|
:((ckWR-5+1)<<9)),
|
:((ckWR-5+1)<<9)),
|
|
// Don't pull in any refreshes ...
|
nREF = 1;
|
nREF = 1;
|
|
|
BANKINFO::BANKINFO(void) {
|
BANKINFO::BANKINFO(void) {
|
m_state = 0; m_row = 0; m_wcounter = 0; m_min_time_before_precharge=0;
|
m_state = 0; m_row = 0; m_wcounter = 0; m_min_time_before_precharge=0;
|
}
|
}
|
Line 90... |
Line 95... |
assert(m_min_time_before_activate==0);
|
assert(m_min_time_before_activate==0);
|
}
|
}
|
*/
|
*/
|
break;
|
break;
|
case DDR_ACTIVATE:
|
case DDR_ACTIVATE:
|
assert((m_state&((1<<ckRP)-1)) == 0);
|
// assert((m_state&((1<<ckRP)-1)) == 0);
|
if (((m_state&7)!=0)&&((addr&0x7fff) != m_row)) {
|
if (((m_state&((1<<ckRP)-1))!=0)&&((addr&0x7fff) != m_row)) {
|
printf("BANK-FAIL: Attempt to Activate an already active bank without closing it first (m_state = %x)\n", m_state);
|
printf(PREFIX "::BANK-FAIL: Attempt to Activate an already active bank without closing it first (m_state = %x)\n", m_state);
|
assert((m_state&7)==0);
|
// assert((m_state&((1<<ckRP)-1))==0);
|
|
} else if((m_state&((1<<ckRP)-1)) != 0) {
|
|
printf(PREFIX "::DOUBLE-ACTIVATE!!\n");
|
}
|
}
|
|
|
/*
|
/*
|
if (m_wcounter != 0) {
|
if (m_wcounter != 0) {
|
printf("BANK-FAIL: ACTIVATE too soon after write (wcounter = %d)\n", m_wcounter);
|
printf("BANK-FAIL: ACTIVATE too soon after write (wcounter = %d)\n", m_wcounter);
|
Line 107... |
Line 114... |
assert(m_min_time_before_activate==0);
|
assert(m_min_time_before_activate==0);
|
}
|
}
|
*/
|
*/
|
m_state = 1;
|
m_state = 1;
|
m_row = addr & 0x7fff;
|
m_row = addr & 0x7fff;
|
printf("BANK -- Setting address to %04x\n", m_row);
|
printf(PREFIX "::BANK -- Setting address to %04x\n", m_row);
|
m_min_time_before_precharge = ckRAS;
|
m_min_time_before_precharge = ckRAS;
|
m_min_time_before_activate = ckRC;
|
m_min_time_before_activate = ckRC;
|
break;
|
break;
|
case DDR_READ: case DDR_WRITE:
|
case DDR_READ: case DDR_WRITE:
|
if (DDR_READ)
|
if (DDR_READ)
|
Line 119... |
Line 126... |
else
|
else
|
m_wcounter = 3+4+4;
|
m_wcounter = 3+4+4;
|
if ((m_state&((1<<ckRP)-1)) != ((1<<ckRP)-1)) {
|
if ((m_state&((1<<ckRP)-1)) != ((1<<ckRP)-1)) {
|
printf(PREFIX "::R/W Error: m_state = %08x, ckRP = %d (%08x)\n",
|
printf(PREFIX "::R/W Error: m_state = %08x, ckRP = %d (%08x)\n",
|
m_state, ckRP, ((1<<ckRP)-1));
|
m_state, ckRP, ((1<<ckRP)-1));
|
assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
|
// assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
|
}
|
}
|
if (m_min_time_before_precharge)
|
if (m_min_time_before_precharge)
|
m_min_time_before_precharge--;
|
m_min_time_before_precharge--;
|
if (m_min_time_before_activate)
|
if (m_min_time_before_activate)
|
m_min_time_before_activate--;
|
m_min_time_before_activate--;
|
Line 134... |
Line 141... |
m_min_time_before_precharge--;
|
m_min_time_before_precharge--;
|
if (m_min_time_before_activate)
|
if (m_min_time_before_activate)
|
m_min_time_before_activate--;
|
m_min_time_before_activate--;
|
break;
|
break;
|
case DDR_NOOP:
|
case DDR_NOOP:
|
|
// NO BREAK: Fall through. On a NOOP we do the same
|
|
// as if the chip were de-selected.
|
|
default:
|
m_state <<= 1;
|
m_state <<= 1;
|
m_state |= (m_state&2)>>1;
|
m_state |= (m_state&2)>>1;
|
m_state &= ((1<<ckRP)-1);
|
m_state &= ((1<<ckRP)-1);
|
|
// Else the chip was de-selected, and we only need
|
|
// tick time away -- as in a NOOP.
|
if (m_min_time_before_precharge)
|
if (m_min_time_before_precharge)
|
m_min_time_before_precharge--;
|
m_min_time_before_precharge--;
|
if (m_min_time_before_activate)
|
if (m_min_time_before_activate)
|
m_min_time_before_activate--;
|
m_min_time_before_activate--;
|
break;
|
break;
|
default:
|
|
break;
|
|
}
|
}
|
}
|
}
|
|
|
int gbl_state, gbl_counts;
|
int gbl_state, gbl_counts;
|
|
|
Line 180... |
Line 190... |
// printf(PREFIX "::Reset-CMD = %02x,BA=%d,ADDR=%04x, counts = %d\n", cmd, ba, addr, m_reset_counts);
|
// printf(PREFIX "::Reset-CMD = %02x,BA=%d,ADDR=%04x, counts = %d\n", cmd, ba, addr, m_reset_counts);
|
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*NWIDTH);
|
assert(m_reset_counts >= (int)ckRESET);
|
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*NWIDTH);
|
assert(m_reset_counts >= (int)ckCKE);
|
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)&&(cmd&DDR_DESELECT)==0) {
|
assert(m_reset_counts > (int)(ckRFC+2*NWIDTH));
|
assert(m_reset_counts >= (int)ckXPR);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 3;
|
m_reset_state = 3;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
// Set MR2
|
// Set MR2
|
assert(ba == 2);
|
assert(ba == 2);
|
Line 207... |
Line 217... |
assert(addr == DDR_MR2);
|
assert(addr == DDR_MR2);
|
} break;
|
} break;
|
case 3:
|
case 3:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if ((cmd != DDR_NOOP)&&(cmd&DDR_DESELECT)==0) {
|
assert(m_reset_counts >= (int)ckMRD);
|
assert(m_reset_counts >= (int)ckMRD);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 4;
|
m_reset_state = 4;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
// Set MR1
|
// Set MR1
|
Line 219... |
Line 229... |
assert(addr == DDR_MR1);
|
assert(addr == DDR_MR1);
|
} break;
|
} break;
|
case 4:
|
case 4:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if ((cmd != DDR_NOOP)&&(cmd&DDR_DESELECT)==0) {
|
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 >= (int)ckMRD);
|
assert(m_reset_counts >= (int)ckMRD);
|
m_reset_counts = 0;
|
m_reset_counts = 0;
|
m_reset_state = 5;
|
m_reset_state = 5;
|
assert(cmd == DDR_MRSET);
|
assert(cmd == DDR_MRSET);
|
Line 232... |
Line 242... |
assert(addr == DDR_MR0);
|
assert(addr == DDR_MR0);
|
} break;
|
} break;
|
case 5:
|
case 5:
|
m_reset_counts++;
|
m_reset_counts++;
|
assert(cke);
|
assert(cke);
|
if (cmd != DDR_NOOP) {
|
if ((cmd != DDR_NOOP)&&(cmd&DDR_DESELECT)==0) {
|
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 >= (int)ckMOD);
|
assert(m_reset_counts >= (int)ckMOD);
|
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)&&(cmd&DDR_DESELECT)==0) {
|
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 >= (int)ckZQinit);
|
assert(m_reset_counts >= (int)ckZQinit);
|
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)&&(cmd&DDR_DESELECT)==0) {
|
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 >= (int)ckRP);
|
assert(m_reset_counts >= (int)ckRP);
|
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)||(cmd&DDR_DESELECT));
|
if (m_reset_counts > (int)ckRFC) {
|
if (m_reset_counts > (int)ckRFC) {
|
m_reset_state = 16;
|
m_reset_state = 16;
|
printf(PREFIX ": Leaving reset state\n");
|
printf(PREFIX ": Leaving reset state\n");
|
}
|
}
|
break;
|
break;
|
Line 433... |
Line 443... |
} 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++)
|
default: // We are deselected
|
m_bank[i].tick(DDR_NOOP,addr);
|
|
break;
|
|
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;
|
}
|
}
|
|
|
Line 469... |
Line 476... |
}}
|
}}
|
}
|
}
|
|
|
ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
if (dqs) {
|
if (dqs) {
|
/*
|
if ((!ts->m_rtt)||(!m_last_rtt)) {
|
if ((!ts->m_rtt)||(!m_last_rtt)) {
|
printf(PREFIX "ODT(dqs is true) m_rtt is %s and last_rtt is %s. Both should be true if DQS. (ERROR!)\n",
|
printf(PREFIX "ODT(dqs is true) m_rtt is %s and last_rtt is %s. Both should be true if DQS. (ERROR!)\n",
|
(ts->m_rtt)?"true":"false",
|
(ts->m_rtt)?"true":"false",
|
(m_last_rtt)?"true":"false");
|
(m_last_rtt)?"true":"false");
|
}
|
} */
|
|
assert((ts->m_rtt)&&(m_last_rtt));
|
assert((ts->m_rtt)&&(m_last_rtt));
|
} else if (!m_last_dqs)
|
} // else if (!m_last_dqs)
|
assert(!m_last_rtt);
|
// assert(!m_last_rtt);
|
}
|
}
|
|
|
m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
|
m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
|
|
|
ts = &m_bus[m_busloc];
|
ts = &m_bus[m_busloc];
|
nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
|
unsigned vl = ts->m_data;
|
unsigned vl = ts->m_data;
|
|
|
assert( ((!ts->m_used)||(busoe))
|
/*
|
|| ((ts->m_used)&&(ts->m_read)&&(!busoe))
|
assert( ((!ts->m_used)||(busoe))
|
|| ((ts->m_used)&&(!ts->m_read)&&(busoe))
|
|| ((ts->m_used)&&(ts->m_read)&&(!busoe))
|
);
|
|| ((ts->m_used)&&(!ts->m_read)&&(busoe))
|
|
);
|
|
*/
|
|
|
m_last_dqs = dqs;
|
m_last_dqs = dqs;
|
m_last_rtt = ts->m_rtt;
|
m_last_rtt = ts->m_rtt;
|
|
|
if (ts->m_used) {
|
/*
|
if (ts->m_read)
|
if (ts->m_used) {
|
assert((!dqs)&&(!m_last_dqs));
|
if (ts->m_read)
|
else
|
assert((!dqs)&&(!m_last_dqs));
|
assert((dqs) && (m_last_dqs));
|
else
|
} else if (!nxtts->m_used)
|
assert((dqs) && (m_last_dqs));
|
assert(!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 != 0x0f)) {
|
if ((ts->m_used)&&(!ts->m_read)&&(dm != 0x0f)) {
|
printf(PREFIX "::Setting MEM[%08x] = %08x (%02x)\n", ts->m_addr, data, dm);
|
printf(PREFIX "::Setting MEM[%08x] = %08x (%02x)\n", ts->m_addr, data, dm);
|
unsigned mask = 0;
|
unsigned mask = 0;
|
if (dm&0x08) mask = 0x0ff;
|
if (dm&0x08) mask = 0x0ff;
|
mask <<= 8; if (dm&0x004) mask |= 0x0ff;
|
mask <<= 8; if (dm&0x004) mask |= 0x0ff;
|