Line 1... |
Line 1... |
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: eqspiflash_tb.cpp
|
// Filename: eqspiflash_tb.cpp
|
//
|
//
|
// Project: OpenArty, an entirely open SoC based upon the Arty platform
|
// Project: Wishbone Controlled Quad SPI Flash Controller
|
//
|
//
|
// Purpose: To determine whether or not the eqspiflash module works. Run
|
// Purpose: To determine whether or not the eqspiflash module works. Run
|
// this with no arguments, and check whether or not the last line
|
// this with no arguments, and check whether or not the last line
|
// contains "SUCCESS" or not. If it does contain "SUCCESS", then the
|
// contains "SUCCESS" or not. If it does contain "SUCCESS", then the
|
// module passes all tests found within here.
|
// module passes all tests found within here.
|
Line 25... |
Line 25... |
// 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
|
Line 37... |
Line 37... |
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
#include "verilated.h"
|
#include "verilated.h"
|
|
#include "verilated_vcd_c.h"
|
#include "Veqspiflash.h"
|
#include "Veqspiflash.h"
|
#include "eqspiflashsim.h"
|
#include "eqspiflashsim.h"
|
|
|
#define QSPIFLASH 0x0400000
|
#define QSPIFLASH 0x0400000
|
const int BOMBCOUNT = 2048;
|
const int BOMBCOUNT = 2048;
|
|
|
class EQSPIFLASH_TB {
|
class EQSPIFLASH_TB {
|
long m_tickcount;
|
unsigned long m_tickcount;
|
Veqspiflash *m_core;
|
Veqspiflash *m_core;
|
EQSPIFLASHSIM *m_flash;
|
EQSPIFLASHSIM *m_flash;
|
bool m_bomb;
|
bool m_bomb;
|
|
VerilatedVcdC* m_trace;
|
|
|
public:
|
public:
|
|
|
EQSPIFLASH_TB(void) {
|
EQSPIFLASH_TB(void) {
|
|
Verilated::traceEverOn(true);
|
m_core = new Veqspiflash;
|
m_core = new Veqspiflash;
|
m_flash= new EQSPIFLASHSIM;
|
m_flash= new EQSPIFLASHSIM(24,true);
|
|
m_trace= NULL;
|
}
|
}
|
|
|
unsigned operator[](const int index) { return (*m_flash)[index]; }
|
unsigned operator[](const int index) { return (*m_flash)[index]; }
|
void setflash(unsigned addr, unsigned v) {
|
void setflash(unsigned addr, unsigned v) {
|
m_flash->set(addr, v);
|
m_flash->set(addr, v);
|
}
|
}
|
void load(const char *fname) {
|
void load(const char *fname) {
|
m_flash->load(0,fname);
|
m_flash->load(0,fname);
|
}
|
}
|
|
|
void tick(void) {
|
void trace(const char *fname) {
|
m_core->i_clk_200mhz = 1;
|
if (!m_trace) {
|
|
m_trace = new VerilatedVcdC;
|
|
m_core->trace(m_trace, 99);
|
|
m_trace->open(fname);
|
|
}
|
|
}
|
|
|
|
void tick(void) {
|
|
// m_core->i_clk_82mhz = 0;
|
|
// m_core->eval();
|
m_core->i_qspi_dat = (*m_flash)(m_core->o_qspi_cs_n,
|
m_core->i_qspi_dat = (*m_flash)(m_core->o_qspi_cs_n,
|
m_core->o_qspi_sck, m_core->o_qspi_dat);
|
m_core->o_qspi_sck, m_core->o_qspi_dat);
|
|
|
|
m_core->i_clk_82mhz = 1;
|
|
m_core->eval();
|
|
// #define DEBUGGING_OUTPUT
|
|
#ifdef DEBUGGING_OUTPUT
|
printf("%08lx-WB: %s %s/%s %s %s[%s%s%s%s%s] %s %s@0x%08x[%08x/%08x] -- SPI %s%s[%x/%x](%d,%d)",
|
printf("%08lx-WB: %s %s/%s %s %s[%s%s%s%s%s] %s %s@0x%08x[%08x/%08x] -- SPI %s%s[%x/%x](%d,%d)",
|
m_tickcount,
|
m_tickcount,
|
(m_core->i_wb_cyc)?"CYC":" ",
|
(m_core->i_wb_cyc)?"CYC":" ",
|
(m_core->i_wb_data_stb)?"DSTB":" ",
|
(m_core->i_wb_data_stb)?"DSTB":" ",
|
(m_core->i_wb_ctrl_stb)?"CSTB":" ",
|
(m_core->i_wb_ctrl_stb)?"CSTB":" ",
|
Line 169... |
Line 186... |
(m_core->v__DOT__ewproc__DOT__accepted)?"EW-ACC":"",
|
(m_core->v__DOT__ewproc__DOT__accepted)?"EW-ACC":"",
|
(m_core->v__DOT__idotp__DOT__accepted)?"ID-ACC":"",
|
(m_core->v__DOT__idotp__DOT__accepted)?"ID-ACC":"",
|
(m_core->v__DOT__ctproc__DOT__accepted)?"CT-ACC":"");
|
(m_core->v__DOT__ctproc__DOT__accepted)?"CT-ACC":"");
|
|
|
|
|
printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
(m_core->v__DOT__preproc__DOT__pending)?" PENDING":"",
|
(m_core->v__DOT__preproc__DOT__pending)?" PENDING":"",
|
(m_core->v__DOT__preproc__DOT__lcl_key)?" KEY":"",
|
(m_core->v__DOT__preproc__DOT__lcl_key)?" KEY":"",
|
(m_core->v__DOT__preproc__DOT__ctreg_stb)?" CTSTB":"",
|
(m_core->v__DOT__preproc__DOT__ctreg_stb)?" CTSTB":"",
|
(m_core->v__DOT__bus_ctreq)?" BUSCTRL":"",
|
(m_core->v__DOT__bus_ctreq)?" BUSCTRL":"",
|
(m_core->v__DOT__bus_other_req)?" BUSOTHER":"",
|
(m_core->v__DOT__bus_other_req)?" BUSOTHER":"",
|
(m_core->v__DOT__preproc__DOT__wp)?" WP":"",
|
(m_core->v__DOT__preproc__DOT__wp)?" WP":"",
|
(m_core->v__DOT__bus_wip)?" WIP":"",
|
(m_core->v__DOT__bus_wip)?" WIP":"",
|
// (m_core->v__DOT__preproc__DOT__lcl_reg)?" LCLREG":"",
|
// (m_core->v__DOT__preproc__DOT__lcl_reg)?" LCLREG":"",
|
// (m_core->v__DOT__w_xip)?" XIP":"",
|
// (m_core->v__DOT__w_xip)?" XIP":"",
|
// (m_core->v__DOT__w_quad)?" QUAD":"",
|
// (m_core->v__DOT__w_quad)?" QUAD":"",
|
// (m_core->v__DOT__bus_piperd)?" RDPIPE":"",
|
(m_core->v__DOT__bus_piperd)?" RDPIPE":"",
|
(m_core->v__DOT__preproc__DOT__wp)?" WRWP":"",
|
(m_core->v__DOT__preproc__DOT__wp)?" WRWP":"",
|
(m_core->v__DOT__ewproc__DOT__cyc)?" WRCYC":"",
|
(m_core->v__DOT__ewproc__DOT__cyc)?" WRCYC":"",
|
(m_core->v__DOT__bus_pipewr)?" WRPIPE":"",
|
(m_core->v__DOT__bus_pipewr)?" WRPIPE":"",
|
(m_core->v__DOT__bus_endwr)?" ENDWR":"",
|
(m_core->v__DOT__bus_endwr)?" ENDWR":"",
|
(m_core->v__DOT__ct_ack)?" CTACK":"",
|
(m_core->v__DOT__ct_ack)?" CTACK":"",
|
Line 205... |
Line 222... |
if (m_core->v__DOT__rdproc__DOT__r_leave_xip)
|
if (m_core->v__DOT__rdproc__DOT__r_leave_xip)
|
fputs(" RD:R_LVXIP", stdout);
|
fputs(" RD:R_LVXIP", stdout);
|
|
|
|
|
printf("\n");
|
printf("\n");
|
|
#endif
|
|
|
|
if ((m_trace)&&(m_tickcount>0)) m_trace->dump(10*m_tickcount-2);
|
|
m_core->i_clk_82mhz = 1;
|
m_core->eval();
|
m_core->eval();
|
m_core->i_clk_200mhz = 0;
|
if (m_trace) m_trace->dump(10*m_tickcount);
|
|
m_core->i_clk_82mhz = 0;
|
m_core->eval();
|
m_core->eval();
|
|
if (m_trace) m_trace->dump(10*m_tickcount+5);
|
|
|
m_tickcount++;
|
m_tickcount++;
|
|
|
/*
|
/*
|
if ((m_core->o_wb_ack)&&(!m_core->i_wb_cyc)) {
|
if ((m_core->o_wb_ack)&&(!m_core->i_wb_cyc)) {
|
Line 240... |
Line 262... |
m_core->i_wb_data_stb = (a & QSPIFLASH)?1:0;
|
m_core->i_wb_data_stb = (a & QSPIFLASH)?1:0;
|
m_core->i_wb_ctrl_stb = !(m_core->i_wb_data_stb);
|
m_core->i_wb_ctrl_stb = !(m_core->i_wb_data_stb);
|
m_core->i_wb_we = 0;
|
m_core->i_wb_we = 0;
|
m_core->i_wb_addr= a & 0x03fffff;
|
m_core->i_wb_addr= a & 0x03fffff;
|
|
|
if (m_core->o_wb_stall)
|
if (m_core->o_wb_stall) {
|
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall))
|
while((errcount++ < BOMBCOUNT)&&(m_core->o_wb_stall))
|
tick();
|
tick();
|
else
|
} tick();
|
tick();
|
|
|
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
|
|
while((errcount++ < BOMBCOUNT)&&(!m_core->o_wb_ack))
|
while((errcount++ < BOMBCOUNT)&&(!m_core->o_wb_ack))
|
Line 261... |
Line 282... |
m_core->i_wb_cyc = 0;
|
m_core->i_wb_cyc = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
|
|
if(errcount >= BOMBCOUNT) {
|
if(errcount >= BOMBCOUNT) {
|
printf("SETTING ERR TO TRUE!!!!!\n");
|
printf("RD-SETTING ERR TO TRUE!!!!!\n");
|
m_bomb = true;
|
m_bomb = true;
|
} else if (!m_core->o_wb_ack) {
|
} else if (!m_core->o_wb_ack) {
|
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
|
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
|
m_bomb = true;
|
m_bomb = true;
|
}
|
}
|
Line 322... |
Line 343... |
|
|
// Release the bus?
|
// Release the bus?
|
m_core->i_wb_cyc = 0;
|
m_core->i_wb_cyc = 0;
|
|
|
if(errcount >= THISBOMBCOUNT) {
|
if(errcount >= THISBOMBCOUNT) {
|
printf("SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", errcount, THISBOMBCOUNT);
|
printf("RDI-SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", errcount, THISBOMBCOUNT);
|
m_bomb = true;
|
m_bomb = true;
|
} else if (!m_core->o_wb_ack) {
|
} else if (!m_core->o_wb_ack) {
|
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
|
printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
|
m_bomb = true;
|
m_bomb = true;
|
}
|
}
|
Line 359... |
Line 380... |
m_core->i_wb_cyc = 0;
|
m_core->i_wb_cyc = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
|
|
if(errcount >= BOMBCOUNT) {
|
if(errcount >= BOMBCOUNT) {
|
printf("SETTING ERR TO TRUE!!!!!\n");
|
printf("WB-SETTING ERR TO TRUE!!!!!\n");
|
m_bomb = true;
|
m_bomb = true;
|
} tick();
|
} tick();
|
}
|
}
|
|
|
void wb_write(unsigned a, unsigned int ln, unsigned int *buf) {
|
void wb_write(unsigned a, unsigned int ln, unsigned int *buf) {
|
Line 402... |
Line 423... |
m_core->i_wb_cyc = 0;
|
m_core->i_wb_cyc = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
|
|
if(errcount >= BOMBCOUNT) {
|
if(errcount >= BOMBCOUNT) {
|
printf("SETTING ERR TO TRUE!!!!!\n");
|
printf("WBI-SETTING ERR TO TRUE!!!!!\n");
|
m_bomb = true;
|
m_bomb = true;
|
} tick();
|
} tick();
|
}
|
}
|
|
|
void wb_write_slow(unsigned a, unsigned int ln, unsigned int *buf,
|
void wb_write_slow(unsigned a, unsigned int ln, unsigned int *buf,
|
Line 459... |
Line 480... |
m_core->i_wb_cyc = 0;
|
m_core->i_wb_cyc = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_data_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
m_core->i_wb_ctrl_stb = 0;
|
|
|
if(errcount >= BOMBCOUNT) {
|
if(errcount >= BOMBCOUNT) {
|
printf("SETTING ERR TO TRUE!!!!!\n");
|
printf("WBS-SETTING ERR TO TRUE!!!!!\n");
|
m_bomb = true;
|
m_bomb = true;
|
} tick();
|
} tick();
|
}
|
}
|
|
|
bool bombed(void) const { return m_bomb; }
|
bool bombed(void) const { return m_bomb; }
|
Line 480... |
Line 501... |
|
|
tb->load(fname);
|
tb->load(fname);
|
rdbuf = new unsigned[4096];
|
rdbuf = new unsigned[4096];
|
tb->setflash(0,0);
|
tb->setflash(0,0);
|
|
|
|
tb->trace("eqspi.vcd");
|
|
|
tb->wb_tick();
|
tb->wb_tick();
|
rdv = tb->wb_read(QSPIFLASH);
|
rdv = tb->wb_read(QSPIFLASH);
|
printf("READ[0] = %04x\n", rdv);
|
printf("READ[0] = %04x\n", rdv);
|
if (rdv != 0)
|
if (rdv != 0)
|
goto test_failure;
|
goto test_failure;
|
Line 577... |
Line 600... |
goto test_failure;
|
goto test_failure;
|
}
|
}
|
} printf("VECTOR TEST PASSES! (QUAD)\n");
|
} printf("VECTOR TEST PASSES! (QUAD)\n");
|
|
|
printf("Attempting to switch to Quad mode with XIP\n");
|
printf("Attempting to switch to Quad mode with XIP\n");
|
tb->wb_write(3, tb->wb_read(3)|0x08);
|
{
|
|
int nv;
|
|
nv = tb->wb_read(3);
|
|
printf("READ VCONF = %02x\n", nv);
|
|
printf("WRITING VCONF= %02x\n", nv | 0x08);
|
|
tb->wb_write(3, nv|0x08);
|
|
}
|
// tb->wb_write(0, 0x22000000);
|
// tb->wb_write(0, 0x22000000);
|
|
|
printf("Attempting to read in Quad mode, using XIP mode\n");
|
printf("Attempting to read in Quad mode, using XIP mode\n");
|
for(int i=0; (i<1000)&&(!tb->bombed()); i++) {
|
for(int i=0; (i<1000)&&(!tb->bombed()); i++) {
|
unsigned tblv;
|
unsigned tblv;
|
Line 612... |
Line 641... |
printf("Turning off write-protect, calling WEL\n");
|
printf("Turning off write-protect, calling WEL\n");
|
tb->wb_write(0, 0x620001be);
|
tb->wb_write(0, 0x620001be);
|
printf("Attempting to erase subsector 1\n");
|
printf("Attempting to erase subsector 1\n");
|
tb->wb_write(0, 0xf20005be);
|
tb->wb_write(0, 0xf20005be);
|
|
|
while (tb->wb_read(0)&0x01000000)
|
while((tb->wb_read(0)&0x01000000)&&(!tb->bombed()))
|
;
|
;
|
while(tb->wb_read(0)&0x80000000)
|
while((tb->wb_read(0)&0x80000000)&&(!tb->bombed()))
|
;
|
;
|
|
if (tb->bombed())
|
|
goto test_failure;
|
if (tb->wb_read(QSPIFLASH+1023) != rdbuf[0])
|
if (tb->wb_read(QSPIFLASH+1023) != rdbuf[0])
|
goto test_failure;
|
goto test_failure;
|
if (tb->wb_read(QSPIFLASH+2048) != rdbuf[1])
|
if (tb->wb_read(QSPIFLASH+2048) != rdbuf[1])
|
goto test_failure;
|
goto test_failure;
|
tb->wb_read(QSPIFLASH+1024, 1024, rdbuf);
|
tb->wb_read(QSPIFLASH+1024, 1024, rdbuf);
|