URL
https://opencores.org/ocsvn/qspiflash/qspiflash/trunk
Subversion Repositories qspiflash
Compare Revisions
- This comparison shows the changes necessary to convert path
/qspiflash/trunk
- from Rev 13 to Rev 14
- ↔ Reverse comparison
Rev 13 → Rev 14
/bench/cpp/eqspiflashsim.cpp
110,7 → 110,7
m_ireg = m_oreg = 0; |
m_sreg = 0x01c; |
m_creg = 0x001; // Initial creg on delivery |
m_config = 0x7; // Volatile configuration register |
m_vconfig = 0x7; // Volatile configuration register |
m_nvconfig = 0x0fff; // Nonvolatile configuration register |
m_quad_mode = false; |
m_mode_byte = 0; |
431,12 → 431,12
break; |
case 0x81: // Write volatile config register |
m_state = EQSPIF_WRCR; |
if (m_debug) printf("EQSPI: WRITING CONFIG REGISTER: %02x\n", m_config); |
if (m_debug) printf("EQSPI: WRITING VOLATILE CONFIG REGISTER: %02x\n", m_vconfig); |
break; |
case 0x85: // Read volatile config register |
m_state = EQSPIF_RDCR; |
if (m_debug) printf("EQSPI: READING CONFIG REGISTER: %02x\n", m_config); |
QOREG(m_config>>8); |
if (m_debug) printf("EQSPI: READING VOLATILE CONFIG REGISTER: %02x\n", m_vconfig); |
QOREG(m_vconfig); |
break; |
case 0x9e: // Read ID (fall through) |
case 0x9f: // Read ID |
508,19 → 508,19
} |
break; |
case EQSPIF_WRCR: // Write volatile config register, 0x81 |
if (m_count == 8) { |
m_config = m_ireg & 0x0ff; |
printf("Setting volatile config register to %08x\n", m_config); |
assert((m_config & 0xfb)==0x8b); |
if (m_count == 8+8) { |
m_vconfig = m_ireg & 0x0ff; |
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) { |
if (m_count == 8+8) { |
m_nvconfig = m_ireg & 0x0ffdf; |
printf("Setting nonvolatile config register to %08x\n", m_config); |
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) { |
if (m_count == 8+8) { |
m_evconfig = m_ireg & 0x0ff; |
printf("Setting enhanced volatile config register to %08x\n", m_evconfig); |
assert((m_evconfig & 0x0d7)==0xd7); |
592,7 → 592,7
QOREG(m_sreg); |
break; |
case EQSPIF_RDCR: |
if (m_debug) printf("Read CREG = %02x\n", m_creg); |
if (m_debug) printf("Read VCONF = %02x\n", m_vconfig); |
QOREG(m_creg); |
break; |
case EQSPIF_FAST_READ: |
637,7 → 637,7
// 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); |
// printf("ERR: EQSPIF--TRYING TO READ WHILE BUSY! (count = %d)\n", m_count); |
m_oreg = 0; |
} |
break; |
/bench/cpp/eqspiflashsim.h
82,7 → 82,7
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_config, m_mode_byte, m_creg, |
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; |
|
bench/cpp
Property changes :
Added: svn:ignore
## -0,0 +1,2 ##
+eqspiflash_tb
+obj-pc
Index: doc/spec.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: doc/src/spec.tex
===================================================================
--- doc/src/spec.tex (revision 13)
+++ doc/src/spec.tex (revision 14)
@@ -45,7 +45,7 @@
\title{Specification}
\author{Dan Gisselquist, Ph.D.}
\email{dgisselq (at) opencores.org}
-\revision{Rev.~0.2}
+\revision{Rev.~0.3}
\begin{document}
\pagestyle{gqtekspecplain}
\titlepage
@@ -67,6 +67,7 @@
copy.
\end{license}
\begin{revisionhistory}
+0.3 & 8/11/2016 & Gisselquist & Added information on the Extended Quad SPI controller\\\hline
0.2 & 5/26/2015 & Gisselquist & Minor spelling changes\\\hline
0.1 & 5/13/2015 & Gisselquist & First Draft \\\hline
\end{revisionhistory}
@@ -81,6 +82,12 @@
JTAG cables, or other proprietary loading capabilities such as Digilent's
Adept program. As a result, all interactions with the board need to take
place using open source tools, and the board must be able to reprogram itself.
+
+That was the beginning of the QSPI flash controller.
+
+The EQSPI flash controller started from a similar need for a board that had
+an EQSPI flash. That particular board was an Arty, and so the EQSPI flash
+controller has been designed around the Arty platform.
\end{preface}
\chapter{Introduction}
@@ -87,39 +94,55 @@
\pagenumbering{arabic}
\setcounter{page}{1}
-The Quad SPI Flash controller handles all necessary queries and accesses to
+This document discusses the design and usage of two cores: a Quad SPI flash
+controller, and a newer Extended Quad SPI flash controller. In general, the
+two are {\em very} similar. However, their construction and register usage
+are subtly different, so the user will need to pay attention to these
+differences.
+
+Both Flash controllers handle all of the necessary queries and accesses to
and from a SPI Flash device that has been augmented with an additional
two data lines and enabled with a mode allowing all four data lines to
work together in the same direction at the same time. Since the interface
was derived from a SPI interface, most of the interaction takes place using
normal SPI protocols and only some commands work at the higher four bits
-at a time speed.
+at a time speed. This remains true, even though the newer Extended SPI flash
+controller allows control accesses and Dual I/O and Quad I/O speeds: control
+interactions remain at SPI speeds, and only data reads and writes take place
+at the Quad I/O speed.
-This particular controller attempts to mask the underlying operation of the
-SPI device behind a wishbone interface, to make it so that reads and writes
+Both controllers attempt to mask the underlying operation of the
+Flash device behind a wishbone interface, to make it so that reads and writes
are as simple as using the wishbone interface. However, the difference
between erasing (turning bits from '0' to '1') and programming (turning bits
from '1' to '0') breaks this model somewhat. Therefore, reads from the
-device act like normal wishbone reads, writes program the device and
-sort of work with the wishbone, while erase commands require another register
-to control. Please read the Operations chapter for a detailed description
-of how to perform these relevant operations.
+device act like normal wishbone reads, writes program the device (if the write
+protect is properly removed) and sort of work with the wishbone, while erase
+commands require another register to control. Please read the Operations
+chapter for a detailed description of how to perform these relevant operations.
-This controller implements the interface for the Quad SPI flash found on the
-Basys-3 board built by Digilent, Inc. Some portions of the interface may
-be specific to the Spansion S25FL032P chip used on this board, and the
+This QSPI controller implements the interface for the Quad SPI flash found on
+the Basys-3 board built by Digilent, Inc, as well as their CMod-S6 board. A
+similar controller has been modified for the flash on the XuLA2-LX25 SoC.
+It is possible that some portions of the interface may be specific to the
+Spansion S25FL032P chip used on the Basys-3 board, and the
100~MHz system clock found on the board, although there is no reason the
controller needs to be limited to this architecture. It just happens to be
-the one I have been designing to and for.
+the one the QSPI controller was designed to and for.
-For a description of how the internals of this core work, feel free to browse
+The Extended QSPI controller, or EQSPI controller, was designed to control the
+Micron Serial NOR Flash Memory, N25Q128A, found on Digilent's Arty board. As
+with the Spansion chip, it is possible that parts of the interface are specific
+to this board and this chip.
+
+For a description of how the internal of each core work, feel free to browse
through the Architecture chapter.
-The registers that control this core are discussed in the Registers chapter.
+The registers that control the cores are discussed in the Registers chapter.
As required, you can find a wishbone datasheet in Chapt.~\ref{chap:wishbone}.
-The final pertinent information for implementing this core is found in the
+The final pertinent information for implementing the cores is found in the
I/O Ports chapter, Chapt.~\ref{chap:ioports}.
As always, write me if you have any questions or problems.
@@ -126,12 +149,20 @@
\chapter{Architecture}\label{chap:arch}
+The internal architecture of each of these two cores is different, reflecting
+their different chips and goals. The QSPI controller is designed to run using
+a 50~MHz SPI clock, generated from a 100~MHz controller clock. The EQSPI
+controller, however, was designed to prove that a 100~MHz SPI clock could be
+used to drive a flash controller from a 200~MHz controller clock. As a result
+of these clocking differences, the architectures of each are quite different.
+
+\section{QSPI Flash Architecture}
As built, the core consists of only two components: the wishbone quad SPI
flash controller, {\tt wbqspiflash}, and the lower level quad SPI driver,
{\tt llqspi}. The controller issues high level read/write commands to the
lower level driver, which actually implements the Quad SPI protocol.
-Pictorally, this looks something like Fig.~\ref{fig:arch}.
+Pictorally, this looks something like Fig.~\ref{fig:qspi-arch}.
\begin{figure}\begin{center}\begin{pspicture}(-2in,0)(2in,3.5in)
\rput(0,2.5in){
\rput(-0.9in,0){\psline{->}(0,1in)(0,0in)}
@@ -186,7 +217,7 @@
\psline{<->}(0.3in,0.5in)(0.3in,0)}
\rput[l](0.4in,0.25in){Quad SPI I/O lines}
\end{pspicture}\end{center}
-\caption{Architecture Diagram}\label{fig:arch}
+\caption{QSPI Architecture Diagram}\label{fig:qspi-arch}
\end{figure}
This is also what you will find if you browse through the code.
@@ -247,14 +278,192 @@
while the higher level driver maintains the state machine controlling which
commands need to be issued and when.
+\section{EQSPI Flash Architecture}
+The EQSPI flash architecture was an entire redesign. The reason for the
+redesign is quite simple: the QSPI flash controller was just way to complex
+to run at a 200~MHz clock. This new and modified architecture is shown in
+Fig.~\ref{fig:eqspi-arch}.
+\begin{figure}\begin{center}\begin{pspicture}(-2in,-1.2in)(2.75in,5.5in)
+% \rput(0,0){\psframe(-2in,-1.2in)(2.75in,5.5in)}
+\rput(0,4.5in){%
+ \rput(-0.9in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.92in,0.5in){\tt i\_wb\_cyc}
+ \rput(-0.7in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.72in,0.5in){\tt i\_wb\_data\_stb}
+ \rput(-0.5in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.52in,0.5in){\tt i\_wb\_ctrl\_stb}
+ \rput(-0.3in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.32in,0.5in){\tt i\_wb\_we}
+ \rput(-0.1in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.12in,0.5in){\tt i\_wb\_addr}
+ \rput( 0.1in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.08in,0.5in){\tt i\_wb\_data}
+ %
+ \rput( 0.5in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.48in,0.5in){\tt o\_wb\_ack}
+ \rput( 0.7in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.68in,0.5in){\tt o\_wb\_stall}
+ \rput( 0.9in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.88in,0.5in){\tt o\_wb\_data}
+ \rput( 1.1in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 1.08in,0.5in){\tt o\_int}}
+\rput(0,4.0in){%
+ \rput(0,0){\psframe(-1.2in,0)(1.2in,0.5in)}
+ \rput(0,0.25in){\tt qspibus}}
+ % Wires
+\rput(0,3.0in){%
+ \rput(0,0){\psframe(-2in,0)(-1.05in,0.5in)}
+ \rput(-1.5in,0.25in){\tt readqspi}}
+\rput(0,3.0in){%
+ \rput(0,0){\psframe(-0.95in,0)(-0.05in,0.5in)}
+ \rput(-0.5in,0.25in){\tt writeqspi}}
+\rput(0,3.0in){%
+ \rput(0,0){\psframe(0.05in,0)(0.95in,0.5in)}
+ \rput(0.5in,0.25in){\tt ctrlspi}}
+\rput(0,3.0in){%
+ \rput(0,0){\psframe(1.05in,0)(2in,0.5in)}
+ \rput(1.5in,0.25in){\tt idotpqspi}}
+\rput(0,2.0in){%
+ \rput(0,0){\pspolygon(-1in,0)(1in,0)(1.5in,0.5in)(-1.5in,0.5in)}
+ \rput(0,0.25in){Command Mux}}
+\rput(0,1.0in){
+ \rput(-1.0in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-1.02in,0.5in){\tt spi\_wr}
+ \rput(-0.8in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.82in,0.5in){\tt spi\_hold}
+ \rput(-0.6in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.62in,0.5in){\tt spi\_in}
+ \rput(-0.4in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.42in,0.5in){\tt spi\_len}
+ \rput(-0.2in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.22in,0.5in){\tt spi\_spd}
+ \rput( 0.0in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}(-0.02in,0.5in){\tt spi\_dir}
+ \rput( 0.2in,0){\psline{->}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.18in,0.5in){\tt spi\_word}
+ \rput( 0.6in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.58in,0.5in){\tt spi\_out}
+ \rput( 0.8in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.78in,0.5in){\tt spi\_valid}
+ \rput( 1.0in,0){\psline{<-}(0,1in)(0,0in)}
+ \rput[b]{90}( 0.98in,0.5in){\tt spi\_busy}}
+\rput(0,0.5in){
+ \rput(0,0){\psframe(-1.25in,0)(1.25in,0.5in)}
+ \rput(0,0.25in){\tt lleqspi}}
+ \rput(0,0){
+ \rput[b]{90}(-1.02in,0.25in){\tt bmod}
+ \psline{->}(-1.0in,0.5in)(-1.0in,-0.35in)(-0.7in,-0.35in)
+ \psline{->}(-0.5in,-0.35in)(-0.3in,-0.35in)
+ \psline{->}(-0.1in,-0.35in)( 0.1in,-0.35in)
+ \psline{->}( 0.3in,-0.35in)( 0.5in,-0.35in)
+ \psline{<->}(-0.6in,0.5in)(-0.6in,0)
+ \rput[b]{90}(-0.62in,0.25in){\tt dat[0]}
+ \psline{<->}(-0.2in,0.5in)(-0.2in,0)
+ \rput[b]{90}(-0.22in,0.25in){\tt dat[1]}
+ \psline{<->}(0.2in,0.5in)(0.2in,0)
+ \rput[b]{90}(0.18in,0.25in){\tt dat[2]}
+ \psline{<->}(0.6in,0.5in)(0.6in,0)
+ \rput[b]{90}(0.58in,0.25in){\tt dat[3]}
+ \psline{->}(1.0in,0.5in)(1.0in,0)
+ \rput[b]{90}(0.98in,0.25in){\tt clk/cs}}
+ \rput[l](1.1in,0.25in){Top level Interface Wires}
+\rput(0,-0.7in){
+ \rput(-0.6in,0){\rput(0,0){\psframe(-0.1in,0)(0.1in,0.7in)}\rput{90}(0,0.35in){\tt xioddr}}
+ \rput(-0.2in,0){\rput(0,0){\psframe(-0.1in,0)(0.1in,0.7in)}\rput{90}(0,0.35in){\tt xioddr}}
+ \rput( 0.2in,0){\rput(0,0){\psframe(-0.1in,0)(0.1in,0.7in)}\rput{90}(0,0.35in){\tt xioddr}}
+ \rput( 0.6in,0){\rput(0,0){\psframe(-0.1in,0)(0.1in,0.7in)}\rput{90}(0,0.35in){\tt xioddr}}
+ \rput( 1.0in,0){\rput(0,0){\psframe(-0.1in,0)(0.1in,0.7in)}\rput{90}(0,0.35in){\tt xioddr}}
+ \rput(0,0){\psline{<->}(-0.6in,-0.5in)(-0.6in,0)
+ \psline{<->}(-0.2in,-0.5in)(-0.2in,0)
+ \psline{<->}(0.2in,-0.5in)(0.2in,0)
+ \psline{<->}(0.6in,-0.5in)(0.6in,0)
+ \psline{<-}(1.0in,-0.5in)(1.0in,0)}
+ \rput[l](1.1in,-0.25in){Quad SPI I/O lines}}
+\end{pspicture}\end{center}
+\caption{EQSPI Architecture Diagram}\label{fig:eqspi-arch}
+\end{figure}
+All of the various modules of this architecture, save the {\tt lleqspi} and
+{\tt xioddr} modules, are found in the {\tt eqspiflash.v} file.
+
+The goal of this architecture was to reduce the amount of logic necessary to
+process the many various requests this controller allows.
+
+At the top, all requests to the controller come from the bus straight into the
+{\tt qspibus} module. The purpose of this module is to parse the various
+commands to their respective modules. One command, however, never gets
+parsed: the request to read from the erase register. This register returns
+the status of the controller, and particularly whether or not it is still
+busy with the last erase or write command.
+
+The top level controller has the ability to latch a bus request. Such requests
+are then issued to the lower level controllers. However, they remain latched
+in the top level controller until the lower controller acknowledges them, at
+which point the bus may advance to its next request. Depending on the lower
+level controller, this may not occurr until the lower level transaction is
+complete, or nearly so.
+
+The lower level controllers also communicate with the command multiplexer
+beneath them. Each controller has a request line, whereby it requests access
+to the lowerest level controller. Once granted, the controller maintains
+control of that lowest level until it is released. In this fashion, for
+example, the {\tt readqspi} controller implements the execute in place
+functionality: it reads from the interface, then maintains the interface.
+If another driver requests the interface, the read controller reactivates
+itself and returns the interface to a non--XIP mode.
+
+Now, of these four controllers, the {\tt readqspi} controller handles reads
+from the device. Reads are always done in Quad SPI mode, if so enabled,
+and the device is left in XIP mode until another controller requests the
+interface. XIP mode is left by reading a 32'bit value from the device at
+address zero.
+
+The {\tt writeqspi} controller handles both program and erase requests.
+Upon completion of either request, the {\tt writeqspi} controller holds on
+to the interface perpetually reading from the status register until the device
+is no longer busy.
+
+The {\tt ctrlspi} controller handles requests to read and write the various
+control registers internal to the device. These include the status register,
+the non--volatile configuration register, the volatile configuration register,
+the extended volatile configuration register, the flags register, and the
+lock registers associated with the most recently selected sector (set in the
+erase register). Writes to these registers, though, aren't quite so simple:
+One must first disable the write protect in the erase control register,
+thus setting the Write Enable Latch of the device, before the device
+will accept write requests.
+
+Finally, the {\tt idotpqspi} controller handles the logic associated with the
+ID memory internal to the controller, as well as both reading and writing the
+One Time Programmable (OTP) registers, and eventually locking the OTP registers
+so that they can no longer be read or written. As with the {\tt writeqspi}
+module, write requests do not release the port until the write has completed.
+Reading the erase register will provide the status on this operation.
+
+Moving down in the architecture to the command multiplexer, this portion is
+really not that remarkable. It takes one clock for requests to go through the
+command multiplexer and get to the lower level controller, and it grants
+and releases control to the various controllers.
+
+The {\tt lleqspi} controller is the lower level controller for this device.
+It's operation mirrors that of the {\tt llqspi} lower--level controller from
+the QSPI flash. The biggest difference is that the Micron chip requires a
+particular recovery time following any command other than a read command
+leaving the chip in the XIP mode.
+
+What is new in this controller is the requirement for the output ports to
+be connected to the I/O banks via {\tt ODDR} and {\tt IDDR} modules. These
+are contained within the {\tt xioddr} modules. Since the wires can change
+direction, the {\tt bmod} pair of wires provides an indication of which
+direction the various bits of the port are moving--either as inputs or outputs.
+
\chapter{Operation}\label{chap:ops}
This implementation attempts to encapsulate (hide) the details of the chip
from the user, so that the user does not need to know about the various
subcommands going to and from the chip. The original goal was to make the
chip act like any other read/write memory, however the difference between
-erasing and programming the chip made this impossible. Therefore a separate
-register is given to erase any given sector, while reads and writes may proceed
-(almost) as normal.
+erasing and programming a flash chip made this impossible. Therefore a
+separate register is provided to control the erase any given sector, while
+reads and writes may proceed (almost) as normal.
The wishbone bus that this controller works with, however, is a 32--bit
bus. Address one on the bus addresses a completely different 32--bit word
@@ -267,19 +476,31 @@
From a high level perspective, this core provides read/write access to the
device either via the wishbone (read and program), or through a control
register found on the wishbone (the EREG). Programming the device consists of
-first erasing the region of interest. This will set all the bits to '1' in
-that region. After erasing the region, the region can then be programmed,
-setting some of the '1' bits to '0's. When neither erase nor program
-operation is going on, the device may be read. The section will describe
-each of those operations in detail.
+first clearing the write protect, and then erasing the region of interest.
+This will set all the bits to `1' in that region. After erasing the region,
+the write protect may again be cleared, and then the region can then be
+programmed, setting some of the `1' bits to '0's. When neither erase nor
+program operation is going on, the device may be read. The section will
+describe each of those operations in detail.
To erase a sector of the device, two writes are required to the EREG register.
The first write turns off the write protect bit, whereas the second write
-commands the erase itself. The first write should equal \hbox{0x1000\_0000},
-the second should be any address within the sector to be erased together
-with setting the high bit of the register or \hbox{0x8000\_0000} plus the
-address. After this second write, the controller will issue a write--enable
-command to the device, followed by a sector erase command. In summary,
+commands the erase itself. The first write should equal \hbox{0x1000\_0000}
+for the QSPI controller and \hbox{0x4000\_0000} for the EQSPI controller.
+After this write, the EQSPI controller will issue a Write Enable command to the
+device. For the QSPI controller, the second write should be any address within
+the sector to be erased together with setting the high bit of the register.
+This is equivalent to setting it to \hbox{0x8000\_0000} plus the address. The
+EQSPI flash driver is subtly different in that it requires a {\em key} to erase.
+Hence, for the EQSPI flash driver, one must write \hbox{0xc000\_01be} plus the
+first address in the sector to accomplish the same result. Further, the
+EQSPI flash controller allows the erasing of 4~kB subsegments. To do this,
+the second write must also set the subsector bit, so it looks like writing
+\hbox{0xd000\_01be} plus the first address in the subsector. After
+this second write, the QSPI controller will issue a write--enable
+command to the device (the EQSPI controller will have already issued the
+write--enable), followed by a sector erase command. In summary, for the
+QSPI flash:
\begin{enumerate}
\item Disable write protect by writing \hbox{\tt 0x1000\_0000} to the EREG
register
@@ -287,18 +508,30 @@
address to the EREG register. (Remember, this is the {\em word
address} of interest, not the {\em byte address}.)
\end{enumerate}
+and for the EQSPI flash:
+\begin{enumerate}
+\item Disable write protect by writing \hbox{\tt 0x4000\_0000} to the EREG
+ register
+\item Command the sector (64~kB) erase by writing \hbox{\tt 0xc000\_01be} plus
+ the first address in the segment to the EREG register.
+ In the case of a subsegment (4~kB) erase command, write
+ \hbox{\tt 0xd000\_01be} plus the first address in the subsegment to
+ the EREG register.
+\end{enumerate}
+
While the device is erasing, the controller will idle while checking the
status register over and over again. Should you wish to read from the EREG
-during this time, the high order bit of the EREG register will be set.
-Once the erase is complete, this bit will clear, the interrupt line will
-be strobed high, and other operations may take then place on the part. Any
-attempt to perform another operation on the part prior to that time will stall
-the bus until the erase is complete.
+during this time, the high order bit of the EREG register will be set indicating
+that a write is in progress (WIP). Once the erase is complete, this bit will
+clear, the interrupt line will be strobed high, and other operations may take
+then place on the part. Any attempt to perform another operation on the part
+prior to that time will stall the bus until the erase is complete.
Once an area has been erased, it may then be programmed. To program the device,
first disable the write protect by writing a {\tt 0x1000\_0000} to the EREG
-register. After that, you may then write to the area in question whatever
+register for the QSPI controller, or {\tt 0x4000\_0000} for the EQSPI
+controller. After that, you may then write to the area in question whatever
values you wish to program. One 256~byte (64~bus word) page may be programmed
at a time. Pages start on even boundaries, such as addresses {\tt 0x040},
{\tt 0x080}, {\tt 0x0100}, etc. To program a whole page at a time, write the
@@ -308,13 +541,15 @@
In summary,
\begin{enumerate}
\item Disable the write protect by writing a {\tt 0x1000\_0000} to the EREG
- register.
+ register when using the QSPI flash controller, or {\tt 0x4000\_0000}
+ for the EQSPI flash controller.
\item Write the page of interest to the data memory of the device.
The first address should start at the beginning of a page (bottom six
bits zero), and end at the end of the page (bottom six bits one, top
bits identical). Writes of less than a page are okay. Writes crossing
- page boundaries will stall the device.
+ page boundaries will stall the bus, while waiting for the first write
+ to complete before attempting to start the second write.
\end{enumerate}
While the device is programming a page, the controller will idle while
@@ -324,29 +559,42 @@
the EREG register will be cleared and the interrupt line strobed. Prior to this
time, any other bus operation will stall the bus until the write completes.
-Reads are simple, you just read from the device and the device does everything
-you expect. Reads may be pipelined. Further, if the device is ever commanded
-to read the configuration register, revealing that the quad SPI mode is
-enabled, then reads will take place four bits at a time from the bus.
-In general, it will take 72 device clocks (at 50~MHz) to read the first word
-from memory, and 32 for every pipelined word read thereafter provided that
-the reads are in memory order. Likewise, in quad SPI mode, it will
-instead take 28 device clocks to read the first word, and 8 device clocks
-to read every word thereafter again provided that the subsequent pipelined
-reads are in memory order.
+Reads are simple for the QSPI flash controller, you just read from the device
+and the device does everything you expect. Reads may be pipelined. To use
+the QSPI mode of transferring 4--bits at a time, when using the QSPI controller,
+you must first either read (or set) the quad mode bit in the configuration
+register. This will enable Quad--I/O mode reads. Once enabled, reads will
+take place four bits at a time from the bus.
-The Quad SPI device provides for a special mode following a read, where the
+Using the EQSPI flash controller, reads are almost as simple, but with a couple
+of caveats. The first caveat is that the controller defaults to Quad I/O mode,
+and will not leave it. The problem is that this mode depends upon a variable
+number of dummy cycles set to 8. Hence, before issuing reads from the data
+section of the device, the number of dummy cycles will need to be set in either
+the volatile or non--volatile configuration register.
+
+
+% When using the QSPI controller,
+% it will take 72 device clocks (at 50~MHz) to read the first word
+% from memory using the QSPI controller, and 32 for every pipelined word read
+% thereafter provided that the reads are in memory order. Likewise, in quad
+% SPI mode, it will instead take 28 device clocks to read the first word,
+% and 8 device clocks to read every word thereafter again provided that the
+% subsequent pipelined reads are in memory order.
+
+Both controllers provide for a special mode following a read, where the
next read may start immediately in Quad I/O mode following a 12~clock
-setup. This controller leaves the device in this mode following any initial
+setup for the QSPI controller, or 16~clocks for the EQSPI controller. Both
+controllers leaves the device in this mode following any initial
read. Therefore, back to back reads as part of separate bus cycles will only
-take 20~clocks to read the first word, and 8~clocks per word thereafter.
-Other commands, however, such as erasing, writing, reading from the status,
-configuration, or ID registers, will take require a 32~device clock operation
-before entering.
+take 20~clocks (24 for EQSPI) to read the first word, and 8~clocks per word
+thereafter. Other commands, however, such as erasing, writing, reading from
+the status, configuration, or ID registers, will require a 32~device
+clock operation before entering.
\section{Low Level}
-At a lower level, this core implements the following Quad SPI commands:
+At a lower level, the QSPI core implements the following Quad SPI commands:
\begin{enumerate}
\item FAST\_READ, when a read is requested and Quad mode has not been enabled.
\item QIOR, or quad I/O high performance read mode. This is the default read
@@ -382,7 +630,9 @@
\chapter{Registers}\label{chap:regs}
-This implementation supports four control registers. These are the EREG
+\section{QSPI Controller}
+
+The QSPI controller supports four control registers. These are the EREG
register, the configuration register, the status register, and the device ID,
as shown and listed in Table.~\ref{tbl:reglist}.
\begin{table}[htbp]
@@ -394,10 +644,10 @@
Status & 2 & 8 & R/W & The devices status register.\\\hline
ID & 3 & 16 & R & Reads the 16-bit ID from the device.\\\hline
\end{reglist}
-\caption{List of Registers}\label{tbl:reglist}
+\caption{List of QSPI Registers}\label{tbl:reglist}
\end{center}\end{table}
-\section{EREG Register}
+\subsection{EREG Register}
The EREG register was designed to be a replacement for all of the device
registers, leaving all the other registers a part of a lower level access
used only in debugging the device. This would've been the case, save that
@@ -470,7 +720,7 @@
would work. Thus, to erase a sector, write the sector address, together with
an erase bit, to this register.
-\section{Config Register}
+\subsection{Config Register}
The Quad Flash device also has a non--volatile configuration register, as
shown in Tbl.~\ref{tbl:confbits}. Writes to this register are program events,
@@ -510,7 +760,7 @@
Further information on this register is available in the device data sheet.
-\section{Status Register}
+\subsection{Status Register}
The definitions of the bits in the status register are shown in
Tbl.~\ref{tbl:statbits}. For operating this core, only the write in progress
bit is relevant. All other bits should be set to zero.
@@ -542,7 +792,7 @@
\caption{Status bit definitions}\label{tbl:statbits}
\end{center}\end{table}
-\section{Device ID}
+\subsection{Device ID}
Reading from the Device ID register causes the core controller to issue
a RDID {\tt 0x9f} command. The bytes returned are first the manufacture
@@ -565,15 +815,17 @@
\begin{center}
\begin{wishboneds}
Revision level of wishbone & WB B4 spec \\\hline
-Type of interface & Slave, (Block) Read/Write \\\hline
+Type of interface & Slave, (Pipelind) Read/Write \\\hline
Port size & 32--bit \\\hline
Port granularity & 32--bit \\\hline
Maximum Operand Size & 32--bit \\\hline
Data transfer ordering & Little Endian \\\hline
-Clock constraints & Must be 100~MHz or slower \\\hline
+Clock constraints & Must be 100~MHz or slower (QSPI)\\\cline{2-2}
+ & Must be 200~MHz or slower (EQSPI)\\\hline
Signal Names & \begin{tabular}{ll}
Signal Name & Wishbone Equivalent \\\hline
- {\tt i\_clk\_100mhz} & {\tt CLK\_I} \\
+ {\tt i\_clk\_100mhz} & {\tt CLK\_I} { (QSPI)} \\
+ {\tt i\_clk\_200mhz} & {\tt CLK\_I} { (EQSPI)}\\
{\tt i\_wb\_cyc} & {\tt CYC\_I} \\
{\tt i\_wb\_ctrl\_stb} & {\tt STB\_I} \\
{\tt i\_wb\_data\_stb} & {\tt STB\_I} \\
@@ -585,24 +837,51 @@
{\tt o\_wb\_data} & {\tt DAT\_O}
\end{tabular}\\\hline
\end{wishboneds}
-\caption{Wishbone Datasheet for the Quad SPI Flash controller}\label{tbl:wishbone}
+\caption{Wishbone Datasheet for the (E)QSPI Flash controller}\label{tbl:wishbone}
\end{center}\end{table}
+The EQSPI flash controller has a further simplified wishbone usage: the strobe
+lines, whether {\tt i\_wb\_ctrl\_stb} or {\tt i\_wb\_data\_stb}, must be
+guaranteed low any time {\tt i\_wb\_cyc} is low. This simplifies transaction
+processing internal to the controller, and is part of the method of getting the
+controller running at 200~MHz.
+
+\section{EQSPI Controller}
+\subsection{EREG Register}
+\subsection{Status Register}
+\subsection{Non--Volatile Configuration Register}
+\subsection{Volatile Configuration Register}
+\subsection{Extended Volatile Configuration Register}
+\subsection{Sector Lock Register}
+\subsection{Flag Status Register}
+\subsection{Identification memory}
+\subsection{One--Time Programmable Memory}
+
\chapter{Clocks}\label{chap:clocks}
-This core is based upon the Basys--3 design. The Basys--3 development board
+The QSPI core is based upon the Basys--3 design. The Basys--3 development board
contains one external 100~MHz clock. This clock is divided by two to create
the 50~MHz clock used to drive the device. According to the data sheet,
it should be possible to run this core at up to 160~MHz, however I have not
-tested it at such speeds. See Table.~\ref{tbl:clocks}.
-\begin{table}[htbp]
-\begin{center}
-\begin{clocklist}
+tested it at such speeds. See Table.~\ref{tbl:qspi-clocks}.
+\begin{table}[htbp]\begin{center}\begin{clocklist}
i\_clk\_100mhz & External & 160 & & System clock.\\\hline
\end{clocklist}
-\caption{List of Clocks}\label{tbl:clocks}
+\caption{List of QSPI Controller Clocks}\label{tbl:qspi-clocks}
\end{center}\end{table}
+The EQSPI core is based upon a very similar Arty design, but one that instead
+uses a 200~MHz core clock frequency. In a fashion similar to the QSPI
+controller, this clock is divided down to create a 100~MHz clock to command
+the device. Hence, the EQSPI clock is much faster, as shown in
+Table.~\ref{tbl:eqspi-clocks}.
+\begin{table}[htbp]\begin{center}\begin{clocklist}
+i\_clk\_200mhz & External & 200 & & System clock.\\\hline
+\end{clocklist}
+\caption{List of EQSPI Controller Clocks}\label{tbl:eqspi-clocks}
+\end{center}\end{table}
+
+
\chapter{I/O Ports}\label{chap:ioports}
There are two interfaces that this device supports: a wishbone interface, and
the interface to the Quad--SPI flash itself. Both of these have their own
@@ -646,7 +925,7 @@
an error for both strobe lines to be on at the same time.
With respect to the Quad SPI interface itself, one piece of glue logic
-is necessary to tie the Quad SPI flash I/O to the in/out port at the top
+is necessary to tie the QSPI flash I/O to the in/out port at the top
level of the device. Specifically, these two lines must be added somewhere:
\begin{tabbing}
assign {\tt io\_qspi\_dat} = \= (\~{\tt qspi\_mod[1]})?(\{2'b11,1'bz,{\tt qspi\_dat[0]}\}) \hbox{\em // Serial mode} \\
@@ -659,6 +938,8 @@
mode, the hold and write protect lines are effectively eliminated in this
design in favor of faster speed I/O (i.e., Quad I/O).
+The EQSPI controller is similar, but the glue logic is more involved.
+
\begin{table}[htbp]
\begin{center}
\begin{portlist}
@@ -684,7 +965,8 @@
\begin{table}[htbp]
\begin{center}
\begin{portlist}
-i\_clk\_100mhz & 1 & Input & The 100~MHz clock driving all interactions.\\\hline
+i\_clk\_100mhz & 1 & Input & The 100~MHz clock driving all QSPI
+ interactions.\\\hline
o\_interrupt & 1 & Output & An strobed interrupt line indicating the end of
any erase or write transaction. This line will be high for exactly
one clock cycle, indicating that the core is again available for
/rtl/eqspiflash.v
63,7 → 63,8
// Attempted reads before buffer is full will stall bus until |
// buffer is read. Writes act like the asynch-Read-ID command, |
// and will cause the controller to read the buffer. |
// 13.-14. Unused, mapped to Asynch-read-ID |
// 13. Reset Enable |
// 14. Reset Memory |
// 15. OTP control word |
// Write zero to permanently lock OTP |
// Read to determine if OTP is permanently locked |
178,7 → 179,7
bus_pipewr, bus_endwr, bus_ctreq, bus_idreq, |
bus_other_req, |
// Live parameters |
w_xip, w_quad, w_idloaded; |
w_xip, w_quad, w_idloaded, w_leave_xip; |
reg bus_wip; |
qspibus preproc(i_clk_200mhz, i_rst, |
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, |
218,7 → 219,7
rd_spi_spd, rd_spi_dir, rd_spi_recycle, |
spi_out, spi_valid, |
spi_busy, spi_stopped, rd_data_ack, rd_data, |
w_quad, w_xip); |
w_quad, w_xip, w_leave_xip); |
|
// |
// Write/Erase flash module |
268,12 → 269,12
wire [1:0] ct_spi_len; |
// |
ctrlspi ctproc(i_clk_200mhz, |
bus_ctreq, bus_wr, bus_addr[2:0], bus_data, bus_sector, |
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, |
ct_spi_spd, ct_spi_dir, |
spi_out, spi_valid, spi_busy, spi_stopped, |
ct_ack, ct_data_ack, ct_data, w_xip, w_quad); |
ct_ack, ct_data_ack, ct_data, w_leave_xip, w_xip, w_quad); |
assign ct_spi_hold = 1'b0; |
assign ct_spi_spd = 1'b0; |
|
504,6 → 505,8
||(pending)&&(ctreg_stb)&&(~lcl_ack)&&(~i_ack); |
if (~o_wb_stall) |
begin // Bus command accepted! |
if (i_data_stb) |
next_addr <= i_addr + 22'h1; |
if ((i_data_stb)||(i_ctrl_stb)) |
begin |
pending <= 1'b1; |
510,7 → 513,6
o_addr <= i_addr; |
o_data <= i_data; |
o_wr <= i_we; |
next_addr <= i_addr + 22'h1; |
end |
|
if ((i_data_stb)&&(~i_we)) |
529,14 → 531,14
5'h5: lcl_ctreq <= 1'b1; |
5'h6: lcl_ctreq <= 1'b1; |
5'h7: lcl_ctreq <= 1'b1; |
5'h8: o_idreq <= 1'b1; // ID[0] |
5'h9: o_idreq <= 1'b1; // ID[1] |
5'ha: o_idreq <= 1'b1; // ID[2] |
5'hb: o_idreq <= 1'b1; // ID[3] |
5'hc: o_idreq <= 1'b1; // ID[4] |
5'hd: o_idreq <= 1'b1; // |
5'he: o_idreq <= 1'b1; |
5'hf: o_idreq <= 1'b1; // Program OTP register |
5'h8: o_idreq <= 1'b1; // ID[0] |
5'h9: o_idreq <= 1'b1; // ID[1] |
5'ha: o_idreq <= 1'b1; // ID[2] |
5'hb: o_idreq <= 1'b1; // ID[3] |
5'hc: o_idreq <= 1'b1; // ID[4] |
5'hd: lcl_ctreq <= 1'b1; // |
5'he: lcl_ctreq <= 1'b1; |
5'hf: o_idreq <= 1'b1; // Program OTP register |
default: begin o_idreq <= 1'b1; end |
endcase |
end else if (i_ctrl_stb) |
559,9 → 561,9
lcl_wrreq <= 1'b0; |
end |
|
if ((i_data_stb)&&(~o_wb_stall)) |
o_piperd <= ((~i_we)&&(~o_wb_stall)&&(pipeable)&&(i_addr == next_addr)); |
else if ((i_ack)||(((i_ctrl_stb)||(i_data_stb))&&(~o_wb_stall))) |
if ((i_data_stb)&&((~o_wb_stall)||(i_ack))) |
o_piperd <= ((~i_we)&&(pipeable)&&(i_addr == next_addr)); |
else if ((i_ack)&&(~i_data_stb)) |
o_piperd <= 1'b0; |
if ((i_data_stb)&&(~o_wb_stall)) |
pipeable <= (~i_we); |
581,6 → 583,7
wire new_req; |
assign new_req = (pending)&&(~last_pending); |
|
initial esector = 15'h00; |
initial o_wrreq = 1'b0; |
initial o_erreq = 1'b0; |
initial wp_err = 1'b0; |
612,9 → 615,9
begin |
esector[13:0] <= { o_data[23:14], 4'h0 }; |
wp <= (o_data[30])&&(new_req)||(wp)&&(~new_req); |
esector[14] <= o_data[28]; // Subsector |
if (o_data[28]) |
begin |
esector[14] <= o_data[28]; |
esector[3:0] <= o_data[13:10]; |
end |
end |
701,7 → 704,7
o_spi_wr, o_spi_hold, o_spi_word, o_spi_len, |
o_spi_spd, o_spi_dir, o_spi_recycle, |
i_spi_data, i_spi_valid, i_spi_busy, i_spi_stopped, |
o_data_ack, o_data, i_quad, i_xip); |
o_data_ack, o_data, i_quad, i_xip, o_leave_xip); |
input i_clk; |
input i_readreq, i_piperd, i_other_req; |
input [21:0] i_addr; |
717,6 → 720,7
output reg o_data_ack; |
output reg [31:0] o_data; |
input i_quad, i_xip; |
output wire o_leave_xip; |
|
reg accepted; |
initial accepted = 1'b0; |
786,13 → 790,13
rd_state <= `RD_GO_TO_IDLE; |
end |
`RD_QUAD_READ_DATA: begin |
o_qspi_req <= 1'b1; |
o_spi_dir <= 1'b1; |
o_spi_spd <= 1'b1; |
o_spi_len <= 2'b11; |
o_qspi_req <= 1'b1; // Insist that we keep the port |
o_spi_dir <= 1'b1; // Read |
o_spi_spd <= 1'b1; // Read at Quad rates |
o_spi_len <= 2'b11; // Read 4-bytes |
o_spi_recycle <= (r_leave_xip)? 1'b1: 1'b0; |
invalid_ack_pipe[0] <= (!r_requested); |
r_requested <= (r_requested)||(accepted); |
r_requested <= (r_requested)||(accepted); // Make sure at least one request goes through |
o_data_ack <= (!invalid_ack_pipe[3])&&(i_spi_valid)&&(r_requested)&&(~r_leave_xip); |
o_bus_ack <= (r_requested)&&(accepted)&&(i_piperd)&&(~r_leave_xip); |
o_spi_wr <= (~r_requested)||(i_piperd); |
868,6 → 872,7
end |
|
assign o_spi_hold = 1'b0; |
assign o_leave_xip = r_leave_xip; |
|
endmodule |
|
1119,12 → 1124,13
o_spi_spd, o_spi_dir, |
i_spi_data, i_spi_valid, i_spi_busy, |
i_spi_stopped, |
o_bus_ack, o_data_ack, o_data, o_xip, o_quad); |
o_bus_ack, o_data_ack, o_data, |
i_leave_xip, o_xip, o_quad); |
input i_clk; |
// From the WB bus controller |
input i_req; |
input i_wr; |
input [2:0] i_addr; |
input [3:0] i_addr; |
input [31:0] i_data; |
input [21:0] i_sector_address; |
// To/from the arbiter |
1144,6 → 1150,7
output reg o_bus_ack, o_data_ack; |
output reg [31:0] o_data; |
// Configuration items that we may have configured. |
input wire i_leave_xip; |
output reg o_xip; |
output wire o_quad; |
|
1181,13 → 1188,13
ctcmd_len <= 2'b00; // 8bit command (for all but Lock regs) |
r_ctdat_len <= 1'b0; // 8bit data (read or write) |
ctdat_wr <= i_wr; |
casez({ i_addr[2:0], i_wr, i_data[30] }) |
5'b00010: begin // Write Disable |
casez({ i_addr[3:0], i_wr, i_data[30] }) |
6'b000010: begin // Write Disable |
ctcmd_word[31:24] <= 8'h04; |
ctdat_skip <= 1'b1; |
ctbus_ack <= 1'b0; |
end |
5'b00011: begin // Write enable |
6'b000011: begin // Write enable |
ctcmd_word[31:24] <= 8'h06; |
ctdat_skip <= 1'b1; |
ctbus_ack <= 1'b0; |
1194,7 → 1201,7
end |
// 4'b0010?: begin // Read Status register |
// Moved to defaults section |
5'b0011?: begin // Write Status register (Requires WEL) |
6'b00011?: begin // Write Status register (Requires WEL) |
ctcmd_word[31:24] <= 8'h01; |
`ifdef CT_SAFE |
ctdat_word <= { 6'h00, i_data[1:0], 24'h00 }; |
1202,11 → 1209,11
ctdat_word <= { i_data[7:0], 24'h00 }; |
`endif |
end |
5'b0100?: begin // Read NV-Config register (two bytes) |
6'b00100?: begin // Read NV-Config register (two bytes) |
ctcmd_word[31:24] <= 8'hB5; |
r_ctdat_len <= 1'b1; // 16-bit data |
end |
5'b0101?: begin // Write NV-Config reg (2 bytes, Requires WEL) |
6'b00101?: begin // Write NV-Config reg (2 bytes, Requires WEL) |
ctcmd_word[31:24] <= 8'hB1; |
r_ctdat_len <= 1'b1; // 16-bit data |
`ifdef CT_SAFE |
1215,10 → 1222,10
ctdat_word <= { i_data[15:0], 16'h00 }; |
`endif |
end |
5'b0110?: begin // Read V-Config register |
6'b00110?: begin // Read V-Config register |
ctcmd_word[31:24] <= 8'h85; |
end |
5'b0111?: begin // Write V-Config register (Requires WEL) |
6'b00111?: begin // Write V-Config register (Requires WEL) |
ctcmd_word[31:24] <= 8'h81; |
r_ctdat_len <= 1'b0; // 8-bit data |
`ifdef CT_SAFE |
1226,12 → 1233,12
`else |
ctdat_word <= { i_data[7:0], 24'h00 }; |
`endif |
o_xip <= i_data[3]; |
o_xip <= ~i_data[3]; |
end |
5'b1000?: begin // Read EV-Config register |
6'b01000?: begin // Read EV-Config register |
ctcmd_word[31:24] <= 8'h65; |
end |
5'b1001?: begin // Write EV-Config register (Requires WEL) |
6'b01001?: begin // Write EV-Config register (Requires WEL) |
ctcmd_word[31:24] <= 8'h61; |
// o_quad <= (~i_data[7]); |
`ifdef CT_SAFE |
1240,24 → 1247,32
ctdat_word <= { i_data[7:0], 24'h00 }; |
`endif |
end |
5'b1010?: begin // Read Lock register |
6'b01010?: begin // Read Lock register |
ctcmd_word[31:0] <= { 8'he8, i_sector_address, 2'b00 }; |
ctcmd_len <= 2'b11; |
ctdat_wr <= 1'b0; // Read, not write |
end |
5'b1011?: begin // Write Lock register (Requires WEL) |
6'b01011?: begin // Write Lock register (Requires WEL) |
ctcmd_word[31:0] <= { 8'he5, i_sector_address, 2'b00 }; |
ctcmd_len <= 2'b11; |
ctdat_wr <= 1'b1; // Write |
end |
5'b1100?: begin // Read Flag Status register |
6'b01100?: begin // Read Flag Status register |
ctcmd_word[31:24] <= 8'h70; |
ctdat_wr <= 1'b0; // Read, not write |
end |
5'b1101?: begin // Write/Clear Flag Status register (No WEL required) |
6'b01101?: begin // Write/Clear Flag Status register (No WEL required) |
ctcmd_word[31:24] <= 8'h50; |
ctdat_skip <= 1'b1; |
end |
6'b11011?: begin // RESET_ENABLE (when written to) |
ctcmd_word[31:24] <= 8'h66; |
ctdat_skip <= 1'b1; |
end |
6'b11101?: begin // RESET_MEMORY (when written to) |
ctcmd_word[31:24] <= 8'h99; |
ctdat_skip <= 1'b1; |
end |
default: begin // Default to reading the status register |
ctcmd_word[31:24] <= 8'h05; |
ctdat_wr <= 1'b0; // Read, not write |
1264,7 → 1279,8
r_ctdat_len <= 1'b0; // 8-bit data |
end |
endcase |
end |
end else if (i_leave_xip) |
o_xip <= 1'b0; |
|
assign o_quad = 1'b1; |
|
/rtl/llqspi.v
37,6 → 37,10
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
`define QSPI_IDLE 3'h0 |
`define QSPI_START 3'h1 |
`define QSPI_BITS 3'h2 |
56,17 → 60,17
o_word, o_valid, o_busy, |
// QSPI interface |
o_sck, o_cs_n, o_mod, o_dat, i_dat); |
input i_clk; |
input wire i_clk; |
// Chip interface |
// Can send info |
// i_dir = 1, i_spd = 0, i_hold = 0, i_wr = 1, |
// i_word = { 1'b0, 32'info to send }, |
// i_len = # of bytes in word-1 |
input i_wr, i_hold; |
input [31:0] i_word; |
input [1:0] i_len; // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits |
input i_spd; // 0 -> normal QPI, 1 -> QSPI |
input i_dir; // 0 -> read, 1 -> write to SPI |
input wire i_wr, i_hold; |
input wire [31:0] i_word; |
input wire [1:0] i_len; // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits |
input wire i_spd; // 0 -> normal QPI, 1 -> QSPI |
input wire i_dir; // 0 -> read, 1 -> write to SPI |
output reg [31:0] o_word; |
output reg o_valid, o_busy; |
// Interface with the QSPI lines |
/rtl/wbqspiflash.v
1,4 → 1,4
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbspiflash.v |
// |
24,12 → 24,12
// (19 bits): Data (R/w, but expect writes to take a while) |
// |
// |
// Creator: Dan Gisselquist |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015,2017, 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 |
42,7 → 42,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. |
// |
50,45 → 50,46
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
`include "flash_config.v" |
`default_nettype none |
// |
`define WBQSPI_RESET 0 |
`define WBQSPI_RESET_QUADMODE 1 |
`define WBQSPI_IDLE 2 |
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode |
`define WBQSPI_WBDECODE 4 |
`define WBQSPI_RD_DUMMY 5 |
`define WBQSPI_QRD_ADDRESS 6 |
`define WBQSPI_QRD_DUMMY 7 |
`define WBQSPI_READ_CMD 8 |
`define WBQSPI_READ_DATA 9 |
`define WBQSPI_WAIT_TIL_RDIDLE 10 |
`define WBQSPI_READ_ID_CMD 11 |
`define WBQSPI_READ_ID 12 |
`define WBQSPI_READ_STATUS 13 |
`define WBQSPI_READ_CONFIG 14 |
`define WBQSPI_WAIT_TIL_IDLE 15 |
`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 16 |
`define WBQSPI_CHECK_WIP_CLEAR 17 |
`define WBQSPI_CHECK_WIP_DONE 18 |
`define WBQSPI_WEN 19 |
`define WBQSPI_PP 20 // Program page |
`define WBQSPI_QPP 21 // Program page, 4 bit mode |
`define WBQSPI_WR_DATA 22 |
`define WBQSPI_WR_BUS_CYCLE 23 |
`define WBQSPI_WRITE_STATUS 24 |
`define WBQSPI_WRITE_CONFIG 25 |
`define WBQSPI_ERASE_WEN 26 |
`define WBQSPI_ERASE_CMD 27 |
`define WBQSPI_ERASE_BLOCK 28 |
`define WBQSPI_CLEAR_STATUS 29 |
`define WBQSPI_IDLE_CHECK_WIP 30 |
`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 |
|
102,11 → 103,11
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat, |
o_interrupt); |
parameter ADDRESS_WIDTH=22; |
input i_clk_100mhz; |
input wire i_clk_100mhz; |
// Wishbone, inputs first |
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we; |
input [(ADDRESS_WIDTH-3):0] i_wb_addr; |
input [31:0] i_wb_data; |
input wire i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we; |
input wire [(ADDRESS_WIDTH-3):0] i_wb_addr; |
input wire [31:0] i_wb_data; |
// then outputs |
output reg o_wb_ack; |
output reg o_wb_stall; |
115,7 → 116,7
output wire o_qspi_sck, o_qspi_cs_n; |
output wire [1:0] o_qspi_mod; |
output wire [3:0] o_qspi_dat; |
input [3:0] i_qspi_dat; |
input wire [3:0] i_qspi_dat; |
// Interrupt line |
output reg o_interrupt; |
// output wire [31:0] o_debug; |
146,12 → 147,29
write_protect = 1'b1; |
end |
|
wire [23:0] w_wb_addr; |
generate |
if (ADDRESS_WIDTH>=24) |
assign w_wb_addr = { i_wb_addr[21:0], 2'b00 }; |
else |
assign w_wb_addr = { {(24-ADDRESS_WIDTH){1'b0}}, i_wb_addr, 2'b00 }; |
endgenerate |
|
// Repeat for spif_addr |
reg [(ADDRESS_WIDTH-3):0] spif_addr; |
wire [23:0] w_spif_addr; |
generate |
if (ADDRESS_WIDTH>=24) |
assign w_spif_addr = { spif_addr[21:0], 2'b00 }; |
else |
assign w_spif_addr = { {(24-ADDRESS_WIDTH){1'b0}}, spif_addr, 2'b00 }; |
endgenerate |
|
reg [7:0] last_status; |
reg quad_mode_enabled; |
reg spif_cmd, spif_override; |
reg [(ADDRESS_WIDTH-3):0] spif_addr; |
reg [31:0] spif_data; |
reg [5:0] state; |
reg [4:0] state; |
reg spif_ctrl, spif_req; |
wire [(ADDRESS_WIDTH-17):0] spif_sector; |
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14]; |
193,7 → 211,9
begin |
// Okay, so here's the problem: we don't know whether or not |
// the Xilinx loader started us up in Quad Read I/O idle mode. |
// So, thus we need to |
// So, thus we need to toggle the clock and CS_n, with fewer |
// clocks than are necessary to transmit a word. |
// |
// Not ready to handle the bus yet, so stall any requests |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
224,7 → 244,7
spi_spd <= 1'b0; |
spi_dir <= 1'b0; // Write (for now, 'cause of cmd) |
// Data register access |
if ((i_wb_data_stb)&&(i_wb_cyc)) |
if (i_wb_data_stb) |
begin |
|
if (i_wb_we) // Request to write a page |
265,15 → 285,11
spi_wr <= 1'b1; // Write cmd to device |
if (quad_mode_enabled) |
begin |
spi_in <= { 8'heb, |
{(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'heb, w_wb_addr }; |
state <= `WBQSPI_QRD_ADDRESS; |
spi_len <= 2'b00; // single byte, cmd only |
end else begin |
spi_in <= { 8'h0b, |
{(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'h0b, w_wb_addr }; |
state <= `WBQSPI_RD_DUMMY; |
spi_len <= 2'b11; // cmd+addr,32bits |
end |
286,7 → 302,7
o_wb_stall <= 1'b1; |
`endif |
end |
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)&&(i_wb_we)) |
end else if ((i_wb_ctrl_stb)&&(i_wb_we)) |
begin |
`ifdef READ_ONLY |
o_wb_ack <= 1'b1; |
352,7 → 368,7
end |
endcase |
`endif |
end else if ((i_wb_cyc)&&(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 |
428,15 → 444,14
spi_hold <= 1'b0; |
spi_spd<= 1'b1; |
spi_dir <= 1'b0; // Write (for now) |
if ((i_wb_cyc)&&(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; |
spi_len <= 2'b10; // Write address, but not mode byte |
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 }; |
spi_in <= { w_wb_addr, 8'ha0 }; |
state <= `WBQSPI_QRD_DUMMY; |
end else if((i_wb_cyc)&&(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 |
448,7 → 463,7
quad_mode_enabled, |
{(29-ADDRESS_WIDTH){1'b0}}, |
erased_sector, 14'h000 }; |
end else if((i_wb_cyc)&&((i_wb_ctrl_stb)||(i_wb_data_stb))) |
end else if(((i_wb_ctrl_stb)||(i_wb_data_stb))) |
begin // Need to release the device from quad mode for all else |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
645,8 → 660,7
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b1; // Non-stop |
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 }; |
spi_in <= { w_spif_addr, 8'ha0 }; |
spi_len <= 2'b10; // Write address, not mode byte |
spi_spd <= 1'b1; |
spi_dir <= 1'b0; // Still writing |
688,7 → 702,7
end else if (state == `WBQSPI_READ_DATA) |
begin |
// Pipelined read support |
spi_wr <=((i_wb_cyc)&&(i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1))); |
spi_wr <=((i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1))); |
spi_in <= 32'h00; |
spi_len <= 2'b11; |
// Don't adjust the speed here, it was set in the setup |
712,8 → 726,7
o_wb_ack <= spif_req; |
o_wb_stall <= (~spi_wr); |
// adjust endian-ness to match the PC |
o_wb_data <= { spi_out[7:0], spi_out[15:8], |
spi_out[23:16], spi_out[31:24] }; |
o_wb_data <= spi_out; |
state <= (spi_wr)?`WBQSPI_READ_DATA |
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE); |
spif_req <= spi_wr; |
900,15 → 913,11
spi_wr <= 1'b1; // Write cmd to device |
if (quad_mode_enabled) |
begin |
spi_in <= { 8'heb, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'heb, w_spif_addr }; |
state <= `WBQSPI_QRD_ADDRESS; |
// spi_len <= 2'b00; // single byte, cmd only |
end else begin |
spi_in <= { 8'h0b, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'h0b, w_spif_addr }; |
state <= `WBQSPI_RD_DUMMY; |
spi_len <= 2'b11; // Send cmd and addr |
end end |
956,9 → 965,7
begin // We come here under a full stop / full port idle mode |
// Issue our command immediately |
spi_wr <= 1'b1; |
spi_in <= { 8'h02, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'h02, w_spif_addr }; |
spi_len <= 2'b11; |
spi_hold <= 1'b1; |
spi_spd <= 1'b0; |
974,9 → 981,7
begin // We come here under a full stop / full port idle mode |
// Issue our command immediately |
spi_wr <= 1'b1; |
spi_in <= { 8'h32, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_in <= { 8'h32, w_spif_addr }; |
spi_len <= 2'b11; |
spi_hold <= 1'b1; |
spi_spd <= 1'b0; |
999,11 → 1004,7
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spi_wr <= 1'b1; // write without waiting |
spi_in <= { |
spif_data[ 7: 0], |
spif_data[15: 8], |
spif_data[23:16], |
spif_data[31:24] }; |
spi_in <= spif_data; |
spi_len <= 2'b11; // Write 4 bytes |
spi_hold <= 1'b1; |
if (~spi_busy) |
rtl
Property changes :
Added: svn:ignore
## -0,0 +1 ##
+obj_dir