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

Subversion Repositories wbddr3

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /wbddr3/trunk
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/bench/cpp/ddrsdramsim.h
0,0 → 1,81
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddrsdramsim.h
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef DDRSDRAMSIM_H
#define DDRSDRAMSIM_H
 
#define DDR_MRSET 0
#define DDR_REFRESH 1
#define DDR_PRECHARGE 2
#define DDR_ACTIVATE 3
#define DDR_WRITE 4
#define DDR_READ 5
#define DDR_ZQS 6
#define DDR_NOOP 7
 
#define NBANKS 8
#define NTIMESLOTS 16
 
class BANKINFO {
public:
int m_state;
unsigned m_row;
void tick(int cmd, unsigned addr=0);
};
 
class BUSTIMESLOT {
public:
int m_used, m_read, m_data;
unsigned m_addr;
};
 
class DDRSDRAMSIM {
int m_reset_state, m_reset_counts, m_memlen, m_busloc;
unsigned *m_mem;
BANKINFO m_bank[8];
BUSTIMESLOT *m_bus;
int cmd(int,int,int,int);
public:
DDRSDRAMSIM(int lglen);
unsigned operator()(int, int,
int, int, int, int,
int, int, int, int,
int, int, int);
unsigned &operator[](unsigned addr) { return m_mem[addr]; };
};
 
#endif
/bench/cpp/ddrsdram_tb.cpp
0,0 → 1,444
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddrsdram_tb.cpp
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: To determine whether or not the wbddrsdram Verilog module works.
// Run this program with no arguments. If the last line output
// is "SUCCESS", you will know it works.
//
// 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 "verilated.h"
#include "Vwbddrsdram.h"
#include "ddrsdramsim.h"
 
const int BOMBCOUNT = 2048,
SDRAMMASK = 0x3ffffff,
LGMEMSIZE = 28;
 
class DDRSDRAM_TB {
long m_tickcount;
Vwbddrsdram *m_core;
DDRSDRAMSIM *m_sdram;
bool m_bomb;
public:
 
DDRSDRAM_TB(void) {
m_core = new Vwbddrsdram;
m_sdram= new DDRSDRAMSIM(LGMEMSIZE);
}
 
unsigned &operator[](const int index) { return (*m_sdram)[index]; }
void set(unsigned addr, unsigned v) {
(*m_sdram)[addr] = v;
}
 
void tick(void) {
m_core->i_clk = 1;
 
m_core->i_ddr_data = (*m_sdram)(
m_core->o_ddr_reset_n,
m_core->o_ddr_cke,
m_core->o_ddr_cs_n,
m_core->o_ddr_ras_n,
m_core->o_ddr_cas_n,
m_core->o_ddr_we_n,
m_core->o_ddr_dqs,
m_core->o_ddr_dm,
m_core->o_ddr_odt,
m_core->o_ddr_bus_oe,
m_core->o_ddr_addr,
m_core->o_ddr_ba,
m_core->o_ddr_data);
 
printf("%08lx-WB: %s/%s %s%s%s %s@0x%08x[%08x/%08x] -- ",
m_tickcount,
(m_core->i_wb_cyc)?"CYC":" ",
(m_core->i_wb_stb)?"STB":" ",
(m_core->o_wb_stall)?"STALL":" ",
(m_core->o_wb_ack)?"ACK":" ",
(m_core->o_cmd_accepted)?"BUS":" ",
(m_core->i_wb_we)?"W":"R",
(m_core->i_wb_addr),
(m_core->i_wb_data),
(m_core->o_wb_data));
 
printf("%s%s %d%d%d%d %s%s%s%s B[%d]@%04x %08x %08x",
(m_core->o_ddr_reset_n)?" ":"R",
(m_core->o_ddr_cke)?"CK":" ",
(m_core->o_ddr_cs_n),
(m_core->o_ddr_ras_n),
(m_core->o_ddr_cas_n),
(m_core->o_ddr_we_n),
//
(m_core->o_ddr_dqs)?"D":" ",
(m_core->o_ddr_dm)?"M":" ",
(m_core->o_ddr_odt)?"O":" ",
(m_core->o_ddr_bus_oe)?"E":" ",
//
(m_core->o_ddr_ba),
(m_core->o_ddr_addr),
(m_core->i_ddr_data),
(m_core->o_ddr_data));
 
// Reset logic
printf(" RST(%06x%s[%d] - %08x->%08x)",
m_core->v__DOT__reset_timer,
(m_core->v__DOT__reset_ztimer)?"Z":" ",
(m_core->v__DOT__reset_address),
(m_core->v__DOT__reset_instruction),
(m_core->v__DOT__reset_cmd));
 
extern int gbl_state, gbl_counts;
printf(" %d:%08x ", gbl_state, gbl_counts);
 
if (m_core->v__DOT__reset_override)
printf(" OVERRIDE");
printf("\n");
 
m_core->eval();
m_core->i_clk = 0;
m_core->eval();
 
m_tickcount++;
 
/*
if ((m_core->o_wb_ack)&&(!m_core->i_wb_cyc)) {
printf("SETTING ERR TO TRUE!!!!! ACK w/ no CYC\n");
// m_bomb = true;
}
*/
}
 
void reset(void) {
m_core->i_reset = 1;
m_core->i_wb_cyc = 0;
m_core->i_wb_stb = 0;
tick();
m_core->i_reset = 0;
}
 
void wb_tick(void) {
m_core->i_wb_cyc = 0;
m_core->i_wb_stb = 0;
tick();
}
 
unsigned wb_read(unsigned a) {
int errcount = 0;
unsigned result;
 
printf("WB-READ(%08x)\n", a);
 
m_core->i_wb_cyc = 1;
m_core->i_wb_stb = 1;
m_core->i_wb_we = 0;
m_core->i_wb_addr= a & SDRAMMASK;
 
if (m_core->o_wb_stall) {
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall))
tick();
} else
tick();
 
m_core->i_wb_stb = 0;
 
while((errcount++ < BOMBCOUNT)&&(!m_core->o_wb_ack))
tick();
 
 
result = m_core->o_wb_data;
 
// Release the bus?
m_core->i_wb_cyc = 0;
m_core->i_wb_stb = 0;
 
if(errcount >= BOMBCOUNT) {
printf("SETTING ERR TO TRUE!!!!!\n");
m_bomb = true;
} else if (!m_core->o_wb_ack) {
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
m_bomb = true;
}
tick();
 
return result;
}
 
void wb_read(unsigned a, int len, unsigned *buf) {
int errcount = 0;
int THISBOMBCOUNT = BOMBCOUNT * len;
int cnt, rdidx, inc;
 
printf("WB-READ(%08x, %d)\n", a, len);
 
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall))
wb_tick();
 
if (errcount >= BOMBCOUNT) {
m_bomb = true;
return;
}
 
errcount = 0;
m_core->i_wb_cyc = 1;
m_core->i_wb_stb = 1;
m_core->i_wb_we = 0;
m_core->i_wb_addr= a & SDRAMMASK;
 
rdidx =0; cnt = 0;
inc = 1;
 
do {
int s;
s = (m_core->o_wb_stall==0)?0:1;
tick();
if (!s)
m_core->i_wb_addr += inc;
cnt += (s==0)?1:0;
if (m_core->o_wb_ack)
buf[rdidx++] = m_core->o_wb_data;
} while((cnt < len)&&(errcount++ < THISBOMBCOUNT));
 
m_core->i_wb_stb = 0;
 
while((rdidx < len)&&(errcount++ < THISBOMBCOUNT)) {
tick();
if (m_core->o_wb_ack)
buf[rdidx++] = m_core->o_wb_data;
}
 
// Release the bus?
m_core->i_wb_cyc = 0;
 
if(errcount >= THISBOMBCOUNT) {
printf("SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", errcount, THISBOMBCOUNT);
m_bomb = true;
} else if (!m_core->o_wb_ack) {
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
m_bomb = true;
}
tick();
}
 
void wb_write(unsigned a, unsigned int v) {
int errcount = 0;
 
printf("WB-WRITE(%08x) = %08x\n", a, v);
m_core->i_wb_cyc = 1;
m_core->i_wb_stb = 1;
m_core->i_wb_we = 1;
m_core->i_wb_addr= a & SDRAMMASK;
m_core->i_wb_data= v;
 
if (m_core->o_wb_stall)
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall))
tick();
tick();
 
m_core->i_wb_stb = 0;
 
while((errcount++ < BOMBCOUNT)&&(!m_core->o_wb_ack))
tick();
 
// Release the bus?
m_core->i_wb_cyc = 0;
m_core->i_wb_stb = 0;
 
if(errcount >= BOMBCOUNT) {
printf("SETTING ERR TO TRUE!!!!!\n");
m_bomb = true;
} tick();
}
 
void wb_write(unsigned a, unsigned int ln, unsigned int *buf) {
unsigned errcount = 0, nacks = 0;
 
m_core->i_wb_cyc = 1;
m_core->i_wb_stb = 1;
for(unsigned stbcnt=0; stbcnt<ln; stbcnt++) {
m_core->i_wb_we = 1;
m_core->i_wb_addr= (a+stbcnt) & SDRAMMASK;
m_core->i_wb_data= buf[stbcnt];
errcount = 0;
 
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall)) {
tick(); if (m_core->o_wb_ack) nacks++;
}
// Tick, now that we're not stalled. This is the tick
// that gets accepted.
tick(); if (m_core->o_wb_ack) nacks++;
}
 
m_core->i_wb_stb = 0;
 
errcount = 0;
while((nacks < ln)&&(errcount++ < BOMBCOUNT)) {
tick();
if (m_core->o_wb_ack) {
nacks++;
errcount = 0;
}
}
 
// Release the bus
m_core->i_wb_cyc = 0;
m_core->i_wb_stb = 0;
 
if(errcount >= BOMBCOUNT) {
printf("SETTING ERR TO TRUE!!!!!\n");
m_bomb = true;
} tick();
}
 
bool bombed(void) const { return m_bomb; }
 
};
 
void uload(unsigned len, unsigned *buf) {
FILE *fp = fopen("/dev/urandom", "r");
 
if ((NULL == fp)||(len != fread(buf, sizeof(unsigned), len, fp))) {
for(int i=0; i<(int)len; i++)
buf[i] = rand();
} if (NULL == fp)
fclose(fp);
}
 
int main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
DDRSDRAM_TB *tb = new DDRSDRAM_TB;
unsigned *rdbuf, *mbuf;
int nw = 3, nr = 13;
unsigned mlen = (1<<(LGMEMSIZE-2));
 
printf("Giving the core 140k cycles to start up\n");
// Before testing, let's give the unit time enough to warm up
tb->reset();
for(int i=0; i<140850; i++)
tb->wb_tick();
 
printf("Getting some memory ...\n");
rdbuf = new unsigned[mlen];
mbuf = new unsigned[mlen]; // Match buffer
printf("Charging my memory with random values\n");
uload(mlen, rdbuf);
 
// First test: singular reads through the memory, followed by
// singular writes
printf("Starting the single-read test\n");
for(int i=0; i<(int)mlen; i++) {
tb->wb_write(i, rdbuf[i]);
tb->wb_tick();
if ((*tb)[i] != rdbuf[i]) {
printf("WRITE[%06x] = %08x (Expecting %08x) FAILED\n",
i, (*tb)[i], rdbuf[i]);
goto test_failure;
} if (tb->bombed())
goto test_failure;
 
} for(int i=0; i<(int)mlen; i++) {
unsigned v;
if (rdbuf[i] != (v=tb->wb_read(i))) {
printf("READ[%06x] = %08x (Expecting %08x)\n",
i, v, rdbuf[i]);
goto test_failure;
} if (tb->bombed())
goto test_failure;
tb->wb_tick();
}
 
// Second test: Vector writes going through all memory, followed a
// massive vector read
uload(mlen, rdbuf); // Get some new values
tb->wb_write(0, mlen, rdbuf);
if (tb->bombed())
goto test_failure;
for(int i=0; i<(int)mlen; i++) {
unsigned v;
if (rdbuf[i] != (v=(*tb)[i])) {
printf("V-WRITE[%06x] = %08x (Expecting %08x)\n",
i, v, rdbuf[i]);
goto test_failure;
}
}
 
tb->wb_read( 0, mlen, mbuf);
if (tb->bombed())
goto test_failure;
for(int i=0; i<(int)mlen; i++) {
if (rdbuf[i] != mbuf[i]) {
printf("V-READ[%06x] = %08x (Expecting %08x)\n",
i, mbuf[i], rdbuf[i]);
goto test_failure;
}
}
 
// Third test: Vector writes going through all memory, an prime number
// of values at a time, followed by reads via a different prime number
for(int i=0; i<(int)mlen; i+=nw) {
int ln = ((int)mlen-i>nw)?nw:mlen-i;
tb->wb_write(i, nw, &rdbuf[i]);
for(int j=0; j<ln; j++) {
if ((*tb)[i+j] != rdbuf[i+j]) {
printf("P-WRITE[%06x] = %08x (Expecting %08x) FAILED\n",
i, (*tb)[i], rdbuf[i]);
goto test_failure;
}
} if (tb->bombed())
goto test_failure;
} for(int i=0; i<(int)mlen; i+=nr) {
int ln = ((int)mlen-i>nr)?nr:mlen-i;
tb->wb_write(i, nr, &mbuf[i]);
for(int j=0; j<ln; j++) {
if (mbuf[i+j] != rdbuf[i+j]) {
printf("P-READ[%06x] = %08x (Expecting %08x) FAILED\n",
i, mbuf[i], rdbuf[i]);
goto test_failure;
}
} if (tb->bombed())
goto test_failure;
}
 
 
printf("SUCCESS!!\n");
exit(0);
test_failure:
printf("FAIL-HERE\n");
for(int i=0; i<64; i++)
tb->tick();
printf("TEST FAILED\n");
exit(-1);
}
/bench/cpp/ddrsdramsim.cpp
0,0 → 1,307
////////////////////////////////////////////////////////////////////////////////
//
// 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;
 
#include "ddrsdramsim.h"
void BANKINFO::tick(int cmd, unsigned addr) {
switch(cmd) {
case DDR_PRECHARGE:
m_state <<= 1;
// m_state |= 1;
m_state &= 6;
break;
case DDR_ACTIVATE:
m_state <<= 1;
m_state |= 1;
m_state &= 7;
m_row = addr & 0x7fff;
break;
case DDR_READ: case DDR_WRITE:
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++;
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++;
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++;
if (cmd != DDR_NOOP) {
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++;
if (cmd != DDR_NOOP) {
assert(m_reset_counts > 12);
m_reset_counts = 0;
m_reset_state = 6;
assert(cmd == DDR_ZQS);
assert(addr == 0x40);
} break;
case 6:
m_reset_counts++;
if (cmd != DDR_NOOP) {
assert(m_reset_counts > 512);
m_reset_counts = 0;
m_reset_state = 7;
assert(cmd == DDR_PRECHARGE);
assert(addr == 0x40);
} break;
case 7:
m_reset_counts++;
if (cmd != DDR_NOOP) {
assert(m_reset_counts > 3);
m_reset_counts = 0;
m_reset_state = 8;
assert(cmd == DDR_REFRESH);
} break;
case 8:
m_reset_counts++;
assert(cmd == DDR_NOOP);
if (m_reset_counts > 140)
m_reset_state = 16;
break;
default:
break;
}
 
gbl_state = m_reset_state;
gbl_counts= m_reset_counts;
} else if (cke == 0) {
assert(0&&"Clock not enabled!");
} else 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);
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:
{
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_WRITE,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:
{
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_READ,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;
}
 
/bench/cpp/Makefile
0,0 → 1,71
################################################################################
##
## Filename: Makefile
##
## Project: A wishbone controlled DDR3 SDRAM memory controller.
##
## Purpose: This coordinates the build of the singular test bench C++
## program found in this directory: ddrsdram_tb.
##
## 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
##
##
################################################################################
##
##
all: $(OBJDIR)/ ddrsdram_tb
 
CXX := g++
OBJDIR := obj-pc
YYMMDD := `date +%Y%m%d`
RTLD := ../../rtl
VOBJDR := $(RTLD)/obj_dir
VROOT := /usr/share/verilator
VINC := -I$(VROOT)/include -I$(VOBJDR)
CFLAGS := -Wall -c -Og -g -I. $(VINC)
SOURCES := ddrsdramsim.cpp ddrsdram_tb.cpp
VOBJDR := $(RTLD)/obj_dir
VLIB := $(VROOT)/include/verilated.cpp
 
$(OBJDIR)/:
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
 
$(OBJDIR)/ddrsdramsim.o: ddrsdramsim.cpp ddrsdramsim.h $(VOBJDR)/Vwbddrsdram.h
$(CXX) $(CFLAGS) ddrsdramsim.cpp -o $@
$(OBJDIR)/verilated.o: $(VLIB) $(OBJDIR)/
$(CXX) $(CFLAGS) $(VLIB) -o $@
$(OBJDIR)/ddrsdram_tb.o: ddrsdram_tb.cpp ddrsdramsim.h $(VOBJDR)/Vwbddrsdram.h
$(CXX) $(CFLAGS) ddrsdram_tb.cpp -o $@
 
OBJECTS := ddrsdramsim.o ddrsdram_tb.o verilated.o
OBJECTSDR:= $(addprefix $(OBJDIR)/,$(OBJECTS))
ddrsdram_tb: $(OBJECTSDR) $(VOBJDR)/Vwbddrsdram__ALL.a
$(CXX) -Wall $(INCS) $^ -o $@
 
.PHONY: clean
clean:
rm -rf $(OBJDIR)/ ddrsdram_tb
 
/rtl/wbddrsdram.v
44,6 → 44,7
`define DDR_ACTIVATE 4'b0011
`define DDR_WRITE 4'b0100
`define DDR_READ 4'b0101
`define DDR_ZQS 4'b0110
`define DDR_NOOP 4'b0111
//`define DDR_DESELECT 4'b1???
//
68,10 → 69,12
o_wb_ack, o_wb_stall, o_wb_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_dir,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_oe,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data,
o_cmd_accepted);
parameter CKREFI4 = 13'd6240, // 4 * 7.8us at 200 MHz clock
CKRFC = 140;
CKRFC = 140,
CKXPR = CKRFC+5+2; // Clocks per tXPR timeout
input i_clk, i_reset;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
87,7 → 90,7
output reg o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
// DQS outputs:set to 3'b010 when data is active, 3'b100 (i.e. 2'bzz) ow
output wire o_ddr_dqs;
output reg o_ddr_dm, o_ddr_odt, o_ddr_bus_dir;
output reg o_ddr_dm, o_ddr_odt, o_ddr_bus_oe;
// Address outputs
output reg [13:0] o_ddr_addr;
output reg [2:0] o_ddr_ba;
94,7 → 97,12
// And the data inputs and outputs
output reg [31:0] o_ddr_data;
input i_ddr_data;
// And just for the test bench
output reg o_cmd_accepted;
 
always @(posedge i_clk)
o_cmd_accepted <= (i_wb_stb)&&(~o_wb_stall);
 
reg drive_dqs;
 
// The pending transaction
174,13 → 182,8
;
else if (reset_instruction[`DDR_RSTDONE])
reset_override <= 1'b0;
else if (reset_instruction[`DDR_RSTTIMER])
begin
if (reset_instruction[`DDR_NOPTIMER])
reset_cmd <= { `DDR_NOOP, reset_instruction[18:0]};
end else begin
else
reset_cmd <= reset_instruction[22:0];
end
always @(posedge i_clk)
if (i_reset)
o_ddr_cke <= 1'b0;
187,13 → 190,13
else if ((reset_override)&&(reset_ztimer))
o_ddr_cke <= reset_instruction[`DDR_CKEBIT];
 
initial reset_ztimer = 1'b1; // Is the timer zero?
initial reset_timer = 17'h00;
initial reset_ztimer = 1'b0; // Is the timer zero?
initial reset_timer = 17'h01;
always @(posedge i_clk)
if (i_reset)
begin
reset_ztimer <= 1'b0;
reset_timer <= 17'h00;
reset_timer <= 17'd1;
end else if (!reset_ztimer)
begin
reset_ztimer <= (reset_timer == 17'h01);
204,22 → 207,74
reset_timer <= reset_instruction[16:0];
end
wire [18:0] w_ckXPR = CKXPR, w_ckRST = 4, w_ckRP = 3,
w_ckRFC = CKRFC;
always @(posedge i_clk)
case(reset_address) // RSTDONE, TIMER, CKE, ??
if (i_reset)
reset_instruction <= { 4'h4, `DDR_NOOP, 19'd40_000 };
else case(reset_address) // RSTDONE, TIMER, CKE, ??
// 1. Reset asserted (active low) for 200 us. (@200MHz)
4'h0: reset_instruction <= { 4'h4, `DDR_NOOP, 19'd40_000 };
// 2. Reset de-asserted, wait 500 us before asserting CKE
4'h1: reset_instruction <= { 4'h6, `DDR_NOOP, 19'd100_000 };
4'h2: reset_instruction <= { 4'h7, `DDR_NOOP, 19'd40_000 };
4'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0, 3'h0, 1'b0, 3'h1, 1'b0, 1'b0, 3'h1, 1'b0, 1'b0, 2'b00 }; // MRS
4'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 19'd40_000 };
4'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2, 5'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2
4'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 19'd40_000 };
4'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1, 3'h0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 2'b0, 1'b1, 1'b0, 2'b0, 1'b1, 1'b1, 1'b0 }; // MRS1
// 3. Assert CKE, wait minimum of Reset CKE Exit time
4'h2: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckXPR };
// 4. Look MR2. (1CK, no TIMER)
4'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2,
5'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2
// 3. Wait 4 clocks (tMRD)
4'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h04 };
// 5. Set MR1
4'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1,
3'h0, // Reserved for Future Use (RFU)
1'b0, // Qoff - output buffer enabled
1'b1, // TDQS ... enabled
1'b0, // RFU
1'b0, // High order bit, Rtt_Nom (3'b011)
1'b0, // RFU
//
1'b0, // Disable write-leveling
1'b1, // Mid order bit of Rtt_Nom
1'b0, // High order bit of Output Drvr Impedence Ctrl
2'b0, // Additive latency = 0
1'b1, // Low order bit of Rtt_Nom
1'b1, // DIC set to 2'b01
1'b1 }; // MRS1, DLL enable
// 7. Wait another 4 clocks
4'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h04 };
// 8. Send MRS0
4'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0,
3'b0, // Reserved for future use
1'b0, // PPD control, (slow exit(DLL off))
3'b1, // Write recovery for auto precharge
1'b0, // DLL Reset (No)
//
1'b0, // TM mode normal
3'b01, // High 3-bits, CAS latency (=4'b0010 = 4'd5)
1'b0, // Read burst type = nibble sequential
1'b0, // Low bit of cas latency
2'b0 }; // Burst length = 8 (Fixed)
// 9. Wait tMOD, is max(12 clocks, 15ns)
4'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 19'h0c };
// 10. Issue a ZQCL command to start ZQ calibration, A10 is high
4'h9: reset_instruction <= { 4'h7, `DDR_ZQS, 8'h0, 1'b1, 10'h0};
//11.Wait for both tDLLK and tZQinit completed, both are 512 cks
4'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 19'd512 };
// 12. Precharge all command
4'hb: reset_instruction <= { 4'h7, `DDR_PRECHARGE, 8'h0, 1'b1, 10'h0 };
// 13. Wait for the precharge to complete
4'hc: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP };
// 14. A single Auto Refresh commands
4'hd: reset_instruction <= { 4'h7, `DDR_REFRESH, 19'h00 };
// 15. Wait for the auto refresh to complete
4'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC };
// Two Auto Refresh commands
default:
reset_instruction <={4'hb, `DDR_NOOP, 19'd00_000 };
endcase
// reset_instruction <= reset_mem[reset_address];
 
initial reset_address = 4'h0;
always @(posedge i_clk)
if (i_reset)
reset_address <= 4'h0;
388,7 → 443,8
bus_subaddr[2] <= bus_subaddr[1];
bus_subaddr[1] <= bus_subaddr[0];
bus_subaddr[0] <= 2'h3;
if (cmd[22:19] == `DDR_READ)
if ((!reset_override)&&(!need_refresh)&&(!need_close_bank)
&&(!need_open_bank)&&(valid_bank))
begin
bus_active[3:0]<= 4'hf; // Once per clock
bus_read[3:0] <= 4'hf; // These will be reads
395,13 → 451,8
bus_subaddr[3] <= 2'h0;
bus_subaddr[2] <= 2'h1;
bus_subaddr[1] <= 2'h2;
end else if (cmd == `DDR_WRITE)
begin
bus_active[3:0] <= 4'hf;
// bus_read[7:4] = 4'h0;
bus_subaddr[3] <= 2'h0;
bus_subaddr[2] <= 2'h1;
bus_subaddr[1] <= 2'h2;
 
bus_read[3:0] <= (r_we)? 4'h0:4'hf;
end
end
 
432,7 → 483,7
r_data <= i_wb_data;
r_row <= i_wb_addr[25:11];
r_bank <= i_wb_addr[10:8];
r_col <= { i_wb_addr[7:2], 2'b00 }; // 9:2
r_col <= { i_wb_addr[7:0], 2'b00 }; // 9:2
r_sub <= i_wb_addr[1:0];
 
// pre-emptive work
464,7 → 515,7
 
close_bank_cmd <= (maybe_close_next_bank)
? { `DDR_PRECHARGE, r_nxt_bank, r_nxt_row[14:10], 1'b0, r_nxt_row[9:0] }
: { `DDR_PRECHARGE, r_bank, r_row[15:11], 1'b0, r_row[9:0] };
: { `DDR_PRECHARGE, r_bank, r_row[14:10], 1'b0, r_row[9:0] };
 
 
need_open_bank <= (r_pending)&&(bank_active[r_bank][1:0]==2'b00)
523,9 → 574,15
// Okay, let's look at the last assignment in our chain. It should look
// something like:
always @(posedge i_clk)
o_ddr_reset_n <= (~reset_override)||(reset_instruction[`DDR_RSTBIT]);
if (i_reset)
o_ddr_reset_n <= 1'b0;
else if (reset_ztimer)
o_ddr_reset_n <= reset_instruction[`DDR_RSTBIT];
always @(posedge i_clk)
o_ddr_cke <= (~reset_override)||(reset_instruction[`DDR_CKEBIT]);
if (i_reset)
o_ddr_cke <= 1'b0;
else if (reset_ztimer)
o_ddr_cke <= reset_instruction[`DDR_CKEBIT];
always @(posedge i_clk)
begin
r_move <= 1'b0;
543,7 → 600,7
cmd <= rw_cmd;
r_move <= 1'b1;
end else
cmd <= { `DDR_NOOP, rw_cmd[20:0] };
cmd <= { `DDR_NOOP, rw_cmd[(`DDR_WEBIT-1):0] };
end
 
reg [31:0] bus_data[8:0];
561,8 → 618,11
 
// Need to set o_wb_dqs high one clock prior to any read.
// As per spec, ODT = 0 during reads
assign o_ddr_bus_dir = bus_read[8];
assign o_ddr_odt = o_ddr_bus_dir;
assign o_ddr_bus_oe = ~bus_read[8];
 
// ODT must be in high impedence while reset_n=0, then it can be set
// to low or high.
assign o_ddr_odt = o_ddr_bus_oe;
 
 
endmodule

powered by: WebSVN 2.1.0

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