SPI_HOST HWIP Technical Specification


This document specifies SPI_HOST hardware IP (HWIP) functionality. This module conforms to the Comportable guideline for peripheral functionality. See that document for integration overview within the broader top-level system.


  • Hardware control for remote devices using the Serial Peripheral Interface (SPI)
  • Primarily designed for serial NOR flash devices such as the Winbond W25Q01JV
  • Number of chip select lines controlled by NumCS parameter
  • Support for Standard SPI, Dual SPI or Quad SPI commands
    • Signals SD[0] through SD[3] are intended to connect to lines IO0 through IO3 respectively, on the target device.
    • Signal SD[0] may also be identified as “MOSI” by other SPI Hosts, while SD[1] is commonly referred to as “MISO”
  • RX and TX data held in separate FIFOs
    • 288 bytes for TX data, 256 bytes for RX data
    • FIFOs loaded/unloaded via 32-bit TL-UL registers
    • Support for arbitrary byte-count in each transaction
    • Parametrizable support for Big- or Little-Endian systems in ordering I/O bytes within 32-bit words.
  • SPI clock rate controlled by separate input clock to core
    • SPI SCK line typically toggles at 1/2 the core clock frequency
    • An additional clock rate divider exists to reduce the frequency if needed
  • Support for all SPI polarity and phases (CPOL, CPHA)
    • Additional support for “Full-cycle” SPI transactions, wherein data can be read a full SPI Clock cycle after the active edge (as opposed to one half cycle as is typical for SPI interfaces)
  • Single Transfer Rate (STR) only (i.e. data received on multiple lines, but only on one clock edge)
    • No support for Dual Transfer Rate (DTR)
  • Pass-through mode for coordination with SPI_DEVICE IP
  • Automatic control of chip select lines
  • Condensed interrupt footprint: Two lines for two distinct interrupt classes: “error” and “spi_event”
    • Fine-grain interrupt masking supplied by secondary enable registers


The Serial Peripheral Interface (SPI) is a synchronous serial interface quite commonly used for NOR flash devices as well as a number of other off-chip peripherals such as ADC’s, DAC’s, or temperature sensors. The interface is a de facto standard (not a formal one), and so there is no definitive reference describing the interface, or establishing compliance criteria.

It is therefore important to consult the data sheets for the desired peripheral devices in order to ensure compatibility. For instance, this OpenTitan SPI Host IP is primarily designed for controlling Quad SPI NOR flash devices, such as the W25Q01JV Serial NOR flash from Winbond or this 1 Gb M25QL NOR flash from Micron. Though this IP implementation aims to be general enough to support a variety of devices, the Winbond serial flash device is used as the primary reference for understanding our host requirements.

There are also a number of good references describing legacy host implementations for this protocol, which are useful for understanding some of the general needs for a wider range of target devices. For instance, the legacy SPI Block Guide from Motorola contains a definitive overview of some of the the general requirements for a standard SPI host, notably the definitions of SPI clock phase and polarity (CPOL and CPHA). In order to potentially support a broad range of devices, this SPI Host IP also supports all four of the standard SPI clock phases.

SPI Protocol Basics

Broadly speaking, the SPI host accepts commands from the TL-UL interface and, based on these commands, serially transmits and receives data on the external SPI interface pins. The timing and data-line formatting of the command sequence depend on the external peripheral device and the nature of the specific command issued.

In each standard SPI command a number of instruction-, address- or data-bytes are transmitted on SD[0], and response bytes are received on SD[1]. So in standard-mode commands, SD[0] is always configured as an output, and SD[1] is always an input. In standard SPI commands the SD[0] and SD[1] lines can be used as a full-duplex communication channel. Not all devices exploit this capability, opting instead to have clear input and output phases for each command. This half-duplex signaling behavior is especially common in devices with also support Dual- and Quad-mode commands, which are always half-duplex. The SPI_HOST IP optionally supports both full-duplex and half-duplex commands in standard mode.

Along with the data lines, the SPI protocol also includes a chip select line, commonly called CS#. In this IP we refer to it as CSB. The SPI bus can be connected to many target peripherals, but each device on the bus gets its own chip select line, and so this active-low signal designates a particular device for each command.

The chip-select line also marks the beginning and end of each command. No device will accept any command input until CSB has been asserted for that device, and most devices (if not all) do not accept a second command unless CSB has been deasserted to mark the end of the previous command. Some simple devices, particularly those that support SPI daisy-chaining, do not process command input at all until after the CSB line has been deasserted. In the case of NOR flash devices, read and write commands are indeterminate in length, and the data transfer ends only when the CSB line is deasserted. So, though the exact details of operation may vary from device to device, the edges of the CSB signal serve as an important markers for delineating the boundaries of each transaction.

The SD and CSB lines are accompanied by a serial clock, SCK. The host is responsible for generating the serial clock, and typically each side asserts outgoing data on one edge of the clock (e.g. on the rising edge) and samples data in the next edge (e.g. on the falling edge). When it comes to devices there is no universal convention on clock polarity (CPOL) or clock phase (CPHA). Some devices expect the clock line to be low when the host is idle, thus the clock should come as a sequence of positive pulses (CPOL = 0). On the other hand, other devices expect CPOL = 1, meaning that the clock line is inverted: high when idle with sequences of negative pulses.

Devices also differ in their expectations of clock phase (CPHA) relative to the data. Devices with CPHA = 0, expect that both the host and device will be sampling data on the leading edge, and asserting data on the trailing edge. (Because of the option for either polarity, the terms “leading” and “trailing” are preferred to “rising” or “falling”). When CPHA = 0, the first output bit is asserted with the falling edge of CSB. Meanwhile if CPHA = 1, data is always is asserted on the leading edge of SCK, and data is always sampled on the trailing edge of SCK.

When operating at the fastest-rated clock speeds, some flash devices (i.e. both the Winbond and Micron devices noted above), require setup times which exceed half a clock-cycle. In order to support these fastest data rates, the SPI_HOST IP offers a modified “Full-cycle” (FULLCYC = 1) timing mode where data can be sampled a full cycle after the target device asserts data on the SD bus. This full cycle mode has no effect on any of the signals transmitted, only on the timing of the sampling of the incoming signals.

As mentioned earlier, the SD[0] and SD[1] lines are unidirectional in Standard SPI mode. On the other hand in the faster Dual- or Quad-modes, all data lines are bidirectional, and in Quad mode the number of data lines increases to four. For the purposes of this IP, Dual or Quad-mode commands can be thought of as consisting of up to four command segments in which the host:

  1. Transmits instructions or data at single-line rate,
  2. Transmits instructions address or data on 2 or 4 data lines,
  3. Holds the bus in a high-impedance state for some number of “dummy” clock cycles (neither side transmits), or
  4. Receives information from the target device.

Each of these segments have a different directionality or speed (i.e., SD bus width). As indicated in the example figure below, input data need only be sampled during the last segment. Likewise, software-provided data is only transmitted in the first two segments. The SPI_HOST command interface allows the user to specify any number of command segments to build larger, more complex transactions.

For even faster transfer rates, some flash chips support double transfer rate (DTR) variations to the SPI protocol wherein the device receives and transmits fresh data on both the leading and trailing edge. This IP only supports single transfer rate (STR), not DTR. A preliminary investigation of DTR transfer mode suggests that proper support for setup and hold times in this mode may require a level of sub-cycle timing control which is not currently planned for this IP.

Theory of Operations

SPI_HOST IP Command Interface

A SPI command consists of at least one segment. Each segment has a different speed (number of active SD lines), direction and length. For example a Quad SPI read transaction consists of 4 segments:

  1. A single byte instruction transmitted at standard data rate
  2. A three or four byte address transmitted at quad data rate
  3. A number of dummy cycles (no data transmitted or received)
  4. The desired data, received by SPI_HOST at Quad data rate

During a transaction, software can issue multiple segment descriptions to the SPI_HOST IP to control for changes in speed or direction.

Issuing a command then consists of the following steps:

  1. Configure the IP to be compatible with each attached peripheral. The CONFIGOPTS_0 multi-register holds separate sets of configuration settings, one for each CSB line. In principle, the configuration of these device-specific options only needs to be done/performed once at initialization.

  2. Load the TX FIFO with the instructions and data to be transmitted to the remote device by writing to the DATA memory window.

  3. Specify which device should receive the next command using the CSID register.

  4. Wait for STATUS.READY before continuing.

  5. Issue speed, direction, and length details for the next command segment using the COMMAND register. If a command consists of multiple segments, then set COMMAND.CSAAT (Chip-select active after transaction) to one for all segments except the last one. Setting COMMAND.CSAAT to zero indicates the end of a transaction, prompting the IP to raise CSB at the end of the segment.

  6. Repeat steps 4 and 5 until all segments have been described.

  7. Read any peripheral response data from the RX FIFO by reading from the DATA memory window.

About Command Segments

The structure of a SPI command depends on the device and the command itself.

To support a variety of different I/O sequences the SPI_HOST FSM treats each command as a sequence of segments, each with a defined length, direction and speed.

In case of a standard SPI device the commands are very consistent in structure: the host transmits data on SD[0], and always receives data on SD[1]. For such devices, all commands can in principle be treated as bidirectional, as both the host and device are always transmitting on their respective lines. For bidirectional commands, the SPI_HOST IP will store one byte in the RX FIFO for each byte transmitted from the TX FIFO.

However, even for these standard SPI commands, software may be uninterested in some or all of the device’s response data. For example, for SPI flash devices, standard-mode write commands contain no useful data in the device response, even though the device may be actively asserting signals to SD[1] throughout the transaction. Therefore, for such commands software may choose to specify the entire command as “TX Only”, in which case data placed in the TX FIFO will be transmitted throughout the write command, but signals received from the device will be ignored and will not fill the RX FIFO.

Meanwhile for other flash commands, such as standard-mode read, the device only transmits useful information during some portions of the transaction. In the case of a basic read (with a 3-byte address), the instruction starts with a 1-byte instruction code (0x3) followed by the three address bytes, during which time the flash device outputs may be high impedance (depending on the device). The device then immediately responds with the requested data in the next SCK cycle, and continues to output data bytes until the CSB line is deasserted. Though such a command could also be treated as entirely bidirectional, the device response can be safely ignored during the instruction and address phase, especially if the SD[1] line is high impedance during this time. Likewise it is not necessary for software to specify any data to transmit while the device is responding. Therefore such a command can be thought of as consisting of two separate segments, the first segment being TX Only and the second segment being RX only, as shown in the following figure. Breaking the command up this way potentially simplifies the job of writing software for this type of command.

In addition to the TX, RX or Bidirectional modes, many SPI commands require periods where neither the host or device are transmitting data. For instance, many flash devices define a Fast Read command in which the host must insert a number of “dummy clocks” between the last address byte and the first data byte from the device. These extra cycles are required for operation at higher clock frequencies, to give the address time to propagate through the flash core. A standard-mode Fast Read (with 3 byte addressing) command then requires three SPI_HOST command segments:

  • 4 bytes TX Only: one for the instruction code (i.e., 0xb for Fast Read), and three for the address.
  • 8 dummy clocks
  • N bytes RX Only for read data response

For standard mode-commands, segments simplify the IO process by identifying which bus cycles have useful RX or TX data. In such cases it is not strictly necessary to the manage the impedance of the SD[0] and SD[1] lines. For Dual- and Quad-mode commands, however, impedance control necessary. The impedance of all data lines (SD[3:0]) must switch between TX and RX segments.

Bidirectional data transfers are not applicable for Dual- or Quad-mode segments.

In addition, the speed-mode changes how data is distributed across the four data lines, and many commands require that some segments are transmitted in standard mode (only on SD[0]), while the bulk of the data is transmitted in Dual- or Quad-mode. For this reason the speed-mode is also adjustable on a segment-by-segment basis.

Specifying Command Segments

The SPI host supports all four possible modes for command segments, and they are controlled writing one of the following values to the 2-bit COMMAND.DIRECTION register:

  • 2’b00: Dummy cycles only (neither side transmits)
  • 2’b01: RX Only
  • 2’b10: TX Only
  • 2’b11: Bidirectional

CSID Register

The CSID register is used to identify the target device for the next command segment. Whenever a command segment descriptor is written to COMMAND, CSID is passed into the FSM along with the command segment descriptor and the corresponding configurations options (taken from the CSID’th element of the CONFIGOPTS multi-register).

This register still exists when instantiated with only one CSB line (i.e. when NumCS=1). However in this case the CSID value is ignored.

Changes in CSID also affect the CSB lines, because a change in CSID can also implicitly end a command, overriding COMMAND.CSAAT. If a change is detected in CSID, but the previous segment was submitted with the CSAAT bit asserted, the FSM terminates the previous command before moving on to the next segment. The previous CSB line is held low for at least CSNTRAIL cycles (as defined by the previous value of CONFIGOPTS_0.CSNTRAIL) and then brought high. All CSB lines are held high for CSNIDLE cycles (using the new value of CONFIGOPTS_0.CSNIDLE). The new CSB line is asserted low, and SCK begins toggling after the usual CSNLEAD cycle delay.

Configuration Options

The CONFIGOPTS_0 multi-register has one entry per CSB line and holds clock configuration and timing settings which are specific to each peripheral. Once the CONFIGOPTS_0 multi-register has been programmed for each SPI peripheral device, the values can be left unchanged.

The following sections give details on how the SPI_HOST can be used to control a specific peripheral. For simplicity, this section describes how to interact one device, attached to CSB[0], and as such references are made to the multi-registers CONFIGOPTS_0 and COMMAND. To configure timing and send commands to devices on other CSB lines, instead use the CONFIGOPTS multi-register corresponding to desired CSB line.

The most common differences between target devices are the requirements for a specific SPI clock phase or polarity, CPOL and CPHA, which were described in the previous section SPI Protocol Basics. These clock parameters can be set via the CONFIGOPTS_0.CPOL_0 or CONFIGOPTS_0.CPHA_0 register fields. Likewise, as also described in the previous section, if device setup times require a full clock cycle before sampling the output, Full-Cycle Mode can be enabled by asserting the CONFIGOPTS_0.FULLCYC_0 bit.

Clock rate selection

The SPI clock rate for each peripheral is set by two factors:

  • The SPI_HOST core clock (which may be generated independently from the TL-UL interface clock)
  • An additional 16-bit clock divider

The SPI protocol usually requires activity (either sampling or asserting data) on either edge of the SCK clock. For this reason the maximum SCK frequency is at most one half the SPI_HOST core frequency. In order to support a broader range of SPI clock frequencies, the SPI_HOST core operates on a separate clock domain, which may be independent from the TL-UL bus clock. This arrangement allows gives more flexibility in setting the serial clock frequency by means of an external PLL, and in principle the SCK frequency could even be configured to exceed the bus clock. For example, if the TL-UL bus is operating at 100MHz, a 200MHz SPI core clock can be fed to the SPI_HOST IP, in order to achieve data rates of 100 MTransfers/s (near the maximum clock rate of the Winbond flash device).

Since some peripheral devices attached to the same SPI_HOST may require different clock frequencies, there is also the option to divide the core clock by an additional factor when dealing with slower peripherals.


Alternatively, this clock-divide feature can also be used to entirely bypass the need for an independent core clock. Instead the core can be driven by the TL-UL bus clock, and the SCK period can be adjusted using the CONFIGOPTS_0.CLKDIV_0 setting.

Chip-select timing control

Typically the CSB line is automatically deasserted after the last edge of SCK. However, by asserting COMMAND.CSAAT when issuing a particular command, one can instruct the core to hold CSB low indefinitely after the last clock edge. This is useful for merging two adjacent commands together, to create very long commands such as continuous read operations. The CSB line can then be deasserted by either issuing another command without the COMMAND.CSAAT field, issuing a command to a different device (after changing the a CSID register), or simply resetting the core FSM via the CONTROL.RST register.

Most devices require at least one-half SCK clock-cycle between either edge of CSB and the nearest SCK edge. However, some devices may require more timing margin and so the SPI_HOST core offers some configuration registers for controlling the timing of the CSB edges when operating under automatic control. The relevant parameters are as follows:

  • TIDLE: The minimum time between each rising edge of CSB and the following falling edge. This time delay is a half SCK cycle by default but can be extended to as long as eight SCK cycles by setting the CONFIGOPTS_0.CSNIDLE_0 register.
  • TLEAD: The minimum time between each falling edge of CSB and the first leading edge of SCK. This time delay is a half SCK cycle by default but can be extended to as long as eight SCK cycles by setting the CONFIGOPTS_0.CSNLEAD_0 register.
  • TTRAIL: The minimum time between the last trailing edge of SCK and the following rising edge of CSB. This time delay is a half SCK cycle by default but can be extended to as long as eight SCK cycles by setting the CONFIGOPTS_0.CSNTRAIL_0 register.

These settings are all minimum bounds, and delays in the FSM implementation may create more margin in each of these timing constraints.

Special Command Fields

The COMMAND register must be written every time a command is issued. Whenever a command segment is written to COMMAND, the contents of the CONFIGOPTS_0 and COMMAND registers are passed through the Config/Command CDC to the SPI_HOST core FSM, along with a Chip Select mask signal, indicating which device should receive the command (for example CSB[0]) Once the command is issued, the core will immediately deassert STATUS.READY, and once the command has started STATUS.ACTIVE will go high. The STATUS.ACTIVE line takes a few cycles to assert, due to CDC delays. The command is complete when STATUS.ACTIVE goes low. A spi_event interrupt can also be triggered to go off on completion by setting EVENT_ENABLE.IDLE.

Chip Select Masks

Each instance of the SPI_HOST IP supports a parametrizable number of chip select lines (CSB[NumCS-1:0]). Each CSB line can be routed either to a single peripheral or to a daisy-chain of peripherals. Whenever a segment description is written to the COMMAND register, the CSID is sent along with COMMAND and the CONFIGOPTS multi-register corresponding to CSID to indicate which device is meant to receive the command. The SPI_HOST core typically then manages the details of asserting and deasserting the proper CSB line, subject to the timing parameters expressed in CONFIGOPTS_0.CSNLEAD_0, CONFIGOPTS_0.CSNTRAIL_0, and CONFIGOPTS_0.CSNIDLE_0.

If Pass-through mode is enabled then the CSB lines are controlled by neither the SPI_HOST hardware nor the firmware register. In Pass-though mode, control of the CSB lines passes directly to the inter-module port, passthrough_i.csb.

Back-to-back Segments

The command interface can allows for any number of segments in a given command.

There is no command queue for submitting segments to the SPI_HOST IP. However a second segment can be placed into the Config/Command CDC whenever STATUS.READY is high, even if the previous segment is still running. The internal state within the Config/Command CDC provides the option of scheduling a second command segement to execute immediately after completion of the current segment.

On the other hand, writing a segment description to COMMAND when STATUS.READY is low will trigger an error condition, which must be acknowledged by software.

Data Formatting

Input and Output Byte Ordering

The SPI transactions must be issued with correct bit ordering to properly communicate with a remote device. Based on the requirements for our chosen flash devices, this IP follows these conventions:

  • The relative significance of lines on the SD bus: SD[0] is always the least significant, followed by SD[1] though SD[3] with increasing significance.
  • The relative significance of a sequence of bits on the same SD bus: more significant bits are always transmitted before (or at the same time as) less significant bits.
    • For instance, when transferring a single byte in Quad mode, all four bits of the upper nibble (bits 7 through 3) are transferred in the first clock cycle and the entire lower nibble (bits 3 through 0) is transferred in the second cycle.

The programming model for the IP should meanwhile make it easy to quickly program the peripheral device, with a minimum amount of byte shuffling. It should be intuitive to program the specific flash devices we are targeting, while following the conventions above:

  • When reading the data in and out of the DATA memory window, the IP should fully utilize the TL-UL bus, using 32-bit I/O instructions.
  • The SPI_HOST should make it easy to arrange transaction data in processor memory, meaning that bytes should be sequentially transmitted in order of ascending memory address.
    • When using 32-bit I/O instructions, this requires some knowledge of the processor byte-order.

Based on these requirements, data placed in or read from DATA are handled as follows:

  • 32-bit words placed in DATA are transmitted in first-in-first-out order. Likewise, words received from the SPI data lines are made available for reading from in DATA in first-in-first-out order.
  • Within a 32-bit word, the ByteOrder parameter controls the order in which bytes are transmitted, and also the manner in which received bytes are eventually arranged in the 32-bit RXDATA register. By default (ByteOrder = 1, for Little-Endian processors), the LSB of DATA (i.e bits 7 though 0) is transmitted first, and the other bytes follow in order of increasing significance. Similarly, the first byte received is packed into the LSB of DATA, and the subsequent bytes read from DATA are filled in order of increasing significance.

On the other hand, if ByteOrder is set to 0 (for Big-Endian processors), the MSB is transmitted first from DATA, and received data is loaded first into the MSB of DATA.

  • The default choice of Little-Endian reflects native byte-order of the Ibex processor.
  • Finally within a given byte, the most significant bits are transmitted and received first. For Dual and Quad transactions the least significant bit in any instantaneous pair or nibble is transmitted or received on SD[0], and the remaining SD bits (1 though 3) are populated in order of increasing significance.

The following figure shows how data appears on the serial data bus when it is written to or read from DATA.

As shown in the following figure, a similar time-ordering scheme applies for Dual- and Quad-mode transfers. However many bits of similar significance are packed into multiple parallel SD data lines, with the least significant going to SD[0].

Command Length and Alignment in DATA

Even though the DATA memory window typically accepts 32-bit words, command segments do not need to use all the bytes from every word.

For TX (or Bidirectional) segments, unused bytes from the latest TX FIFO word are simply ignored at the end of a segment. For RX (or Bidirectional) segments, if the last few bytes received do not fill an entire DATA word, the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed. If ByteOrder=1 (the default, Little-Endian case), this padding will fill the unused most-significant bytes of the final RX DATA word, otherwise the padding will fill the unused least-significant bytes.

The following waveform illustrates an example SPI transaction, where neither the data transmitted nor the data received in each segment fit into an even number of 32-bit words. In this example, the values I[31:0], A[31:0] and B[31:0], have been previously written into DATA via firmware, and afterwards one word, X[31:0], is available for reading from DATA. All data in the waveform is transferred using 32-bit instructions.

When packing data into the TX FIFO, there are also no restrictions on the alignment of the data written to the DATA memory window, as it supports byte-enable signals. This means that when copying bytes into DATA from unaligned firmware memory addresses, it is possible to use byte or half-word instructions. Full-word instructions should however be used whenever possible, because each write consumes a full word of data in the TX FIFO regardless of the instruction size. Smaller writes will thus make inefficient use of the TX FIFO.

The RX FIFO has no special provisions for packing received data in any unaligned fashion. Depending on the ByteOrder parameter, the first byte received is always packed into either the most- or least-significant byte read from the DATA memory window.

Pass-through Mode

The SPI_HOST also supports a special “Pass-through” mode, which allows for the direct control of the serial interface by another block (namely SPI_DEVICE). This feature is entirely controlled by intermodule signals passthrough_i and passthrough_o, which control a set of multiplexers. If passthrough_i.passthrough_en is asserted the SPI_HOST peripheral bus signals reflect the corresponding signals in the passthrough_i structure. Otherwise, the peripheral signals are controlled by the SPI_HOST FSM and the internal shift register.

Interrupt aggregation

In order to reduce the total number of interrupts in the system, the SPI_HOST has only two interrupt lines: error and spi_event. Within these two interrupt classes, there are a number of conditions which can trigger them.

Each interrupt class has a secondary status and mask register, to control which sub-classes of SPI events will cause an interrupt.

SPI Events and Event Interrupts

The SPI_HOST supports interrupts for the following SPI events:

  • IDLE: The SPI_HOST is idle.
  • READY: The SPI_HOST is ready to accept a new command.
  • RXFULL: The SPI_HOST has run out of room in the RXFIFO.
  • RXWM: The number of 32-bit words in the RXFIFO currently exceeds the value set in CONTROL.RX_WATERMARK.
  • TXEMPTY: The SPI_HOST has transmitted all the data in the TX FIFO.
  • TXWM: The number of 32-bit words in the TX FIFO currently is currently less than the value set in CONTROL.TX_WATERMARK

Most SPI events signal a particular condition that persists until it is fixed, and these conditions can be detected by polling the corresponding field in the STATUS register.

In addition to these events, there are also two additional diagnostic fields in the STATUS register:

  • RXSTALL: The RX FIFO is full, and the SPI_HOST is stalled and waiting for firmware to remove some data.
  • TXSTALL: The TX FIFO is not only empty, but the SPI_HOST is stalled and waiting for firmware to add more data.

These bits can provide diagnostic data for tuning the throughput of the device, but do not themselves generate event interrupts.

By default none of these SPI events trigger an interrupt. They need to be enabled by writing to the corresponding field in EVENT_ENABLE.

The SPI event interrupt is signaled only when the IP enters the corresponding state. For example if an interrupt is requested when the TX FIFO is empty, the IP will only generate one interrupt when the last data word is transmitted from the TX FIFO. In this case, no new interrupts will be created until more data has been added to the FIFO, and all of it has been transmitted.

Error Interrupt Conditions

An error interrupt is usually caused by a violation of the SPI_HOST programming model:

By default all of these programming violations will cause an error interrupt when they occur. They will also halt the IP until the corresponding bit is cleared in the ERROR_STATUS register.

Each of these errors can be optionally ignored by clearing the corresponding bit in ERROR_ENABLE. Clearing an error-enable bit will suppress interrupts for that class of violation and will allow the IP to proceed even if one of these errors has occurred. The ERROR_STATUS register will continue to report all of these violations even if one of the corresponding bits in ERROR_ENABLE is zero.

The ERROR_STATUS bit should be cleared before clearing the error interrupt in the INTR_STATE register. Failure do to so may result in a repeated interrupt.

Status Indicators

The STATUS register contains a number of fields that should be queried for successful operation or troubleshooting.

The register STATUS.ACTIVE indicates whether a command segment is currently being processed by the FSM. Even if STATUS.ACTIVE is high it is often still possible to insert another command segment into the CDC, allowing for the possibility of back-to-back processing of multiple segments. So the register STATUS.READY indicates that there is room to submit another segment into COMMAND.

The STATUS.BYTEORDER field indicates the fixed value of the ByteOrder parameter, which is presented to software to confirm the byte ordering used in the DATA register.

The 8-bit fields STATUS.RXQD and STATUS.TXQD respectively indicate the number of words currently stored in the RX and TX FIFOs.

The remaining fields in the STATUS register are all flags related to the management of the TX and RX FIFOs, which are described in the section on SPI Events.

Other Registers


The SPI_HOST state machine is disabled on reset. Before any commands are processed, the block must be enabled by writing one to the CONTROL.SPIEN register. Writing a zero to this register temporarily suspends any previously submitted transactions. If the block is re-enabled by writing a one to CONTROL.SPIEN, any previously executing commands will continue from wherever they left off.

An unacknowledged error interrupt will also suspend the core state machine.

Component reset

In addition to the global hardware reset, there is a software reset option which completely resets the SPI host. To use this reset, assert CONTROL.SW_RST, and then wait for the device to reset (STATUS.ACTIVE, STATUS.TXQD and STATUS.RXQD to all go to zero), before releasing CONTROL.SW_RST.

Block Diagram

Hardware Interfaces

Referring to the Comportable guideline for peripheral device functionality, the module spi_host has the following hardware interfaces defined.

Primary Clock: clk_i

Other Clocks: clk_core_i

Bus Device Interfaces (TL-UL): tl

Bus Host Interfaces (TL-UL): none

Peripheral Pins for Chip IO:

Pin namedirectionDescription

SPI Clock


Chip Select# (One hot, active low). The size of this port should match NumCS.


SPI data bus


Interrupt NameDescription

Error-related interrupts, see ERROR_ENABLE register for more information.


Event-related interrupts, see EVENT_ENABLE register for more information.

Security Alerts:

Alert NameDescription

This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected.

Design Details

Component Overview.

TODO High level introductory description of

  • Control FSM
  • SDQ Shift register
  • Byte Select
  • Byte Merge
  • TX FIFO and RXFIFO interfaces

Programmer’s Guide


Register Table

spi_host.INTR_STATE @ 0x0

Interrupt State Register

Reset default = 0x0, mask 0x3
  spi_event error

Error-related interrupts, see ERROR_ENABLE register for more information.


Event-related interrupts, see EVENT_ENABLE register for more information.

spi_host.INTR_ENABLE @ 0x4

Interrupt Enable Register

Reset default = 0x0, mask 0x3
  spi_event error

Enable interrupt when INTR_STATE.error is set.


Enable interrupt when INTR_STATE.spi_event is set.

spi_host.INTR_TEST @ 0x8

Interrupt Test Register

Reset default = 0x0, mask 0x3
  spi_event error

Write 1 to force INTR_STATE.error to 1.


Write 1 to force INTR_STATE.spi_event to 1.

spi_host.ALERT_TEST @ 0xc

Alert Test Register

Reset default = 0x0, mask 0x1

Write 1 to trigger one alert event of this kind.

spi_host.CONTROL @ 0x10

Control register

Reset default = 0x7f, mask 0xc000ffff

If EVENT_ENABLE.RXWM is set, the IP will send an interrupt when the depth of the RX FIFO reaches RX_WATERMARK words (32b each).


If EVENT_ENABLE.TXWM is set, the IP will send an interrupt when the depth of the RX FIFO drops below TX_WATERMARK words (32b each).


Clears the entire IP to the reset state when set to 1, including the FIFOs, the CDC's, the core state machine and the shift register. In the current implementation, the CDC FIFOs are drained not reset. Therefore software must confirm that both FIFO's empty before releasing clearing this bit.


Enables the SPI host. On reset, this field is 0, meaning that no transactions can proceed.

spi_host.STATUS @ 0x14

Status register

Reset default = 0x0, mask 0xffd0ffff

Transmit queue depth. Indicates how many unsent 32-bit words are currently in the TX FIFO. When active, this result may be an overestimate due to synchronization delays,


Receive queue depth. Indicates how many unread 32-bit words are currently in the RX FIFO. When active, this result may an underestimate due to synchronization delays.


If high, the number of 32-bits in the RX FIFO now exceeds the CONTROL.RX_WATERMARK entries (32b each).


The value of the ByteOrder parameter, provided so that firmware can confirm proper IP configuration.


If high, signifies that an ongoing transaction has stalled due to lack of available space in the RX FIFO


When high, indicates that the receive fifo is empty. Any reads from RX FIFO will cause an error interrupt.


When high, indicates that the receive fifo is full. Any ongoing transactions will stall until firmware reads some data from DATA.


If high, the amount of data in the TX FIFO has fallen below the level of CONTROL.TX_WATERMARK words (32b each).


If high, signifies that an ongoing transaction has stalled due to lack of data in the TX FIFO


When high, indicates that the transmit data fifo is empty.


When high, indicates that the transmit data fifo is full. Any further writes to DATA will create an error interrupt.


When high, indicates the SPI host is processing a previously issued command.


When high, indicates the SPI host is ready to receive commands. Writing to COMMAND when READY is low is an error, and will trigger an interrupt.

spi_host.CONFIGOPTS @ 0x18

Configuration options register.

Reset default = 0x0, mask 0xefffffff

Contains options for controlling each peripheral. One register per cs_n line


Core clock divider. Slows down subsequent SPI transactions by a factor of (CLKDIV+1) relative to the core clock frequency. The period of sck, T(sck) then becomes 2*(CLK_DIV+1)*T(core)


Minimum idle time between commands. Indicates the minimum number of sck half-cycles to hold cs_n high between commands. Setting this register to zero creates a minimally-wide CS_N-high pulse of one-half sck cycle.


CS_N Trailing Time. Indicates the number of half sck cycles, CSNTRAIL+1, to leave between last edge of sck and the rising edge of cs_n. Setting this register to zero corresponds to the minimum delay of one-half sck cycle.


CS_N Leading Time. Indicates the number of half sck cycles, CSNLEAD+1, to leave between the falling edge of cs_n and the first edge of sck. Setting this register to zero corresponds to the minimum delay of one-half sck cycle


Full cycle. Modifies the CPHA sampling behaviour to allow for longer device logic setup times. Rather than sampling the SD bus a half cycle after shifting out data, the data is sampled a full cycle after shifting data out. This means that if CPHA = 0, data is shifted out on the trailing edge, and sampled a full cycle later. If CPHA = 1, data is shifted and sampled with the trailing edge, also separated by a full cycle.


The phase of the sck clock signal relative to the data. When CPHA = 0, the data changes on the trailing edge of sck and is typically sampled on the leading edge. Conversely if CPHA = 1 high, data lines change on the leading edge of sck and are typically sampled on the trailing edge. CPHA should be chosen to match the phase of the selected device. The sampling behavior is modified by the !!CONFIGOPTS_0.FULLCYC bit.


The polarity of the sck clock signal. When CPOL is 0, sck is low when idle, and emits high pulses. When CPOL is low, sck is high when idle, and emits a series of low pulses.

spi_host.CSID @ 0x1c

Chip-Select ID

Reset default = 0x0, mask 0xffffffff

Controls which device to target with the next command. This register is passed to the core whenever COMMAND is written. The core then asserts cio_csb_o[CSID] during the execution of the command.


Chip Select ID

spi_host.COMMAND @ 0x20

Command Register

Reset default = 0x0, mask 0x3fff

Parameters specific to each command segment. Unlike the CONFIGOPTS multi-register, there is only one command register for controlling all attached SPI devices


Segment Length.

For read or write segments, this field controls the number of 1-byte bursts to transmit and or receive in this command segment. The number of cyles required to send or received a byte will depend on COMMAND.SPEED. For dummy segments, (COMMAND.DIRECTION == 0), this register controls the number of dummy cycles to issue.


Chip select active after transaction. If CSAAT = 0, the chip select line is raised immediately at the end of the command segment. If COMMAND.CSAAT = 1, the chip select line is left low at the end of the current transaction segment. This allows the creation longer, more complete SPI transactions, consisting of several separate segments for issuing instructions, pausing for dummy cycles, and transmitting or receiving data from the device.


The speed for this command segment: "0" = Standard SPI. "1" = Dual SPI. "2"=Quad SPI, "3": RESERVED.


The direction for the following command: "0" = Dummy cycles (no TX/RX). "1" = Rx only, "2" = Tx only, "3" = Bidirectional Tx/Rx (Standard SPI mode only).

spi_host.DATA @ + 0x24
1 item wo window
Byte writes are supported

SPI Transmit and Receive Data.

Write data to this window to place it in the TXFIFO. Reads from this register pull data from the RXFIFO. Byte-enables are supported for writes.

The serial order of bit transmission is chosen to match SPI flash devices. Individual bytes are always transmitted with the most significant bit first. Multi-byte writes are also supported, and if ByteOrder = 0, the bits of DATA are transmitted strictly in order of decreasing signficance (i.e. most signicant bit first). For some processor architectures, this could lead to shuffling of flash data as compared to how it is written in memory. In which case, choosing ByteOrder = 1 can reverse the byte-order of multi-byte data writes. (Though within each byte the most significant bit is always sent first.)

spi_host.ERROR_ENABLE @ 0x28

Controls which classes of errors raise an interrupt.

Reset default = 0x1f, mask 0x1f

Command Error: If this bit is set, the block sends an error interrupt whenever a command is issued while busy (i.e. a 1 is when STATUS.READY is not asserted.)


Overflow Errors: If this bit is set, the block sends an error interrupt whenever the TX FIFO overflows.


Underflow Errors: If this bit is set, the block sends an error interrupt whenever there is a read from DATA but the RX FIFO is empty.


Invalid Command Errors: If this bit is set, the block sends an error interrupt whenever a command is sent with invalid values for COMMAND.SPEED or COMMAND.DIRECTION.


Invalid CSID: If this bit is set, the block sends an error interrupt whenever a command is submitted, but CSID exceeds NumCS.

spi_host.ERROR_STATUS @ 0x2c

Indicates that any errors that have occurred. When an error occurs, the corresponding bit must be cleared here before issuing any further commands.

Reset default = 0x0, mask 0x1f

Indicates a write to COMMAND when STATUS.READY = 0.


Indicates that firmware has overflowed the TX FIFO


Indicates that firmware has attempted to read from DATA when the RX FIFO is empty.


Indicates an invalid command segment, meaning either an invalid value of COMMAND.SPEED or a request for bidirectional data transfer at dual or quad speed


Indicates a command was attempted with an invalid value for CSID.

spi_host.EVENT_ENABLE @ 0x30

Controls which classes of SPI events raise an interrupt.

Reset default = 0x0, mask 0x3f

Assert to send a spi_event interrupt whenever STATUS.RXFULL goes high


Assert to send a spi_event interrupt whenever STATUS.TXEMPTY goes high


Assert to send a spi_event interrupt whenever the number of 32-bit words in the RX FIFO is greater than CONTROL.RX_WATERMARK. To prevent the reassertion of this interrupt, read more data from the RX FIFO, or increase CONTROL.RX_WATERMARK.


Assert to send a spi_event interrupt whenever the number of 32-bit words in the TX FIFO is less than CONTROL.TX_WATERMARK. To prevent the reassertion of this interrupt add more data to the TX FIFO, or reduce CONTROL.TX_WATERMARK.


Assert to send a spi_event interrupt whenever STATUS.READY goes high


Assert to send a spi_event interrupt whenever STATUS.ACTIVE goes low