<<<
:sectnums:
==== Stream Link Interface (SLINK)

[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_slink.vhd |
| Software driver file(s): | neorv32_slink.c |
|                          | neorv32_slink.h |
| Top entity port:         | `slink_tx_dat_o` | TX link data (8x32-bit)
|                          | `slink_tx_val_o` | TX link data valid (8x1-bit)
|                          | `slink_tx_rdy_i` | TX link allowed to send (8x1-bit)
|                          | `slink_tx_lst_o` | TX link end of packet (8x1-bit)
|                          | `slink_rx_dat_i` | RX link data (8x32-bit)
|                          | `slink_rx_val_i` | RX link data valid (8x1-bit)
|                          | `slink_rx_rdy_o` | RX link ready to receive (8x1-bit)
|                          | `slink_rx_lst_i` | RX link end of packet (8x1-bit)
| Configuration generics:  | _SLINK_NUM_TX_  | Number of TX links to implement (0..8)
|                          | _SLINK_NUM_RX_  | Number of RX links to implement (0..8)
|                          | _SLINK_TX_FIFO_ | FIFO depth (1..32k) of TX links, has to be a power of two
|                          | _SLINK_RX_FIFO_ | FIFO depth (1..32k) of RX links, has to be a power of two
| CPU interrupts:          | fast IRQ channel 10 | SLINK RX IRQ (see <<_processor_interrupts>>)
|                          | fast IRQ channel 11 | SLINK TX IRQ (see <<_processor_interrupts>>)
|=======================


**Overview**

The SLINK component provides up to 8 independent RX (receiving) and TX (sending) links for moving
stream data. The interface provides higher bandwidth and less latency than the external memory bus
interface, which makes it ideally suited to couple custom stream processing units.

Each link provides an individual internal FIFO for data buffering. The FIFO depth is globally defined
for all TX links via the _SLINK_TX_FIFO_ generic and for all RX links via the _SLINK_RX_FIFO_ generic.
The FIFO depth has to be at least 1, which will implement a simple input/output register. The maximum
value is limited to 32768 entries. Note that the FIFO depth has to be a power of two.

The actual number of implemented RX/TX links is configured by the _SLINK_NUM_RX_ and _SLINK_NUM_TX_
generics, respectively. The SLINK module will be synthesized only if at least one of these generics is greater than
zero. All unimplemented links are internally terminated and their according output signals are set to zero.

[NOTE]
The NEORV32 stream link interfaces are compatible to the _AXI Stream_ specs.

.Example Program
[TIP]
An example program for the SLINK module is available in `sw/example/demo_slink`.


**Theory of Operation**

The SLINK provides eight data registers (`DATA[i]`) to access the links (read accesses will access the RX link FIFOs,
write accesses will access the TX link FIFOs), one control register (`CTRL`), one interrupt configuration register (`IRQ`)
and two status registers - one for the RX links (`RX_STATUS`) and one for the TX links (`TX_STATUS`).

The SLINK is globally activated by setting the control register's enable bit _SLINK_CTRL_EN_. Clearing this
bit will reset all internal logic and will also clear all FIFOs. The actual data links are accessed by
reading or writing the according link data registers `DATA[0]` to `DATA[7]`. For example, writing to `DATA[0]`
will put the according data into the FIFO of TX link 0. Accordingly, reading from `DATA[0]` will return one data
word from the FIFO of RX link 0.

The current link status of each RX and TX channel is accessible via the `*X_STATUS` registers. The FIFO's status
signals that represent the fill level (empty, at least half full, full) are exposed as read-only flags via those two
registers.

[NOTE]
Writing to a TX link's FIFO that is _full_ will have no effect. Reading data from a RX link's FIFO that is
_empty_ will have no effect and will return the last valid data word.

The TX link's "end of packet" signal `slink_tx_lst_o` is controlled by the `TX_STATUS` register's _SLINK_TX_STATUS_LAST_
bits. Note that these bits are also buffered by the internal TX FIFOs, so setting one of these bits before writing data to
`DATA` will set the `slink_tx_lst_o` signal when the written data word is actually send from the FIFO. Vice versa, the
_SLINK_RX_STATUS_LAST_ bits in `RX_STATUS` represent the level of the according `slink_rx_lst_i` input when a new data word
was samples. These bits are also buffered in the internal RX FIFOs.


**Data Transmission**

To send (TX) data the program should ensure there is at least one left in the according link's FIFO by checking
_SLINK_CTRL_TX_FREE_. To mark the current data word to-be-send as "end of packet" the according _SLINK_TX_STATUS_LAST_
bit has to be set _before_ writing `DATA`.

Received data (RX) is available when the according link's _SLINK_RX_STATUS_EMPTY_ bit is cleared. To check if the received
data is marked as "end of packet" the according _SLINK_RX_STATUS_LAST_ bit has to be examined _before_ reading `DATA`.


**Interface & Protocol**

The SLINK interface consists of four signals `dat`, `val`, `rdy` and `lst` for each RX and TX link.
Each signal is constructed as an "array" with eight entries - one for each link. Note that an entry in `slink_*x_dat` is 32-bit
wide while entries in `slink_*x_val`, `slink_*x_rdy` and `slink_*x_lst` are are just 1-bit wide.

* `dat` contains the actual data word
* `val` marks the current transmission cycle as valid
* `rdy` indicates that the receiving part is ready to receive
* `lst` marks the current data word as "end of packet"

.Exemplary Stream Link Transfer (transferring 5 elements, element "E" is marked as "end of packet")
image::stream_link_interface.png[width=560,align=center]


**SLINK Interrupts**

The stream interface provides two independent CPU interrupt channels - one for RX conditions and one
for TX conditions. These IRQs can be used to signal specific FIFO conditions (e.g. "data available") to the
CPU. The specific interrupt conditions are programmed per-link via the `IRQ` register.
A 2-bit-coded value is used to enable the according link's interrupt and to specify the actual condition.

[NOTE]
Note that all enabled interrupt configurations are logically OR-ed for the CPU RX and TX interrupts, respectively.
Hence, if **any** link fulfills the according interrupt configuration the according RX/TX interrupt request is
sent to the CPU.

For the TX links (in `IRQ` _SLINK_IRQ_TX_) the following interrupt conditions are supported:

* `0-`: off, no interrupt from link
* `10`: interrupt fires if FIFO _becomes_ not empty
* `11`: interrupt fires if FIFO _becomes_ at least half full

For the RX links (in `IRQ` _SLINK_IRQ_RX_) the following interrupt conditions are supported:

* `0-`: off, no interrupt from link
* `10`: interrupt fires if FIFO _becomes_ empty
* `11`: interrupt fires if FIFO _becomes_ less than half full

Once the SLINK's RX or TX CPU interrupt has become pending, it has to be explicitly cleared again by writing
zero to the according <<_mip>> CSR bit(s).


**Register Map**

.SLINK register map (`struct NEORV32_SLINK`)
[cols="^4,<5,^2,^2,<14"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s) | R/W | Function
.6+<| `0xfffffec0` .6+<| `NEORV32_SLINK.CTRL` <| `0`     _SLINK_CTRL_EN_                                     ^| r/w  | SLINK global enable/reset
                                              <| `7:1`   _reserved_                                          ^| r/- <| _reserved_, returns zero
                                              <| `19:16` _SLINK_CTRL_RX_NUM_MSB_  : _SLINK_CTRL_RX_NUM_LSB_  ^| r/- <| Number of RX links (_SLINK_NUM_RX_)
                                              <| `23:20` _SLINK_CTRL_TX_NUM_MSB_  : _SLINK_CTRL_TX_NUM_LSB_  ^| r/- <| Number of TX links (_SLINK_NUM_TX_)
                                              <| `27:24` _SLINK_CTRL_RX_FIFO_MSB_ : _SLINK_CTRL_RX_FIFO_LSB_ ^| r/- <| RX FIFO depth, log2(_SLINK_RX_FIFO_)
                                              <| `31:28` _SLINK_CTRL_TX_FIFO_MSB_ : _SLINK_CTRL_TX_FIFO_MSB_ ^| r/- <| TX FIFO depth, log2(_SLINK_TX_FIFO_)
.2+<| `0xfffffec4` .2+<| `NEORV32_SLINK.IRQ` <|`15:0`  _SLINK_IRQ_RX_MSB_ : _SLINK_IRQ_RX_LSB_ ^| r/w <| RX link _i_ interrupt configuration (2 bits per link)
                                             <|`31:16` _SLINK_IRQ_TX_MSB_ : _SLINK_IRQ_TX_LSB_ ^| r/w <| TX link _i_ interrupt configuration (2 bits per link)
.4+<| `0xfffffec8` .4+<| `NEORV32_SLINK.RX_STATUS` <|`7:0`   _SLINK_RX_STATUS_EMPTY_MSB_ : _SLINK_RX_STATUS_EMPTY_LSB_ ^| r/- <| RX link _i_ FIFO empty
                                                   <|`15:8`  _SLINK_RX_STATUS_HALF_MSB_  : _SLINK_RX_STATUS_HALF_LSB_  ^| r/- <| RX link _i_ FIFO at least half full
                                                   <|`23:16` _SLINK_RX_STATUS_FULL_MSB_  : _SLINK_RX_STATUS_FULL_LSB_  ^| r/- <| RX link _i_ FIFO full
                                                   <|`31:24` _SLINK_RX_STATUS_LAST_MSB_  : _SLINK_RX_STATUS_LAST_LSB_  ^| r/- <| Current data word of RX link _i_ is marked as "end of packet"
.4+<| `0xfffffecc` .4+<| `NEORV32_SLINK.TX_STATUS` <|`7:0`   _SLINK_TX_STATUS_EMPTY_MSB_ : _SLINK_TX_STATUS_EMPTY_LSB_ ^| r/- <| TX link _i_ FIFO empty
                                                   <|`15:8`  _SLINK_TX_STATUS_HALF_MSB_  : _SLINK_TX_STATUS_HALF_LSB_  ^| r/- <| TX link _i_ FIFO at least half full
                                                   <|`23:16` _SLINK_TX_STATUS_FULL_MSB_  : _SLINK_TX_STATUS_FULL_LSB_  ^| r/- <| TX link _i_ FIFO full
                                                   <|`31:24` _SLINK_TX_STATUS_LAST_MSB_  : _SLINK_TX_STATUS_LAST_LSB_  ^| r/w <| Set to mark next data word of TX link _i_ is "end of packet"
| `0xfffffed0` : `0xfffffedf` | - |`31:0` | r/- | _reserved_, returns zero
| `0xfffffee0` | `NEORV32_SLINK.DATA[0]` | `31:0` | r/w | Link 0 RX/TX data
| `0xfffffee4` | `NEORV32_SLINK.DATA[1]` | `31:0` | r/w | Link 1 RX/TX data
| `0xfffffee8` | `NEORV32_SLINK.DATA[2]` | `31:0` | r/w | Link 2 RX/TX data
| `0xfffffeec` | `NEORV32_SLINK.DATA[3]` | `31:0` | r/w | Link 3 RX/TX data
| `0xfffffef0` | `NEORV32_SLINK.DATA[4]` | `31:0` | r/w | Link 4 RX/TX data
| `0xfffffef4` | `NEORV32_SLINK.DATA[5]` | `31:0` | r/w | Link 5 RX/TX data
| `0xfffffef8` | `NEORV32_SLINK.DATA[6]` | `31:0` | r/w | Link 6 RX/TX data
| `0xfffffefc` | `NEORV32_SLINK.DATA[7]` | `31:0` | r/w | Link 7 RX/TX data
|=======================
