OpenCores
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

powered by: WebSVN 2.1.0

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