OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [docs/] [datasheet/] [soc_xip.adoc] - Rev 74

Go to most recent revision | Compare with Previous | Blame | View Log

<<<
:sectnums:
==== Execute In Place Module (XIP)

[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_xip.vhd | 
| Software driver file(s): | neorv32_xip.c |
|                          | neorv32_xip.h |
| Top entity port:         | `xip_csn_o` | 1-bit chip select, low-active
|                          | `xip_clk_o` | 1-bit serial clock output
|                          | `xip_sdi_i` | 1-bit serial data input
|                          | `xip_sdo_o` | 1-bit serial data output
| Configuration generics:  | _IO_XIP_EN_ | implement XIP module when _true_
| CPU interrupts:          | none | 
|=======================


**Overview**

The execute in place (XIP) module is probably one of the more complicated modules of the NEORV32. The module
allows to execute code (and read constant data) directly from a SPI flash memory. Hence, it uses the standard
serial peripheral interface (SPI) as transfer protocol under the hood.

The XIP flash is not mapped to a specific region of the processor's address space. Instead, the XIP module
provides a programmable mapping scheme to allow a flexible user-defined mapping of the flash to _any section_
of the address space.

From the CPU side, the modules provides two different interfaces: one for transparently accessing the XIP flash and another
one for accessing the module's control and status registers. The first interface provides a _transparent_
gateway to the SPI flash, so the CPU can directly fetch and execute instructions (and/or read constant _data_).
Note that this interface is read-only. Any write access will raise a bus error exception.
The second interface is mapped to the processor's IO space and allows data accesses to the XIP module's
configuration registers.

[TIP]
An example program for the XIP module is available in `sw/example/demo_xip`.

[NOTE]
Quad-SPI (QSPI) support, which is about 4x times faster, is planned for the future. 😉


**SPI Protocol**

The XIP module accesses external flash using the standard SPI protocol. The module always sends data MSB-first and
provides all of the standard four clock modes (0..3), which are configured via the _XIP_CTRL_CPOL_ (clock polarity)
and _XIP_CTRL_CPHA_ (clock phase) control register bits, respectively. The clock speed of the interface (`xip_clk_o`)
is defined by a three-bit clock pre-scaler configured using the _XIP_CTRL_PRSCx_ bits:

.XIP prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| **`XIP_CTRL_PRSCx`**        | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| Resulting `clock_prescaler` |       2 |       4 |       8 |      64 |     128 |    1024 |    2048 |    4096
|=======================

Based on the _XIP_CTRL_PRSCx_ configuration the actual XIP SPI clock frequency f~XIP~ is derived from the processor's
main clock f~main~ and is determined by:

_**f~XIP~**_ = _f~main~[Hz]_ / (2 * `clock_prescaler`)

Hence, the maximum XIP clock speed is f~main~ / 4.

.High-Speed SPI mode
[TIP]
The module provides a "high-speed" SPI mode. In this mode the clock prescaler configuration (_XIP_CTRL_PRSCx_) is ignored
and the SPI clock operates at f~main~ / 2 (half of the processor's main clock). High speed SPI mode is enabled by setting
the control register's _XIP_CTRL_HIGHSPEED_ bit.

The flash's "read command", which initiates a read access, is defined by the _XIP_CTRL_RD_CMD_ control register bits.
For most SPI flash memories this is `0x03` for normal SPI mode.


**Direct SPI Access**

The XIP module allows to initiate _direct_ SPI transactions. This feature can be used to configure the attached SPI
flash or to perform direct read and write accesses to the flash memory. Two data registers `NEORV32_XIP.DATA_LO` and
`NEORV32_XIP.DATA_HI` are provided to send up to 64-bit of SPI data. The `NEORV32_XIP.DATA_HI` register is write-only,
so a total of 32-bit receive data is provided. Note that the module handles the chip-select
line (`xip_csn_o`) by itself so it is not possible to construct larger consecutive transfers.

The actual data transmission size in bytes is defined by the control register's _XIP_CTRL_SPI_NBYTES_ bits.
Any configuration from 1 byte to 8 bytes is valid. Other value will result in unpredictable behavior.

Since data is always transferred MSB-first, the data in `DATA_HI:DATA_LO` also has to be MSB-aligned. Receive data is
available in `DATA_LO` only - `DATA_HI` is write-only. Writing to `DATA_HI` triggers the actual SPI transmission.
The _XIP_CTRL_PHY_BUSY_ control register flag indicates a transmission being in progress.

The chip-select line of the XIP module (`xip_csn_o`) will only become asserted (enabled, pulled low) if the
_XIP_CTRL_SPI_CSEN_ control register bit is set. If this bit is cleared, `xip_csn_o` is always disabled
(pulled high).

[NOTE]
Direct SPI mode is only possible when the module is enabled (setting _XIP_CTRL_EN_) but **before** the actual
XIP mode is enabled via _XIP_CTRL_XIP_EN_.

[TIP]
When the XIP mode is not enabled, the XIP module can also be used as additional general purpose SPI controller
with a transfer size of up to 64 bits per transmission.


**Address Mapping**

The address mapping of the XIP flash is not fixed by design. It can be mapped to _any section_ within the processor's
address space. A _section_ refers to one out of 16 naturally aligned 256MB wide memory segments. This segment
is defined by the four most significant bits of the address (`31:28`) and the XIP's segment is programmed by the
four _XIP_CTRL_XIP_PAGE_ bits in the unit's control register. All accesses within this page will be mapped to the XIP flash.

[NOTE]
Care must be taken when programming the page mapping to prevent access collisions with other modules (like internal memories
or modules attached to the external memory interface).

Example: to map the XIP flash to the address space starting at `0x20000000` write a "2" (`0b0010`) to the _XIP_CTRL_XIP_PAGE_
control register bits. Any access within `0x20000000 .. 0x2fffffff` will be forwarded to the XIP flash.
Note that the SPI access address might wrap around.

.Using the FPGA Bitstream Flash also for XIP
[TIP]
You can also use the FPGA's bitstream SPI flash for storing XIP programs. To prevent overriding the bitstream,
a certain offset needs to be added to the executable (which might require linker script modifications).
To execute the program stored in the SPI flash simply jump to the according base address. For example
if the executable starts at flash offset `0x8000` and the XIP flash is mapped to the base address `0x20000000`
then add the offset to the base address and use that as jump/call destination (=`0x20008000`).


**Using the XIP Mode**

The XIP module is globally enabled by setting the _XIP_CTRL_EN_ bit in the device's `CTRL` control register.
Clearing this bit will reset the whole module and will also terminate any pending SPI transfer.

Since there is a wide variety of SPI flash components with different sizes, the XIP module allows to specify
the address width of the flash: the number of address bytes used for addressing flash memory content has to be
configured using the control register's _XIP_CTRL_XIP_ABYTES_ bits. These two bits contain the number of SPI
address bytes (**minus one**). For example for a SPI flash with 24-bit addresses these bits have to be set to
`0b10`.

The transparent XIP accesses are transformed into SPI transmissions with the following format (starting with the MSB):

* 8-bit command: configured by the _XIP_CTRL_RD_CMD_ control register bits ("SPI read command")
* 8 to 32 bits address: defined by the _XIP_CTRL_XIP_ABYTES_ control register bits ("number of address bytes")
* 32-bit data: sending zeros and receiving the according flash word (32-bit)

Hence, the maximum XIP transmission size is 72-bit, which has to be configured via the _XIP_CTRL_SPI_NBYTES_
control register bits. Note that the 72-bit transmission size is only available in XIP mode. The transmission
size of the direct SPI accesses is limited to 64-bit.

[NOTE]
There is no _continuous read_ feature (i.e. a burst SPI transmission fetching several data words at once) implemented yet.

[NOTE]
When using four SPI flash address bytes, the most significant 4 bits of the address are always hardwired
to zero allowing a maximum **accessible** flash size of 256MB.

After the SPI properties (including the amount of address bytes **and** the total amount of SPI transfer bytes)
and XIP address mapping are configured, the actual XIP mode can be enabled by setting
the control register's _XIP_CTRL_XIP_EN_ bit. This will enable the "transparent SPI access port" of the module and thus,
the _transparent_ conversion of access requests into proper SPI flash transmissions. Make sure _XIP_CTRL_SPI_CSEN_
is also set so the module can actually select/enable the attached SPI flash.
No more direct SPI accesses via `DATA_HI:DATA_LO` are possible when the XIP mode is enabled. However, the
XIP mode can be disabled at any time.

[NOTE]
If the XIP module is disabled (_XIP_CTRL_EN_ = `0`) any accesses to the programmed XIP memory segment are ignored
by the module and might be forwarded to the processor's external memory interface (if implemented) or will cause a bus
exception. If the XIP module is enabled (_XIP_CTRL_EN_ = `1`) but XIP mode is not enabled yet (_XIP_CTRL_XIP_EN_ = '0')
any access to the programmed XIP memory segment will raise a bus exception.

[TIP]
It is highly recommended to enable the <<_processor_internal_instruction_cache_icache>> to cover some
of the SPI access latency.


.XIP register map (`struct NEORV32_XIP`)
[cols="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.16+<| `0xffffff40` .16+<| `NEORV32_XIP.CTRL` <|`0`  _XIP_CTRL_EN_    ^| r/w <| XIP module enable
                                              <|`1`  _XIP_CTRL_PRSC0_ ^| r/w .3+| 3-bit SPI clock prescaler select
                                              <|`2`  _XIP_CTRL_PRSC1_ ^| r/w
                                              <|`3`  _XIP_CTRL_PRSC2_ ^| r/w
                                              <|`4`  _XIP_CTRL_CPOL_  ^| r/w <| SPI clock polarity
                                              <|`5`  _XIP_CTRL_CPHA_  ^| r/w <| SPI clock phase
                                              <|`9:6`  _XIP_CTRL_SPI_NBYTES_MSB_ : _XIP_CTRL_SPI_NBYTES_LSB_ ^| r/w <| Number of bytes in SPI transaction (1..9)
                                              <|`10` _XIP_CTRL_XIP_EN_ ^| r/w <| XIP mode enable
                                              <|`12:11` _XIP_CTRL_XIP_ABYTES_MSB_ : _XIP_CTRL_XIP_ABYTES_LSB_ ^| r/w <| Number of address bytes for XIP flash (minus 1)
                                              <|`20:13` _XIP_CTRL_RD_CMD_MSB_ : _XIP_CTRL_RD_CMD_LSB_ ^| r/w <| Flash read command
                                              <|`24:21` _XIP_CTRL_XIP_PAGE_MSB_ : _XIP_CTRL_XIP_PAGE_LSB_ ^| r/w <| XIP memory page
                                              <|`25` _XIP_CTRL_SPI_CSEN_  ^| r/w <| Allow SPI chip-select to be actually asserted when set
                                              <|`26` _XIP_CTRL_HIGHSPEED_ ^| r/w <| enable SPI high-speed mode (ignoring _XIP_CTRL_PRSC_)
                                              <|`29:27`                   ^| r/- <| _reserved_, read as zero
                                              <|`30` _XIP_CTRL_PHY_BUSY_  ^| r/- <| SPI PHY busy when set
                                              <|`31` _XIP_CTRL_XIP_BUSY_  ^| r/- <| XIP access in progress when set
| `0xffffff44` | _reserved_            |`31:0` | r/- | _reserved_, read as zero
| `0xffffff48` | `NEORV32_XIP.DATA_LO` |`31:0` | r/w | Direct SPI access - data register low
| `0xffffff4C` | `NEORV32_XIP.DATA_HI` |`31:0` | -/w | Direct SPI access - data register high; write access triggers SPI transfer
|=======================

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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