URL
https://opencores.org/ocsvn/wbddr3/wbddr3/trunk
Subversion Repositories wbddr3
[/] [wbddr3/] [trunk/] [bench/] [cpp/] [ddrsdram_tb.cpp] - Rev 9
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // 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); bool writeout = (!m_core->v__DOT__reset_override); if (writeout) { int cmd; cmd = (m_core->o_ddr_reset_n?0:32) |(m_core->o_ddr_cke?0:16) |(m_core->o_ddr_cs_n?8:0) |(m_core->o_ddr_ras_n?4:0) |(m_core->o_ddr_cas_n?2:0) |(m_core->o_ddr_we_n?1:0); 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)); printf(" FIFO[%x,%x](%s,%d,%08x)", m_core->v__DOT__bus_fifo_head, m_core->v__DOT__bus_fifo_tail, (m_core->v__DOT__bus_fifo_new[m_core->v__DOT__bus_fifo_tail])?"N":"o", m_core->v__DOT__bus_fifo_sub[m_core->v__DOT__bus_fifo_tail], m_core->v__DOT__bus_fifo_data[m_core->v__DOT__bus_fifo_tail]); printf(" BUS[%03x/%03x/%03x/%d]", (m_core->v__DOT__bus_active), (m_core->v__DOT__bus_read), (m_core->v__DOT__bus_new), (m_core->v__DOT__bus_subaddr[8])); /* // 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)); */ printf(" R_%s%03x[%d]%04x:%d/%08x", (!m_core->v__DOT__r_pending)?"_" :(m_core->v__DOT__r_we)?"W":"R", (m_core->v__DOT__r_row), (m_core->v__DOT__r_bank), (m_core->v__DOT__r_col), (m_core->v__DOT__r_sub), (m_core->v__DOT__r_data)); printf(" S_%s%03x[%d]%04x:%d/%08x%s%s%s", (!m_core->v__DOT__s_pending)?"_" :(m_core->v__DOT__s_we)?"W":"R", (m_core->v__DOT__s_row), (m_core->v__DOT__s_bank), (m_core->v__DOT__s_col), (m_core->v__DOT__s_sub), (m_core->v__DOT__s_data), (m_core->v__DOT__s_match)?"M":" ", (m_core->v__DOT__pipe_stall)?"P":" ", "-" //(m_core->v__DOT__s_stall)?"S":" " ); printf(" %s%s%s", "B", // (m_core->v__DOT__all_banks_closed)?"b":"B", (m_core->v__DOT__need_close_bank)?"C":"N", //:(m_core->v__DOT__maybe_close_next_bank)?"c":"N", (m_core->v__DOT__need_open_bank)?"O":"K"); // :(m_core->v__DOT__maybe_open_next_bank)?"o":"K"); for(int i=0; i<8; i++) { printf("%s%x@%x%s", (m_core->v__DOT__r_bank==i)?"R":"[", m_core->v__DOT__bank_status[i], m_core->v__DOT__bank_address[i], (m_core->v__DOT__r_nxt_bank==i)?"N":"]"); } extern int gbl_state, gbl_counts; printf(" %2d:%08x ", gbl_state, gbl_counts); printf(" %s%s%s%s%s%s:%08x:%08x", (m_core->v__DOT__reset_override)?"R":" ", (m_core->v__DOT__need_refresh)?"N":" ", (m_core->v__DOT__need_close_bank)?"C":" ", (m_core->v__DOT__need_open_bank)?"O":" ", (m_core->v__DOT__valid_bank)?"V":" ", (m_core->v__DOT__r_move)?"R":" ", m_core->v__DOT__activate_bank_cmd, m_core->v__DOT__cmd); printf(" F%s%05x:%x/%s", (m_core->v__DOT__refresh_ztimer)?"Z":" ", m_core->v__DOT__refresh_counter, m_core->v__DOT__refresh_addr, (m_core->v__DOT__need_refresh)?"N":" "); if (m_core->v__DOT__reset_override) printf(" OVERRIDE"); //if(m_core->v__DOT__last_open_bank)printf(" LST-OPEN"); switch(cmd) { case DDR_MRSET: printf(" MRSET"); break; case DDR_REFRESH: printf(" REFRESH"); break; case DDR_PRECHARGE: printf(" PRECHARGE%s", (m_core->o_ddr_addr&0x400)?"-ALL":""); break; case DDR_ACTIVATE: printf(" ACTIVATE"); break; case DDR_WRITE: printf(" WRITE"); break; case DDR_READ: printf(" READ"); break; case DDR_ZQS: printf(" ZQS"); break; case DDR_NOOP: printf(" NOOP"); break; default: printf(" Unknown-CMD(%02x)", cmd); break; } // Decode the command 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(); } 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; 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<141195; i++) tb->wb_tick(); // Let's short circuit the test, and only test *some* of the memory // space. It'll probably be good enough, and it'll finish while I'm // waiting ... mlen = 1<<16; 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); #define SINGULAR_WRITE #define SINGULAR_READ #define BIGPIPELINE_WRITE #define BIGPIPELINE_READ #define PRIMEVEC_WRITE #define PRIMEVEC_READ #define SKIP_WRITE #define SKIP_READ #ifdef SINGULAR_WRITE // 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; } #else #ifdef SINGULAR_READ // If we aren't doing the write test, we still need to charge // the memory for the read test. Here we do it manually. for(int i=0; i<(int)mlen; i++) (*tb)[i] = rdbuf[i]; #endif // !SINGULAR_WRITE && SINGULAR_READ #endif // SINGULAR_WRITE #ifdef SINGULAR_READ 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(); } #endif #ifdef BIGPIPELINE_WRITE // 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; } } #else #ifdef BIGPIPELINE_READ uload(mlen, rdbuf); // Get some new values // If we aren't doing the write test, we still need to charge // the memory for the read test. Here we do it manually. for(int i=0; i<(int)mlen; i++) (*tb)[i] = rdbuf[i]; #endif // BIGPIPELINE_WRITE && BIGPIPELINE_READ #endif #ifdef BIGPIPELINE_READ 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; } } #endif #ifdef PRIMEVEC_WRITE // Third test: Vector writes going through all memory, in prime numbers // of values at a time, followed by reads via a different prime number uload(mlen, rdbuf); // Get some new values { int nw = 3; 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; } } #else #ifdef PRIMEVEC_READ uload(mlen, rdbuf); // Get some new values // If we aren't doing the write test, we still need to charge // the memory for the read test. Here we do it manually. for(int i=0; i<(int)mlen; i++) (*tb)[i] = rdbuf[i]; #endif #endif #ifdef PRIMEVEC_READ { int nr = 13; for(int i=0; i<(int)mlen; i+=nr) { int ln = ((int)mlen-i>nr)?nr:mlen-i; tb->wb_read(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; } } #endif #ifdef SKIP_WRITE // Fourth test: Singular writes though all of memory, skipping by some // prime address increment each time, followed by reads via a different // prime numbered increment. uload(mlen, rdbuf); // Get some new values for(int i=0; i<(int)mlen; i++) { int loc = (i*3889)&(mlen-1); tb->wb_write(loc, rdbuf[loc]); if ((*tb)[loc] != rdbuf[loc]) { printf("R-WRITE[%06x] = %08x (Expecting %08x) FAILED\n", i, (*tb)[loc], rdbuf[loc]); goto test_failure; } if (tb->bombed()) goto test_failure; } #else #ifdef SKIP_READ uload(mlen, rdbuf); // Get some new values for(int i=0; i<(int)mlen; i++) (*tb)[i] = rdbuf[i]; #endif // !SKIP_WRITE && SKIP_READ #endif #ifdef SKIP_READ for(int i=0; i<(int)mlen; i++) { int loc = (i*7477)&(mlen-1); mbuf[loc] = tb->wb_read(loc); if (mbuf[loc] != rdbuf[loc]) { printf("R-READ[%06x] = %08x (Expecting %08x) FAILED\n", loc, mbuf[loc], rdbuf[loc]); goto test_failure; } if (tb->bombed()) goto test_failure; } #endif 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); }
Go to most recent revision | Compare with Previous | Blame | View Log