<<<
:sectnums:
==== Serial Data Interface Controller (SDI)

[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_sdi.vhd | 
| Software driver file(s): | neorv32_sdi.c |
|                          | neorv32_sdi.h |
| Top entity port:         | `sdi_clk_i` | 1-bit serial clock input
|                          | `sdi_dat_o` | 1-bit serial data output
|                          | `sdi_dat_i` | 1-bit serial data input
|                          | `sdi_csn_i` | 1-bit chip-select input (low-active)
| Configuration generics:  | `IO_SDI_EN`   | implement SDI controller when `true`
|                          | `IO_SDI_FIFO` | data FIFO size, has to a power of two, min 1
| CPU interrupts:          | fast IRQ channel 11 | configurable SDI interrupt (see <<_processor_interrupts>>)
|=======================


**Overview**

The serial data interface module provides a **device-class** SPI interface and allows to connect the processor
to an external SPI _host_, which is responsible for triggering (clocking) the actual transmission - the SDI is entirely
passive. An optional receive/transmit FIFO can be configured via the _IO_SDI_FIFO_ generic to support block-based
transmissions without CPU interaction.

.Device-Mode Only
[NOTE]
The NEORV32 SDI module only supports _device mode_. Transmission are initiated by an external host and not by the
the processor itself. If you are looking for a _host-mode_ serial peripheral interface (transactions
initiated by the NEORV32) check out the <<_serial_peripheral_interface_controller_spi>>.

The SDI module provides a single control register `CTRL` to configure the module and to check it's status
and a single data register `DATA` for receiving/transmitting data.


**Theory of Operation**

The SDI module is enabled by setting the `SDI_CTRL_EN` bit in the `CTRL` control register. Clearing this bit
resets the entire module including the RX and TX FIFOs.

The SDI operates on byte-level only. Data written to the `DATA` register will be pushed to the TX FIFO. Received
data can be retrieved by reading the RX FIFO via the `DATA` register. The current state of these FIFOs is available
via the control register's `SDI_CTRL_RX_*` and `SDI_CTRL_TX_*` flags. The RX FIFO can be manually cleared at any time
by setting the `SDI_CTRL_CLR_RX` bit.

.MSB-first Only
[NOTE]
The NEORV32 SDI module only supports MSB-first mode.

.Transmission Abort
[NOTE]
If the external SPI controller aborts an transmission (by setting the chip-select signal high again) _before_
8 data bits have been transferred, no data is written to the RX FIFO.


**SDI Clocking**

The SDI module supports both SPI clock polarity modes ("CPOL") but regarding the clock phase only "CPHA=0" is supported
yet. All SDI operations are clocked by the external `sdi_clk_i` signal. This signal is synchronized to the processor's
clock domain to simplify timing behavior. However, the clock synchronization requires that the external SDI clock
(`sdi_clk_i`) does **not exceed 1/4 of the processor's main clock**.


**SDI Interrupt**

The SDI module provides a set of programmable interrupt conditions based on the level of the RX & TX FIFOs. The different
interrupt sources are enabled by setting the according control register's `SDI_CTRL_IRQ` bits. All enabled interrupt
conditions are logically OR-ed so any enabled interrupt source will trigger the module's interrupt signal.

Once the SDI interrupt has fired it will remain active until the actual cause of the interrupt is resolved; for
example if just the `SDI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep firing until the RX FIFO is empty again.
Furthermore, an active SDI interrupt has to be explicitly cleared again by writing zero to the according
<<_mip>> CSR bit.


**Register Map**

.SDI register map (`struct NEORV32_SDI`)
[cols="<2,<1,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.16+<| `0xfffff700` .16+<| `CTRL` <|`0`     `SDI_CTRL_EN`                           ^| r/w <| SDI module enable
                                  <|`1`     `SDI_CTRL_CLR_RX`                       ^| -/w <| clear RX FIFO when set, bit auto-clears
                                  <|`3:2`   _reserved_                              ^| r/- <| reserved, read as zero
                                  <|`7:4`   `SDI_CTRL_FIFO_MSB : SDI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SDI_FIFO_)
                                  <|`14:8`  _reserved_                              ^| r/- <| reserved, read as zero
                                  <|`15`    `SDI_CTRL_IRQ_RX_AVAIL`                 ^| r/w <| fire interrupt if RX FIFO is not empty
                                  <|`16`    `SDI_CTRL_IRQ_RX_HALF`                  ^| r/w <| fire interrupt if RX FIFO is at least half full
                                  <|`17`    `SDI_CTRL_IRQ_RX_FULL`                  ^| r/w <| fire interrupt if if RX FIFO is full
                                  <|`18`    `SDI_CTRL_IRQ_TX_EMPTY`                 ^| r/w <| fire interrupt if TX FIFO is empty
                                  <|`22:19` _reserved_                              ^| r/- <| reserved, read as zero
                                  <|`23`    `SDI_CTRL_RX_AVAIL`                     ^| r/- <| RX FIFO data available (RX FIFO not empty)
                                  <|`24`    `SDI_CTRL_RX_HALF`                      ^| r/- <| RX FIFO at least half full
                                  <|`25`    `SDI_CTRL_RX_FULL`                      ^| r/- <| RX FIFO full
                                  <|`26`    `SDI_CTRL_TX_EMPTY`                     ^| r/- <| TX FIFO empty
                                  <|`27`    `SDI_CTRL_TX_FULL`                      ^| r/- <| TX FIFO full
                                  <|`31:28` _reserved_                              ^| r/- <| reserved, read as zero
| `0xfffff704` | `DATA` |`7:0` | r/w | receive/transmit data (FIFO)
|=======================
