URL
https://opencores.org/ocsvn/qspiflash/qspiflash/trunk
Subversion Repositories qspiflash
Compare Revisions
- This comparison shows the changes necessary to convert path
/qspiflash/trunk/bench/cpp
- from Rev 16 to Rev 15
- ↔ Reverse comparison
Rev 16 → Rev 15
/testb.h
File deleted
/qspiflash_tb.cpp
File deleted
/wbflash_tb.h
File deleted
/qspiflashsim.cpp
238,6 → 238,7
} m_oreg = 0; |
} else if (m_count == 8) { |
QOREG(0x0a5); |
// printf("SFLASH-CMD = %02x\n", m_ireg & 0x0ff); |
// Figure out what command we've been given |
if (m_debug) printf("SPI FLASH CMD %02x\n", m_ireg&0x0ff); |
switch(m_ireg & 0x0ff) { |
/qspiflashsim.h
78,14 → 78,10
void load(const char *fname) { load(0, fname); } |
void load(const unsigned addr, const char *fname); |
void load(const uint32_t offset, const char *data, const uint32_t len); |
bool write_protect(void) { return ((m_sreg & QSPIF_WEL_FLAG)==0); } |
bool write_in_progress(void) { return ((m_sreg | QSPIF_WIP_FLAG)!=0); } |
bool xip_mode(void) { return (QSPIF_QUAD_READ_IDLE == m_state); } |
bool quad_mode(void) { return m_quad_mode; } |
void debug(const bool dbg) { m_debug = dbg; } |
bool debug(void) const { return m_debug; } |
unsigned operator[](const int index) { |
unsigned char *cptr = (unsigned char *)&m_mem[index]; |
unsigned char *cptr = (unsigned char *)&m_mem[index<<2]; |
unsigned v; |
v = (*cptr++); |
v = (v<<8)|(*cptr++); |
94,7 → 90,7
|
return v; } |
void set(const unsigned addr, const unsigned val) { |
unsigned char *cptr = (unsigned char *)&m_mem[addr]; |
unsigned char *cptr = (unsigned char *)&m_mem[addr<<2]; |
*cptr++ = (val>>24); |
*cptr++ = (val>>16); |
*cptr++ = (val>> 8); |
/eqspiflashsim.cpp
2,7 → 2,7
// |
// Filename: eqspiflashsim.cpp |
// |
// Project: Wishbone Controlled Quad SPI Flash Controller |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: This library simulates the operation of a Quad-SPI commanded |
// flash, such as the Micron N25Q128A used on the Arty development |
18,7 → 18,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2017, 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 |
31,7 → 31,7
// 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 |
// 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. |
// |
46,10 → 46,11
#include <string.h> |
#include <assert.h> |
#include <stdlib.h> |
#include <stdint.h> |
|
#include "eqspiflashsim.h" |
|
#define MEMBYTES (1<<24) |
|
static const unsigned |
DEVESD = 0x014, |
// MICROSECONDS = 200, |
90,11 → 91,9
(char)0xf0, (char)0xef |
}; |
|
EQSPIFLASHSIM::EQSPIFLASHSIM(const int lglen, bool debug) { |
int nsectors; |
m_membytes = (1<<lglen); |
m_memmask = (m_membytes - 1); |
m_mem = new char[m_membytes]; |
EQSPIFLASHSIM::EQSPIFLASHSIM(void) { |
const int NSECTORS = MEMBYTES>>16; |
m_mem = new char[MEMBYTES]; |
m_pmem = new char[256]; |
m_otp = new char[65]; |
for(int i=0; i<65; i++) |
101,9 → 100,8
m_otp[i] = 0x0ff; |
m_otp[64] = 1; |
m_otp_wp = false; |
nsectors = m_membytes>>16; |
m_lockregs = new char[nsectors]; |
for(int i=0; i<nsectors; i++) |
m_lockregs = new char[NSECTORS]; |
for(int i=0; i<NSECTORS; i++) |
m_lockregs[i] = 0; |
|
m_state = EQSPIF_IDLE; |
112,50 → 110,39
m_ireg = m_oreg = 0; |
m_sreg = 0x01c; |
m_creg = 0x001; // Initial creg on delivery |
m_vconfig = 0x83; // Volatile configuration register |
m_vconfig = 0x7; // Volatile configuration register |
m_nvconfig = 0x0fff; // Nonvolatile configuration register |
m_quad_mode = EQSPIF_QMODE_SPI; |
m_quad_mode = false; |
m_mode_byte = 0; |
m_flagreg = 0x0a5; |
|
m_debug = true; |
|
memset(m_mem, 0x0ff, m_membytes); |
memset(m_mem, 0x0ff, MEMBYTES); |
} |
|
void EQSPIFLASHSIM::load(const unsigned addr, const char *fname) { |
FILE *fp; |
size_t len, nr = 0; |
size_t len; |
|
if (addr >= m_membytes) |
if (addr >= MEMBYTES) |
return; // return void |
len = MEMBYTES-addr*4; |
|
// If not given, then length is from the given address until the end |
// of the flash memory |
len = m_membytes-addr*4; |
|
if (NULL != (fp = fopen(fname, "r"))) { |
int nr = 0; |
nr = fread(&m_mem[addr*4], sizeof(char), len, fp); |
fclose(fp); |
if (nr == 0) { |
fprintf(stderr, "EQSPI-FLASH: Could not read %s\n", fname); |
fprintf(stderr, "SPI-FLASH: Could not read %s\n", fname); |
perror("O/S Err:"); |
} |
} else { |
fprintf(stderr, "EQSPI-FLASH: Could not open %s\n", fname); |
fprintf(stderr, "SPI-FLASH: Could not open %s\n", fname); |
perror("O/S Err:"); |
} |
|
for(unsigned i=nr; i<m_membytes; i++) |
m_mem[i] = 0x0ff; |
} |
|
void EQSPIFLASHSIM::load(const uint32_t offset, const char *data, const uint32_t len) { |
uint32_t moff = (offset & (m_memmask)); |
|
memcpy(&m_mem[moff], data, len); |
} |
|
#define QOREG(A) m_oreg = ((m_oreg & (~0x0ff))|(A&0x0ff)) |
|
int EQSPIFLASHSIM::operator()(const int csn, const int sck, const int dat) { |
195,13 → 182,13
*/ |
m_mem[(m_addr&(~0x0ff))+i] &= m_pmem[i]; |
} |
m_quad_mode = EQSPIF_QMODE_SPI; |
m_quad_mode = false; |
} else if (EQSPIF_WRCR == m_state) { |
if (m_debug) printf("Actually writing volatile config register: VCONFIG = 0x%04x\n", m_vconfig); |
if (m_debug) printf("Actually writing volatile config register\n"); |
if (m_debug) printf("CK = %d & 7 = %d\n", m_count, m_count & 0x07); |
m_state = EQSPIF_IDLE; |
} else if (EQSPIF_WRNVCONFIG == m_state) { |
if (m_debug) printf("Actually writing nonvolatile config register: VCONFIG = 0x%02x\n", m_nvconfig); |
if (m_debug) printf("Actually writing nonvolatile config register\n"); |
m_write_count = tWNVCR; |
m_state = EQSPIF_IDLE; |
} else if (EQSPIF_WREVCONFIG == m_state) { |
253,7 → 240,7
m_sreg &= (~EQSPIF_WEL_FLAG); |
m_sreg |= (EQSPIF_WIP_FLAG); |
// Should I be checking the lock register(s) here? |
for(unsigned i=0; i<m_membytes; i++) |
for(int i=0; i<MEMBYTES; i++) |
m_mem[i] = 0x0ff; |
} else if (m_state == EQSPIF_PROGRAM_OTP) { |
// Program the One-Time Programmable (OTP memory |
276,15 → 263,19
m_write_count = tRES; |
m_state = EQSPIF_IDLE; |
*/ |
} else if (m_state == EQSPIF_QUAD_READ_CMD) { |
m_state = EQSPIF_IDLE; |
if (m_mode_byte!=0) |
m_quad_mode = false; |
else |
m_state = EQSPIF_XIP; |
} else if (m_state == EQSPIF_QUAD_READ) { |
m_state = EQSPIF_IDLE; |
if (m_mode_byte!=0) |
m_quad_mode = EQSPIF_QMODE_SPI; |
else { |
if (m_quad_mode == EQSPIF_QMODE_SPI_ADDR) |
m_quad_mode = EQSPIF_QMODE_SPI; |
m_quad_mode = false; |
else |
m_state = EQSPIF_XIP; |
} |
// } else if (m_state == EQSPIF_XIP) { |
} |
|
m_oreg = 0x0fe; |
331,12 → 322,9
if (m_count == 24) { |
if (m_debug) printf("EQSPI: Entering from Quad-Read Idle to Quad-Read\n"); |
if (m_debug) printf("EQSPI: QI/O Idle Addr = %02x\n", m_ireg&0x0ffffff); |
m_addr = (m_ireg) & m_memmask; |
assert((m_addr & (~(m_memmask)))==0); |
} else if (m_count == 24 + 4*8) {// After the idle bits |
m_addr = (m_ireg) & 0x0ffffff; |
assert((m_addr & 0xfc00000)==0); |
m_state = EQSPIF_QUAD_READ; |
if (m_debug) printf("EQSPI: QI/O Dummy = %04x\n", m_ireg); |
m_mode_byte = (m_ireg>>24) & 0x10; |
} m_oreg = 0; |
} else if (m_count == 8) { |
QOREG(0x0a5); |
389,10 → 377,8
if (m_debug) printf("EQSPI: WEL not set, cannot do a subsector erase\n"); |
m_state = EQSPIF_INVALID; |
assert(0&&"WEL not set"); |
} else { |
} else |
m_state = EQSPIF_SUBSECTOR_ERASE; |
if (m_debug) printf("EQSPI: SUBSECTOR_ERASE COMMAND\n"); |
} |
break; |
case 0x32: // QUAD Page program, 4 bits at a time |
if (2 != (m_sreg & 0x203)) { |
435,7 → 421,7
QOREG(m_evconfig); |
break; |
case 0x06b: |
m_state = EQSPIF_QUAD_OREAD_CMD; |
m_state = EQSPIF_QUAD_READ_CMD; |
// m_quad_mode = true; // Not yet, need to wait past dummy registers |
break; |
case 0x70: // Read flag status register |
493,8 → 479,10
if (m_debug) printf("EQSPI: READ LOCK REGISTER (Waiting on address)\n"); |
break; |
case 0x0eb: // Here's the (other) read that we support |
m_state = EQSPIF_QUAD_IOREAD_CMD; |
m_quad_mode = EQSPIF_QMODE_QSPI_ADDR; |
// printf("EQSPI: QUAD-I/O-READ\n"); |
// m_state = EQSPIF_QUAD_READ_CMD; |
// m_quad_mode = true; |
assert(0 && "Quad Input/Output fast read not supported"); |
break; |
default: |
printf("EQSPI: UNRECOGNIZED SPI FLASH CMD: %02x\n", m_ireg&0x0ff); |
520,21 → 508,21
} |
break; |
case EQSPIF_WRCR: // Write volatile config register, 0x81 |
if (m_count == 8+8+8) { |
if (m_count == 8+8) { |
m_vconfig = m_ireg & 0x0ff; |
if (m_debug) printf("Setting volatile config register to %08x\n", m_vconfig); |
printf("Setting volatile config register to %08x\n", m_vconfig); |
assert((m_vconfig & 0xfb)==0x8b); |
} break; |
case EQSPIF_WRNVCONFIG: // Write nonvolatile config register |
if (m_count == 8+8+8) { |
if (m_count == 8+8) { |
m_nvconfig = m_ireg & 0x0ffdf; |
if (m_debug) printf("Setting nonvolatile config register to %08x\n", m_nvconfig); |
printf("Setting nonvolatile config register to %08x\n", m_nvconfig); |
assert((m_nvconfig & 0xffc5)==0x8fc5); |
} break; |
case EQSPIF_WREVCONFIG: // Write enhanced volatile config reg |
if (m_count == 8+8) { |
m_evconfig = m_ireg & 0x0ff; |
if (m_debug) printf("Setting enhanced volatile config register to %08x\n", m_evconfig); |
printf("Setting enhanced volatile config register to %08x\n", m_evconfig); |
assert((m_evconfig & 0x0d7)==0xd7); |
} break; |
case EQSPIF_WRLOCK: |
542,13 → 530,14
m_addr = (m_ireg>>24)&0x0ff; |
if ((m_lockregs[m_addr]&2)==0) |
m_lockregs[m_addr] = m_ireg&3; |
if (m_debug) printf("Setting lock register[%02x] to %d\n", m_addr, m_lockregs[m_addr]); |
printf("Setting lock register[%02x] to %d\n", m_addr, m_lockregs[m_addr]); |
assert((m_config & 0xfb)==0x8b); |
} break; |
case EQSPIF_RDLOCK: |
if (m_count == 24) { |
m_addr = (m_ireg>>16)&0x0ff; |
QOREG(m_lockregs[m_addr]); |
if (m_debug) printf("Reading lock register[%02x]: %d\n", m_addr, m_lockregs[m_addr]); |
printf("Reading lock register[%02x]: %d\n", m_addr, m_lockregs[m_addr]); |
} else |
QOREG(m_lockregs[m_addr]); |
break; |
608,16 → 597,15
break; |
case EQSPIF_FAST_READ: |
if (m_count < 32) { |
if (m_debug) printf("FAST READ, WAITING FOR FULL COMMAND (count = %d)\n", m_count); |
QOREG(0x0c3); |
} else if (m_count == 32) { |
m_addr = m_ireg & m_memmask; |
m_addr = m_ireg & 0x0ffffff; |
if (m_debug) printf("FAST READ, ADDR = %08x\n", m_addr); |
QOREG(0x0c3); |
if (m_addr & (~(m_memmask))) { |
printf("EQSPI: ADDR = %08x ? !!\n", m_addr); |
} assert((m_addr & (~(m_memmask)))==0); |
assert((m_addr & 0xf000003)==0); |
} else if ((m_count >= 40)&&(0 == (m_sreg&0x01))) { |
if ((m_debug)&&(m_count == 40)) |
if (m_count == 40) |
printf("DUMMY BYTE COMPLETE ...\n"); |
QOREG(m_mem[m_addr++]); |
if (m_debug) printf("SPIF[%08x] = %02x -> %02x\n", m_addr-1, m_mem[m_addr-1]&0x0ff, m_oreg); |
626,56 → 614,51
if (m_debug) printf("CANNOT READ WHEN WRITE IN PROGRESS, m_sreg = %02x\n", m_sreg); |
} else printf("How did I get here, m_count = %d\n", m_count); |
break; |
case EQSPIF_QUAD_IOREAD_CMD: |
case EQSPIF_QUAD_READ_CMD: |
// The command to go into quad read mode took 8 bits |
// that changes the timings, else we'd use quad_Read |
// below |
if (m_count == 32) { |
m_addr = m_ireg & m_memmask; |
if (m_debug) printf("EQSPI: QUAD I/O READ, ADDR = %06x (%02x:%02x:%02x:%02x)\n", m_addr, |
m_addr = m_ireg & 0x0ffffff; |
// printf("FAST READ, ADDR = %08x\n", m_addr); |
printf("EQSPI: QUAD READ, ADDR = %06x (%02x:%02x:%02x:%02x)\n", m_addr, |
(m_addr<0x1000000)?(m_mem[m_addr]&0x0ff):0, |
(m_addr<0x0ffffff)?(m_mem[m_addr+1]&0x0ff):0, |
(m_addr<0x0fffffe)?(m_mem[m_addr+2]&0x0ff):0, |
(m_addr<0x0fffffd)?(m_mem[m_addr+3]&0x0ff):0); |
assert((m_addr & (~(m_memmask)))==0); |
} else if (m_count == 8+24+8*4) { |
assert((m_addr & (~(MEMBYTES-1)))==0); |
} else if (m_count == 32+8) { |
QOREG(m_mem[m_addr++]); |
m_quad_mode = EQSPIF_QMODE_QSPI_ADDR; |
m_quad_mode = true; |
m_mode_byte = (m_ireg & 0x080); |
m_state = EQSPIF_QUAD_READ; |
printf("EQSPI: (QUAD) MODE BYTE = %02x\n", m_mode_byte); |
} else if ((m_count > 32+8)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
// printf("EQSPIF[%08x]/QR = %02x\n", |
// m_addr-1, m_oreg); |
} else { |
// printf("ERR: EQSPIF--TRYING TO READ WHILE BUSY! (count = %d)\n", m_count); |
m_oreg = 0; |
} |
break; |
case EQSPIF_QUAD_OREAD_CMD: |
if (m_count == 8+24) { |
m_addr = m_ireg & m_memmask; |
// printf("FAST READ, ADDR = %08x\n", m_addr); |
if (m_debug) printf("EQSPI: QUAD READ, ADDR = %06x (%02x:%02x:%02x:%02x)\n", m_addr, |
(m_addr<0x1000000)?(m_mem[m_addr]&0x0ff):0, |
(m_addr<0x0ffffff)?(m_mem[m_addr+1]&0x0ff):0, |
(m_addr<0x0fffffe)?(m_mem[m_addr+2]&0x0ff):0, |
(m_addr<0x0fffffd)?(m_mem[m_addr+3]&0x0ff):0); |
assert((m_addr & (~(m_memmask)))==0); |
} else if (m_count == 8+24+4*8) { |
QOREG(m_mem[m_addr]); |
m_quad_mode = EQSPIF_QMODE_SPI_ADDR; |
m_mode_byte = (m_ireg & 0x080); |
if (m_debug) printf("EQSPI: (QUAD) MODE BYTE = %02x\n", m_mode_byte); |
m_state = EQSPIF_QUAD_READ; |
} |
break; |
case EQSPIF_QUAD_READ: |
if ((m_count >= 64)&&(0 == (m_sreg&0x01))) { |
if (m_count == 24+8*4) {// Requires 8 QUAD clocks |
m_mode_byte = (m_ireg>>24) & 0x10; |
printf("EQSPI/QR: MODE BYTE = %02x\n", m_mode_byte); |
QOREG(m_mem[m_addr++]); |
// printf("EQSPIF[%08x]/QR = %02x\n", m_addr-1, m_oreg & 0x0ff); |
} else if ((m_count >= 64)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
printf("EQSPIF[%08x]/QR = %02x\n", m_addr-1, m_oreg & 0x0ff); |
} else { |
m_oreg = 0; |
if (m_debug) printf("EQSPI/QR ... m_count = %d\n", m_count); |
printf("EQSPI/QR ... m_count = %d\n", m_count); |
} |
break; |
case EQSPIF_PP: |
if (m_count == 32) { |
m_addr = m_ireg & m_memmask; |
m_addr = m_ireg & 0x0ffffff; |
if (m_debug) printf("EQSPI: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & (~(m_memmask)))==0); |
assert((m_addr & 0xfc00000)==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
686,15 → 669,16
} break; |
case EQSPIF_QPP: |
if (m_count == 32) { |
m_addr = m_ireg & m_memmask; |
m_quad_mode = EQSPIF_QMODE_SPI_ADDR; |
m_addr = m_ireg & 0x0ffffff; |
m_quad_mode = true; |
if (m_debug) printf("EQSPI/QR: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & (~(m_memmask)))==0); |
assert((m_addr & 0xfc00000)==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
} else if (m_count >= 40) { |
if (m_debug) printf("EQSPI: PROGRAM[%06x] = %02x\n", m_addr, m_ireg & 0x0ff); |
m_pmem[m_addr & 0x0ff] = m_ireg & 0x0ff; |
// printf("EQSPI/QR: PMEM[%02x] = 0x%02x -> %02x\n", m_addr & 0x0ff, m_ireg & 0x0ff, (m_pmem[(m_addr & 0x0ff)]&0x0ff)); |
m_addr = (m_addr & (~0x0ff)) | ((m_addr+1)&0x0ff); |
} break; |
case EQSPIF_SUBSECTOR_ERASE: |
/eqspiflashsim.h
2,7 → 2,7
// |
// Filename: eqspiflashsim.h |
// |
// Project: Wishbone Controlled Quad SPI Flash Controller |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: This library simulates the operation of an Extended Quad-SPI |
// commanded flash, such as the N25Q128A used on the Arty |
14,7 → 14,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015,2017, 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 |
27,7 → 27,7
// 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 |
// 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. |
// |
63,8 → 63,7
EQSPIF_RDID, |
EQSPIF_RELEASE, |
EQSPIF_FAST_READ, |
EQSPIF_QUAD_OREAD_CMD, |
EQSPIF_QUAD_IOREAD_CMD, |
EQSPIF_QUAD_READ_CMD, |
EQSPIF_QUAD_READ, |
EQSPIF_PP, |
EQSPIF_QPP, |
83,22 → 82,14
char *m_mem, *m_pmem, *m_otp, *m_lockregs; |
int m_last_sck; |
unsigned m_write_count, m_ireg, m_oreg, m_sreg, m_addr, |
m_count, m_vconfig, m_mode_byte, m_creg, m_membytes, |
m_memmask, m_nvconfig, m_evconfig, m_flagreg, m_nxtout[4]; |
bool mode, m_debug, m_otp_wp; |
m_count, m_vconfig, m_mode_byte, m_creg, |
m_nvconfig, m_evconfig, m_flagreg, m_nxtout[4]; |
bool m_quad_mode, m_debug, m_otp_wp; |
|
typedef enum { |
EQSPIF_QMODE_SPI = 0, |
EQSPIF_QMODE_QSPI_ADDR, |
EQSPIF_QMODE_SPI_ADDR |
} QUAD_MODE; |
QUAD_MODE m_quad_mode; |
|
public: |
EQSPIFLASHSIM(const int lglen = 24, bool debug = false); |
EQSPIFLASHSIM(void); |
void load(const char *fname) { load(0, fname); } |
void load(const unsigned addr, const char *fname); |
void load(const uint32_t offset, const char *data, const uint32_t len); |
void debug(const bool dbg) { m_debug = dbg; } |
bool debug(void) const { return m_debug; } |
bool write_enabled(void) const { return m_debug; } |
/Makefile
13,7 → 13,7
## |
################################################################################ |
## |
## Copyright (C) 2015-2017, 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 |
26,7 → 26,7
## 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 |
## 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. |
## |
38,82 → 38,36
## |
## |
CXX := g++ |
CFLAGS := -Wall -Og -g |
FLAGS := -Wall -Og -g |
OBJDIR := obj-pc |
RTLD := ../../rtl |
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"') |
VROOT := $(VERILATOR_ROOT) |
VINCD := $(VROOT)/include |
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I$(VINCD) -I$(VINCD)/vltstd |
EQSOURCES := eqspiflashsim.cpp eqspiflash_tb.cpp |
QSOURCES := qspiflashsim.cpp qspiflash_tb.cpp |
SOURCES := $(EQSOURCES) $(QSOURCES) |
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I$(VROOT)/include |
SOURCES := eqspiflashsim.cpp eqspiflash_tb.cpp |
VOBJDR := $(RTLD)/obj_dir |
RAWVLIB := verilated.cpp verilated_vcd_c.cpp |
VSRCS := $(addprefix $(VROOT)/include/,$(RAWVLIB)) |
VOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(RAWVLIB))) |
QOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(QSOURCES))) $(VOBJS) |
EQOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(EQSOURCES))) $(VOBJS) |
VLIB := $(VROOT)/include/verilated.cpp |
SIMSRCS := enetctrlsim.cpp eqspiflashsim.cpp |
all: qspiflash_tb pretest |
all: $(OBJDIR)/ eqspiflash_tb pretest |
|
$(OBJDIR)/: |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
|
$(OBJDIR)/%.o: %.cpp |
$(mk-objdir) |
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@ |
$(CXX) $(FLAGS) -c $^ -o $@ |
|
$(OBJDIR)/%.o: $(VINCD)/%.cpp |
$(mk-objdir) |
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@ |
eqspiflash_tb: eqspiflash_tb.cpp $(OBJDIR)/eqspiflashsim.o $(VOBJDR)/Veqspiflash__ALL.a |
$(CXX) $(FLAGS) $(INCS) $^ $(VOBJDR)/Veqspiflash__ALL.a $(VLIB) -o $@ |
|
eqspiflash_tb: $(EQOBJS) $(VOBJDR)/Veqspiflash__ALL.a |
$(CXX) $(CFLAGS) $(INCS) $(EQOBJS) $(VOBJDR)/Veqspiflash__ALL.a -o $@ |
|
qspiflash_tb: $(QOBJS) $(VOBJDR)/Vwbqspiflash__ALL.a $(VOBJS) |
$(CXX) $(CFLAGS) $(INCS) $(QOBJS) $(VOBJDR)/Vwbqspiflash__ALL.a -o $@ |
|
.PHONY: pretest |
pretest: qspiflash_tb eqspiflash_tb |
pretest: eqspiflash_tb |
@echo "The test bench has been created. Type make test, and look at" |
@echo "the end of its output to see if it (still) works." |
|
# .PHONY: test |
# test: eqspiflash_tb |
# ./eqspiflash_tb |
|
.PHONY: test qtest eqtest |
test: qtest eqtest |
qtest: qspiflash_tb |
./qspiflash_tb |
eqtest: eqspiflash_tb qtest |
.PHONY: test |
test: eqspiflash_tb |
./eqspiflash_tb |
|
define mk-objdir |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
endef |
|
|
define build-depends |
@echo "Building dependency file(s)" |
$(mk-objdir) |
@$(CXX) $(CFLAGS) $(INCS) -MM $(SOURCES) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
|
tags: $(SOURCES) $(HEADERS) |
@echo "Generating tags" |
@ctags $(SOURCES) $(HEADERS) |
|
.PHONY: clean |
clean: |
rm -f ./eqspiflash_tb qspiflash_tb |
rm -rf $(OBJDIR)/ |
|
.PHONY: depends |
depends: tags |
$(build-depends) |
|
$(OBJDIR)/depends.txt: $(SOURCES) $(HEADERS) |
$(build-depends) |
|
-include $(OBJDIR)/depends.txt |
rm ./eqspiflash_tb |
/eqspiflash_tb.cpp
2,7 → 2,7
// |
// Filename: eqspiflash_tb.cpp |
// |
// Project: Wishbone Controlled Quad SPI Flash Controller |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: To determine whether or not the eqspiflash module works. Run |
// this with no arguments, and check whether or not the last line |
27,7 → 27,7
// 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 |
// 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. |
// |
39,7 → 39,6
// |
// |
#include "verilated.h" |
#include "verilated_vcd_c.h" |
#include "Veqspiflash.h" |
#include "eqspiflashsim.h" |
|
47,19 → 46,15
const int BOMBCOUNT = 2048; |
|
class EQSPIFLASH_TB { |
unsigned long m_tickcount; |
long m_tickcount; |
Veqspiflash *m_core; |
EQSPIFLASHSIM *m_flash; |
bool m_bomb; |
VerilatedVcdC* m_trace; |
|
public: |
|
EQSPIFLASH_TB(void) { |
Verilated::traceEverOn(true); |
m_core = new Veqspiflash; |
m_flash= new EQSPIFLASHSIM(24,true); |
m_trace= NULL; |
m_flash= new EQSPIFLASHSIM; |
} |
|
unsigned operator[](const int index) { return (*m_flash)[index]; } |
70,24 → 65,12
m_flash->load(0,fname); |
} |
|
void trace(const char *fname) { |
if (!m_trace) { |
m_trace = new VerilatedVcdC; |
m_core->trace(m_trace, 99); |
m_trace->open(fname); |
} |
} |
void tick(void) { |
m_core->i_clk_200mhz = 1; |
|
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->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)", |
m_tickcount, |
(m_core->i_wb_cyc)?"CYC":" ", |
188,7 → 171,7
(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%s", |
printf("%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__lcl_key)?" KEY":"", |
(m_core->v__DOT__preproc__DOT__ctreg_stb)?" CTSTB":"", |
199,7 → 182,7
// (m_core->v__DOT__preproc__DOT__lcl_reg)?" LCLREG":"", |
// (m_core->v__DOT__w_xip)?" XIP":"", |
// (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__ewproc__DOT__cyc)?" WRCYC":"", |
(m_core->v__DOT__bus_pipewr)?" WRPIPE":"", |
224,15 → 207,10
|
|
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(); |
if (m_trace) m_trace->dump(10*m_tickcount); |
m_core->i_clk_82mhz = 0; |
m_core->i_clk_200mhz = 0; |
m_core->eval(); |
if (m_trace) m_trace->dump(10*m_tickcount+5); |
|
m_tickcount++; |
|
264,10 → 242,11
m_core->i_wb_we = 0; |
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)) |
tick(); |
} tick(); |
else |
tick(); |
|
m_core->i_wb_data_stb = 0; |
m_core->i_wb_ctrl_stb = 0; |
284,7 → 263,7
m_core->i_wb_ctrl_stb = 0; |
|
if(errcount >= BOMBCOUNT) { |
printf("RD-SETTING ERR TO TRUE!!!!!\n"); |
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"); |
345,7 → 324,7
m_core->i_wb_cyc = 0; |
|
if(errcount >= THISBOMBCOUNT) { |
printf("RDI-SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", 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"); |
382,7 → 361,7
m_core->i_wb_ctrl_stb = 0; |
|
if(errcount >= BOMBCOUNT) { |
printf("WB-SETTING ERR TO TRUE!!!!!\n"); |
printf("SETTING ERR TO TRUE!!!!!\n"); |
m_bomb = true; |
} tick(); |
} |
425,7 → 404,7
m_core->i_wb_ctrl_stb = 0; |
|
if(errcount >= BOMBCOUNT) { |
printf("WBI-SETTING ERR TO TRUE!!!!!\n"); |
printf("SETTING ERR TO TRUE!!!!!\n"); |
m_bomb = true; |
} tick(); |
} |
482,7 → 461,7
m_core->i_wb_ctrl_stb = 0; |
|
if(errcount >= BOMBCOUNT) { |
printf("WBS-SETTING ERR TO TRUE!!!!!\n"); |
printf("SETTING ERR TO TRUE!!!!!\n"); |
m_bomb = true; |
} tick(); |
} |
503,8 → 482,6
rdbuf = new unsigned[4096]; |
tb->setflash(0,0); |
|
tb->trace("eqspi.vcd"); |
|
tb->wb_tick(); |
rdv = tb->wb_read(QSPIFLASH); |
printf("READ[0] = %04x\n", rdv); |
602,13 → 579,7
} printf("VECTOR TEST PASSES! (QUAD)\n"); |
|
printf("Attempting to switch to Quad mode with XIP\n"); |
{ |
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(3, tb->wb_read(3)|0x08); |
// tb->wb_write(0, 0x22000000); |
|
printf("Attempting to read in Quad mode, using XIP mode\n"); |
643,12 → 614,10
printf("Attempting to erase subsector 1\n"); |
tb->wb_write(0, 0xf20005be); |
|
while((tb->wb_read(0)&0x01000000)&&(!tb->bombed())) |
while (tb->wb_read(0)&0x01000000) |
; |
while((tb->wb_read(0)&0x80000000)&&(!tb->bombed())) |
while(tb->wb_read(0)&0x80000000) |
; |
if (tb->bombed()) |
goto test_failure; |
if (tb->wb_read(QSPIFLASH+1023) != rdbuf[0]) |
goto test_failure; |
if (tb->wb_read(QSPIFLASH+2048) != rdbuf[1]) |