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

Subversion Repositories qspiflash

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 16 to Rev 15
    Reverse comparison

Rev 16 → Rev 15

/qspiflash/trunk/bench/cpp/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) {
/qspiflash/trunk/bench/cpp/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);
/qspiflash/trunk/bench/cpp/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:
/qspiflash/trunk/bench/cpp/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; }
/qspiflash/trunk/bench/cpp/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
/qspiflash/trunk/bench/cpp/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])
/qspiflash/trunk/rtl/eqspiflash.v
2,7 → 2,7
//
// Filename: eqspiflash.v
//
// Project: Wishbone Controlled Quad SPI Flash Controller
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: Provide access to the flash device on an Arty, via the Extended
// SPI interface. Reads and writes will use the QuadSPI interface
90,7 → 90,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.
//
102,7 → 102,7
//
//
// `define QSPI_READ_ONLY
module eqspiflash(i_clk_82mhz, i_rst,
module eqspiflash(i_clk_200mhz, i_rst,
// Incoming wishbone connection(s)
// The two strobe lines allow the data to live on a
// separate part of the master bus from the control
120,7 → 120,7
// Debug the interface
o_dbg);
 
input i_clk_82mhz, i_rst;
input i_clk_200mhz, i_rst;
// Wishbone bus inputs
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
input [21:0] i_wb_addr; // 24 bits of addr space
142,7 → 142,7
output wire [31:0] o_dbg;
 
initial o_cmd_accepted = 1'b0;
always @(posedge i_clk_82mhz)
always @(posedge i_clk_200mhz)
o_cmd_accepted=((i_wb_data_stb)||(i_wb_ctrl_stb))&&(~o_wb_stall);
//
// lleqspi
154,7 → 154,7
reg [1:0] spi_len;
wire [31:0] spi_out;
wire spi_valid, spi_busy, spi_stopped;
lleqspi lowlvl(i_clk_82mhz, spi_wr, spi_hold, spi_word, spi_len,
lleqspi lowlvl(i_clk_200mhz, spi_wr, spi_hold, spi_word, spi_len,
spi_spd, spi_dir, spi_recycle, spi_out, spi_valid, spi_busy,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
assign spi_stopped = (o_qspi_cs_n)&&(~spi_busy)&&(~spi_wr);
181,7 → 181,7
// Live parameters
w_xip, w_quad, w_idloaded, w_leave_xip;
reg bus_wip;
qspibus preproc(i_clk_82mhz, i_rst,
qspibus preproc(i_clk_200mhz, i_rst,
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb,
i_wb_we, i_wb_addr, i_wb_data,
bus_wb_ack, bus_wb_stall, bus_wb_data,
211,7 → 211,7
wire [31:0] rd_spi_word;
wire [1:0] rd_spi_len;
//
readqspi rdproc(i_clk_82mhz, bus_readreq, bus_piperd,
readqspi rdproc(i_clk_200mhz, bus_readreq, bus_piperd,
bus_other_req,
bus_addr, rd_bus_ack,
rd_qspi_req, rd_qspi_grant,
241,7 → 241,7
//
wire w_ew_wip;
//
writeqspi ewproc(i_clk_82mhz, bus_wreq,bus_ereq,
writeqspi ewproc(i_clk_200mhz, bus_wreq,bus_ereq,
bus_pipewr, bus_endwr,
bus_addr, bus_data,
ew_bus_ack, ew_qspi_req, ew_qspi_grant,
268,7 → 268,7
wire [31:0] ct_spi_word;
wire [1:0] ct_spi_len;
//
ctrlspi ctproc(i_clk_82mhz,
ctrlspi ctproc(i_clk_200mhz,
bus_ctreq, bus_wr, bus_addr[3:0], bus_data, bus_sector,
ct_qspi_req, ct_grant,
ct_spi_wr, ct_spi_hold, ct_spi_word, ct_spi_len,
299,7 → 299,7
//
wire w_id_wip;
//
idotpqspi idotp(i_clk_82mhz, bus_idreq,
idotpqspi idotp(i_clk_200mhz, bus_idreq,
bus_wr, bus_pipewr, bus_addr[4:0], bus_data, id_bus_ack,
id_qspi_req, id_qspi_grant,
id_spi_wr, id_spi_hold, id_spi_word, id_spi_len,
311,7 → 311,7
reg owned;
reg [1:0] owner;
initial owned = 1'b0;
always @(posedge i_clk_82mhz) // 7 inputs (spi_stopped is the CE)
always @(posedge i_clk_200mhz) // 7 inputs (spi_stopped is the CE)
if ((~owned)&&(spi_stopped))
begin
casez({rd_qspi_req,ew_qspi_req,id_qspi_req,ct_qspi_req})
338,7 → 338,7
assign ct_grant = (owned)&&(owner == 2'b11);
 
// Module controller
always @(posedge i_clk_82mhz)
always @(posedge i_clk_200mhz)
case(owner)
2'b00: begin
spi_wr <= (owned)&&(rd_spi_wr);
382,7 → 382,7
initial bus_wip = 1'b0;
initial last_wip = 1'b0;
initial o_interrupt = 1'b0;
always @(posedge i_clk_82mhz)
always @(posedge i_clk_200mhz)
begin
bus_wip <= w_ew_wip || w_id_wip;
last_wip <= bus_wip;
391,7 → 391,7
 
 
// Now, let's return values onto the wb bus
always @(posedge i_clk_82mhz)
always @(posedge i_clk_200mhz)
begin
// Ack our internal bus controller. This means the command was
// accepted, and the bus can go on to looking for the next
451,7 → 451,7
//
reg pending, lcl_wrreq, lcl_ctreq, lcl_ack, ack, wp_err, wp;
reg lcl_reg;
reg [12:0] esector;
reg [14:0] esector;
reg [21:0] next_addr;
 
 
583,7 → 583,7
wire new_req;
assign new_req = (pending)&&(~last_pending);
 
initial esector = 13'h00;
initial esector = 15'h00;
initial o_wrreq = 1'b0;
initial o_erreq = 1'b0;
initial wp_err = 1'b0;
613,9 → 613,9
 
if (set_sector)
begin
esector[11:0] <= { o_data[21:14], 4'h0 };
esector[13:0] <= { o_data[23:14], 4'h0 };
wp <= (o_data[30])&&(new_req)||(wp)&&(~new_req);
esector[12] <= o_data[28]; // Subsector
esector[14] <= o_data[28]; // Subsector
if (o_data[28])
begin
esector[3:0] <= o_data[13:10];
679,10 → 679,10
end
 
 
assign o_wb_data[31:0] = { i_wip, ~wp, i_quad, esector[12],
assign o_wb_data[31:0] = { i_wip, ~wp, i_quad, esector[14],
i_idloaded, wp_err, i_xip, i_spi_stopped,
2'b00, esector[11:0], 10'h00 };
assign o_sector = { 2'b00, esector[11:0], 8'h00 }; // 22 bits
esector[13:0], 10'h00 };
assign o_sector = { esector[13:0], 8'h00 }; // 22 bits
assign o_other = (r_other)||(o_idreq);
 
endmodule
698,7 → 698,6
`define RD_XIP 4'h7
`define RD_GO_TO_IDLE 4'h8
`define RD_GO_TO_XIP 4'h9
`define RD_IDLE_QUAD_PORT 4'ha
 
module readqspi(i_clk, i_readreq, i_piperd, i_other_req, i_addr, o_bus_ack,
o_qspi_req, i_grant,
747,16 → 746,11
`RD_IDLE: begin
r_requested <= 1'b0;
o_qspi_req <= 1'b0;
// 0x0b is a fast read, uses all SPI protocol
// 0x6b is a Quad output fast read, uses SPI cmd,
// SPI address, QSPI data
// 0xeb is a Quad I/O fast read, using SPI cmd,
// QSPI address and data
o_spi_word <= { ((i_quad)? 8'hEB: 8'h0b), i_addr, 2'b00 };
o_spi_word <= { ((i_quad)? 8'h6B: 8'h0b), i_addr, 2'b00 };
o_spi_wr <= 1'b0;
o_spi_dir <= 1'b0;
o_spi_spd <= 1'b0;
o_spi_len <= (i_quad)? 2'b00 : 2'b11;
o_spi_len <= 2'b11;
r_xip <= (i_xip)&&(i_quad);
r_leave_xip <= 1'b0; // Not in it, so can't leave it
r_quad <= i_quad;
769,30 → 763,15
o_spi_wr <= 1'b1; // Write the address
o_qspi_req <= 1'b1;
if (accepted)
begin
rd_state <= (r_quad) ? `RD_IDLE_QUAD_PORT : `RD_SLOW_DUMMY;
o_spi_word[31:8] <= o_spi_word[23:0];
end end
`RD_IDLE_QUAD_PORT: begin
o_spi_wr <= 1'b1; // Write the command
o_qspi_req <= 1'b1;
o_spi_spd <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b10;
 
// We haven't saved our address any where but in the
// SPI word we just sent. Hence, let's just
// grab it from there.
if (accepted)
rd_state <= `RD_SLOW_DUMMY;
end
`RD_SLOW_DUMMY: begin
o_spi_wr <= 1'b1; // Write 8 dummy clocks--this is the same for
o_qspi_req <= 1'b1; // both Quad I/O, Quad O, and fast-read commands
o_spi_wr <= 1'b1; // Write 8 dummy clocks
o_qspi_req <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_spd <= r_quad;
o_spi_word[31:0] <= (r_xip) ? 32'h00 : 32'hffffffff;
o_spi_len <= (r_quad)? 2'b11:2'b00; // 8 clocks
o_spi_spd <= 1'b0;
o_spi_word[31:24] <= (r_xip) ? 8'h00 : 8'hff;
o_spi_len <= 2'b00; // 8 clocks = 8-bits
if (accepted)
rd_state <= (r_quad)?`RD_QUAD_READ_DATA
: `RD_SLOW_READ_DATA;
/qspiflash/trunk/rtl/llqspi.v
1,4 → 1,4
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Filename: llqspi.v
//
10,12 → 10,12
// When not in use, unlike our previous SPI work, no bits will
// toggle.
//
// Creator: Dan Gisselquist, Ph.D.
// Creator: Dan Gisselquist
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, Gisselquist Technology, LLC
// Copyright (C) 2015, 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
28,7 → 28,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.
//
36,7 → 36,7
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
193,7 → 193,6
initial o_valid = 1'b0;
initial o_busy = 1'b0;
initial r_input = 31'h000;
initial o_mod = `QSPI_MOD_SPI;
always @(posedge i_clk)
if ((state == `QSPI_IDLE)&&(o_sck))
begin
201,16 → 200,16
o_valid <= 1'b0;
o_busy <= 1'b0;
o_mod <= `QSPI_MOD_SPI;
r_word <= i_word;
r_spd <= i_spd;
r_dir <= i_dir;
if (i_wr)
begin
r_word <= i_word;
state <= `QSPI_START;
r_spd <= i_spd;
r_dir <= i_dir;
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
o_cs_n <= 1'b0;
// o_sck <= 1'b1;
o_busy <= 1'b1;
o_sck <= 1'b1;
end
end else if (state == `QSPI_START)
begin // We come in here with sck high, stay here 'til sck is low
229,9 → 228,13
o_busy <= 1'b1;
o_valid <= 1'b0;
if (r_spd)
begin
o_dat <= r_word[31:28];
else
// r_word <= { r_word[27:0], 4'h0 };
end else begin
o_dat <= { 3'b110, r_word[31] };
// r_word <= { r_word[30:0], 1'b0 };
end
end else if (~o_sck)
begin
o_sck <= 1'b1;
273,16 → 276,6
// this state. Here we chose to either STOP or
// continue and transmit more.
o_sck <= (i_hold); // No clocks while holding
r_spd <= i_spd;
r_dir <= i_dir;
if (i_spd)
begin
r_word <= { i_word[27:0], 4'h0 };
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8 - 6'h4;
end else begin
r_word <= { i_word[30:0], 1'b0 };
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8 - 6'h1;
end
if((~o_busy)&&(i_wr))// Acknowledge a new request
begin
state <= `QSPI_BITS;
290,29 → 283,51
o_sck <= 1'b0;
 
// Read the new request off the bus
r_spd <= i_spd;
r_dir <= i_dir;
// Set up the first bits on the bus
o_mod <= (i_spd) ? { 1'b1, i_dir } : `QSPI_MOD_SPI;
if (i_spd)
begin
o_dat <= i_word[31:28];
else
r_word <= { i_word[27:0], 4'h0 };
// spi_len <= spi_len - 4;
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
- 6'h4;
end else begin
o_dat <= { 3'b110, i_word[31] };
r_word <= { i_word[30:0], 1'b0 };
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
- 6'h1;
end
 
// Read a bit upon any transition
o_valid <= 1'b1;
if (~o_mod[1])
begin
r_input <= { r_input[29:0], i_miso };
o_word <= { r_input[30:0], i_miso };
end else if (o_mod[1])
begin
r_input <= { r_input[26:0], i_dat };
o_word <= { r_input[27:0], i_dat };
end
end else begin
o_sck <= 1'b1;
state <= (i_hold)?`QSPI_HOLDING : `QSPI_STOP;
o_busy <= (~i_hold);
end
 
// Read a bit upon any transition
o_valid <= 1'b1;
if (~o_mod[1])
begin
r_input <= { r_input[29:0], i_miso };
o_word <= { r_input[30:0], i_miso };
end else if (o_mod[1])
begin
r_input <= { r_input[26:0], i_dat };
o_word <= { r_input[27:0], i_dat };
// Read a bit upon any transition
o_valid <= 1'b1;
if (~o_mod[1])
begin
r_input <= { r_input[29:0], i_miso };
o_word <= { r_input[30:0], i_miso };
end else if (o_mod[1])
begin
r_input <= { r_input[26:0], i_dat };
o_word <= { r_input[27:0], i_dat };
end
end
end else if (state == `QSPI_HOLDING)
begin
/qspiflash/trunk/rtl/wbqspiflash.v
55,45 → 55,45
`include "flash_config.v"
`default_nettype none
//
`define WBQSPI_RESET 5'd0
`define WBQSPI_RESET_QUADMODE 5'd1
`define WBQSPI_IDLE 5'd2
`define WBQSPI_RDIDLE 5'd3 // Idle, but in fast read mode
`define WBQSPI_WBDECODE 5'd4
`define WBQSPI_RD_DUMMY 5'd5
`define WBQSPI_QRD_ADDRESS 5'd6
`define WBQSPI_QRD_DUMMY 5'd7
`define WBQSPI_READ_CMD 5'd8
`define WBQSPI_READ_DATA 5'd9
`define WBQSPI_WAIT_TIL_RDIDLE 5'd10
`define WBQSPI_READ_ID_CMD 5'd11
`define WBQSPI_READ_ID 5'd12
`define WBQSPI_READ_STATUS 5'd13
`define WBQSPI_READ_CONFIG 5'd14
`define WBQSPI_WAIT_TIL_IDLE 5'd15
`define WBQSPI_RESET 5'h0
`define WBQSPI_RESET_QUADMODE 5'h1
`define WBQSPI_IDLE 5'h2
`define WBQSPI_RDIDLE 5'h3 // Idle, but in fast read mode
`define WBQSPI_WBDECODE 5'h4
`define WBQSPI_RD_DUMMY 5'h5
`define WBQSPI_QRD_ADDRESS 5'h6
`define WBQSPI_QRD_DUMMY 5'h7
`define WBQSPI_READ_CMD 5'h8
`define WBQSPI_READ_DATA 5'h9
`define WBQSPI_WAIT_TIL_RDIDLE 5'h10
`define WBQSPI_READ_ID_CMD 5'h11
`define WBQSPI_READ_ID 5'h12
`define WBQSPI_READ_STATUS 5'h13
`define WBQSPI_READ_CONFIG 5'h14
`define WBQSPI_WAIT_TIL_IDLE 5'h15
//
//
`ifndef READ_ONLY
//
`define WBQSPI_WAIT_WIP_CLEAR 5'd16
`define WBQSPI_CHECK_WIP_CLEAR 5'd17
`define WBQSPI_CHECK_WIP_DONE 5'd18
`define WBQSPI_WEN 5'd19
`define WBQSPI_PP 5'd20 // Program page
`define WBQSPI_QPP 5'd21 // Program page, 4 bit mode
`define WBQSPI_WR_DATA 5'd22
`define WBQSPI_WR_BUS_CYCLE 5'd23
`define WBQSPI_WRITE_STATUS 5'd24
`define WBQSPI_WRITE_CONFIG 5'd25
`define WBQSPI_ERASE_WEN 5'd26
`define WBQSPI_ERASE_CMD 5'd27
`define WBQSPI_ERASE_BLOCK 5'd28
`define WBQSPI_CLEAR_STATUS 5'd29
`define WBQSPI_IDLE_CHECK_WIP 5'd30
`define WBQSPI_WAIT_WIP_CLEAR 5'h16
`define WBQSPI_CHECK_WIP_CLEAR 5'h17
`define WBQSPI_CHECK_WIP_DONE 5'h18
`define WBQSPI_WEN 5'h19
`define WBQSPI_PP 5'h20 // Program page
`define WBQSPI_QPP 5'h21 // Program page, 4 bit mode
`define WBQSPI_WR_DATA 5'h22
`define WBQSPI_WR_BUS_CYCLE 5'h23
`define WBQSPI_WRITE_STATUS 5'h24
`define WBQSPI_WRITE_CONFIG 5'h25
`define WBQSPI_ERASE_WEN 5'h26
`define WBQSPI_ERASE_CMD 5'h27
`define WBQSPI_ERASE_BLOCK 5'h28
`define WBQSPI_CLEAR_STATUS 5'h29
`define WBQSPI_IDLE_CHECK_WIP 5'h30
//
`endif
 
module wbqspiflash(i_clk,
module wbqspiflash(i_clk_100mhz,
// Internal wishbone connections
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
i_wb_addr, i_wb_data,
103,11 → 103,10
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
o_interrupt);
parameter ADDRESS_WIDTH=22;
localparam AW = ADDRESS_WIDTH-2;
input wire i_clk;
input wire i_clk_100mhz;
// Wishbone, inputs first
input wire i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
input wire [(AW-1):0] i_wb_addr;
input wire [(ADDRESS_WIDTH-3):0] i_wb_addr;
input wire [31:0] i_wb_data;
// then outputs
output reg o_wb_ack;
131,7 → 130,7
wire [3:0] w_qspi_dat;
wire [1:0] w_qspi_mod;
// wire [22:0] spi_dbg;
llqspi lldriver(i_clk,
llqspi lldriver(i_clk_100mhz,
spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir,
spi_out, spi_valid, spi_busy,
w_qspi_sck, w_qspi_cs_n, w_qspi_mod, w_qspi_dat,
167,15 → 166,13
endgenerate
reg [7:0] last_status;
reg [9:0] reset_counter;
reg quad_mode_enabled;
reg spif_cmd, spif_override;
reg [31:0] spif_data;
reg [4:0] state;
reg spif_ctrl, spif_req;
reg alt_cmd, alt_ctrl;
wire [(ADDRESS_WIDTH-17):0] spif_sector;
assign spif_sector = spif_addr[(AW-1):14];
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14];
 
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg };
 
186,13 → 183,9
initial spi_len = 2'b00;
initial quad_mode_enabled = 1'b0;
initial o_interrupt = 1'b0;
initial spif_override = 1'b1;
initial spif_ctrl = 1'b0;
always @(posedge i_clk)
always @(posedge i_clk_100mhz)
begin
spif_override <= 1'b0;
alt_cmd <= (reset_counter[9:8]==2'b10)?reset_counter[3]:1'b1; // Toggle CS_n
alt_ctrl <= (reset_counter[9:8]==2'b10)?reset_counter[0]:1'b1; // Toggle clock too
if (state == `WBQSPI_RESET)
begin
// From a reset, we should
210,8 → 203,7
state <= `WBQSPI_RESET_QUADMODE;
spif_req <= 1'b0;
spif_override <= 1'b1;
last_status <= 8'h00; //
reset_counter <= 10'h3fc; //
last_status <= 8'hfc; //
// This guarantees that we aren't starting in quad
// I/O mode, where the FPGA configuration scripts may
// have left us.
227,20 → 219,15
o_wb_stall <= 1'b1;
 
// Do something ...
if (reset_counter == 10'h00)
if (last_status == 8'h00)
begin
spif_override <= 1'b0;
state <= `WBQSPI_IDLE;
 
// Find out if we can use Quad I/O mode ...
state <= `WBQSPI_READ_CONFIG;
spi_wr <= 1'b1;
spi_len <= 2'b01;
spi_in <= { 8'h35, 24'h00};
 
end else begin
reset_counter <= reset_counter - 10'h1;
last_status <= last_status - 8'h1;
spif_override <= 1'b1;
spif_cmd <= last_status[3]; // Toggle CS_n
spif_ctrl <= last_status[0]; // Toggle clock too
end
end else if (state == `WBQSPI_IDLE)
begin
324,10 → 311,10
o_wb_stall <= 1'b1;
case(i_wb_addr[1:0])
2'b00: begin // Erase command register
write_protect <= !i_wb_data[28];
write_protect <= ~i_wb_data[28];
o_wb_stall <= 1'b0;
 
if((i_wb_data[31])&&(!write_in_progress))
if((i_wb_data[31])&&(~write_in_progress))
begin
// Command an erase--ack it immediately
 
381,7 → 368,7
end
endcase
`endif
end else if (i_wb_ctrl_stb) // &&(!i_wb_we))
end else if (i_wb_ctrl_stb) // &&(~i_wb_we))
begin
case(i_wb_addr[1:0])
2'b00: begin // Read local register
457,7 → 444,7
spi_hold <= 1'b0;
spi_spd<= 1'b1;
spi_dir <= 1'b0; // Write (for now)
if ((i_wb_data_stb)&&(!i_wb_we))
if ((i_wb_data_stb)&&(~i_wb_we))
begin // Continue our read ... send the new address / mode
o_wb_stall <= 1'b1;
spi_wr <= 1'b1;
464,7 → 451,7
spi_len <= 2'b10; // Write address, but not mode byte
spi_in <= { w_wb_addr, 8'ha0 };
state <= `WBQSPI_QRD_DUMMY;
end else if((i_wb_ctrl_stb)&&(!i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
end else if((i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00))
begin
// A local read that doesn't touch the device, so leave
// the device in its current state
1043,7 → 1030,7
// Do nothing here.
end else if ((i_wb_data_stb)&&(i_wb_we)
&&(i_wb_addr == (spif_addr+1))
&&(i_wb_addr[(AW-1):6]==spif_addr[(AW-1):6]))
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]==spif_addr[(ADDRESS_WIDTH-3):6]))
begin
spif_cmd <= 1'b1;
spif_data <= i_wb_data;
1116,7 → 1103,7
// together with setting our copy of the WIP bit
write_in_progress <= 1'b1;
// keeping track of which sector we just erased
erased_sector <= spif_data[(AW-1):14];
erased_sector <= spif_data[(ADDRESS_WIDTH-3):14];
// and marking this erase sector as no longer dirty
dirty_sector <= 1'b0;
 
1134,10 → 1121,11
o_wb_ack <= 1'b0;
spif_req <= (spif_req) && (i_wb_cyc);
// When the port clears, we can head back to idle
// No ack necessary, we ackd before getting
// here.
if ((~spi_busy)&&(~spi_wr))
begin
o_wb_ack <= spif_req;
state <= `WBQSPI_IDLE;
end
end else if (state == `WBQSPI_CLEAR_STATUS)
begin // Issue a clear status command
spi_wr <= 1'b1;
1197,8 → 1185,8
end
 
// Command and control during the reset sequence
assign o_qspi_cs_n = (spif_override)?alt_cmd :w_qspi_cs_n;
assign o_qspi_sck = (spif_override)?alt_ctrl:w_qspi_sck;
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod;
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat;
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n;
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck;
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod;
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat;
endmodule
/qspiflash/trunk/rtl/lleqspi.v
1,4 → 1,4
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Filename: lleqspi.v
//
10,12 → 10,12
// When not in use, unlike our previous SPI work, no bits will
// toggle.
//
// Creator: Dan Gisselquist, Ph.D.
// Creator: Dan Gisselquist
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// 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
28,7 → 28,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.
//
36,9 → 36,7
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////////////////////////////
`define EQSPI_IDLE 3'h0
`define EQSPI_START 3'h1
`define EQSPI_BITS 3'h2
/qspiflash/trunk/rtl/Makefile
1,4 → 1,4
################################################################################
##########################################################################/
##
## Filename: Makefile
##
12,9 → 12,9
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
################################################################################
##########################################################################/
##
## Copyright (C) 2015-2017, Gisselquist Technology, LLC
## Copyright (C) 2015, 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,16 → 26,11
## 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
## http:##www.gnu.org/licenses/gpl.html
##
##
################################################################################
##########################################################################/
##
##
all: test
45,13 → 40,12
VDIRFB:= $(FBDIR)/obj_dir
 
.PHONY: test
test: $(VDIRFB)/Veqspiflash__ALL.a $(VDIRFB)/Vwbqspiflash__ALL.a
test: $(VDIRFB)/Veqspiflash__ALL.a
# test: $(VDIRFB)/Vfastmaster__ALL.a
 
$(VDIRFB)/Veqspiflash.h $(VDIRFB)/Veqspiflash.cpp $(VDIRFB)/Veqspiflash.mk: eqspiflash.v lleqspi.v
$(VDIRFB)/Vwbqspiflash.h $(VDIRFB)/Vwbqspiflash.cpp $(VDIRFB)/Vwbqspiflash.mk: wbqspiflash.v llqspi.v
$(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v
verilator -trace -cc $*.v
verilator -cc $*.v
 
$(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk
cd $(VDIRFB); make -f V$*.mk
/qspiflash/trunk/rtl/flash_config.v
1,4 → 1,4
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Filename: flashconfig.v
//
10,12 → 10,13
// the configuration only includes whether the flash is read only or not.
// Other configuration options may be added later.
//
// Creator: Dan Gisselquist, Ph.D.
//
// Creator: Dan Gisselquist
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
// Copyright (C) 2015, 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
28,7 → 29,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.
//
36,9 → 37,8
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
//
`ifndef FLASH_CONFIG_V
`define FLASH_CONFIG_V
//

powered by: WebSVN 2.1.0

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