URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/docs/datasheet
- from Rev 67 to Rev 68
- ↔ Reverse comparison
Rev 67 → Rev 68
/cpu.adoc
611,28 → 611,31
|
The CSR access instructions as well as the exception and interrupt system (= the privileged architecture) |
is implemented when the `CPU_EXTENSION_RISCV_Zicsr` configuration generic is _true_. |
|
[IMPORTANT] |
If the `Zicsr` extension is disabled the CPU does not provide any _privileged architecture_ features at all! |
In order to provide the full set of privileged functions that are required to run more complex tasks like |
operating system and to allow a secure execution environment the `Zicsr` extension should always be enabled. |
|
In this case the following instructions are available: |
|
* CSR access: `csrrw`, `csrrs`, `csrrc`, `csrrwi`, `csrrsi`, `csrrci` |
* environment: `mret`, `wfi` |
|
[WARNING] |
If the `Zicsr` extension is disabled the CPU does not provide any _privileged architecture_ features at all! |
In order to provide the full set of functions and to allow a secure execution |
environment the `Zicsr` extension should always be enabled. |
[NOTE] |
If `rd=x0` for the `csrrw[i]` instructions there will be no actual read access to the according CSR. |
However, access privileges are still enforced so these instruction variants _do_ cause side-effects |
(the RISC-V spec. state that these combinations "_shall_ not cause any side-effects"). |
|
[NOTE] |
The "wait for interrupt instruction" `wfi` works like a sleep command. When executed, the CPU is |
The "wait for interrupt instruction" `wfi` acts like a sleep command. When executed, the CPU is |
halted until a valid interrupt request occurs. To wake up again, the according interrupt source has to |
be enabled via the `mie` CSR and the global interrupt enable flag in `mstatus` has to be set. |
|
[NOTE] |
The `wfi` instruction may also be executed in user-mode without causing an exception as <<_mstatus>> bit |
`TW` (timeout wait) is hardwired to zero. |
`TW` (timeout wait) is _hardwired_ to zero. |
|
|
|
|
==== **`Zicntr`** CPU Base Counters |
|
The `Zicntr` ISA extension adds the basic cycle `[m]cycle[h]`), instruction-retired (`[m]instret[h]`) and time (`time[h]`) |
/on_chip_debugger.adoc
87,13 → 87,11
| `jtag_tms_i` | 1 | in | mode select |
|======================= |
|
.JTAG Clock |
.Maximum JTAG Clock |
[IMPORTANT] |
The actual JTAG clock signal is **not** used as primary clock. Instead it is used to synchronize |
JTGA accesses, while all internal operations trigger on the system clock. Hence, no additional clock domain is required |
for integration of this module. |
However, this constraints the maximal JTAG clock (`jtag_tck_i`) frequency to be less than or equal to |
1/4 of the system clock (`clk_i`) frequency. |
All JTAG signals are synchronized to the processor clock domain by oversampling them in DTM. Hence, no additional |
clock domain is required for the DTM. However, this constraints the maximal JTAG clock frequency (`jtag_tck_i`) to be less |
than or equal to **1/5** of the processor clock frequency (`clk_i`). |
|
[NOTE] |
If the on-chip debugger is disabled (_ON_CHIP_DEBUGGER_EN_ = false) the JTAG serial input `jtag_tdi_i` is directly |
127,10 → 125,24
| others | `BYPASS` | 1 | default JTAG bypass register |
|======================= |
|
.`DTMCS` - DTM Control and Status Register |
[cols="^2,^3,^1,<8"] |
[options="header",grid="rows"] |
|======================= |
| Bit(s) | Name | r/w | Description |
| 31:18 | - | r/- | _reserved_, hardwired to zero |
| 17 | `dmihardreset` | r/w | setting this bit will reset the DM interface; this bit auto-clears |
| 16 | `dmireset` | r/w | setting this bit will clear ste sticky error state; this bit auto-clears |
| 15 | - | r/- | _reserved_, hardwired to zero |
| 14:12 | `idle` | r/- | recommended idle states (= 0, no idle states required) |
| 11:10 | `dmistat` | r/- | DMI statu: `00` = no error, `01` = reserved, `10` = operation failed, `11` = failed operation during pending DMI operation |
| 9:4 | `abits` | r/- | number of DMI address bits (= 7) |
| 3:0 | `version` | r/- | `0001` = spec version 0.13 |
|======================= |
|
[INFO] |
See the https://github.com/riscv/riscv-debug-spec[RISC-V debug specification] for more information regarding the data |
registers and operations. |
A local copy can be found in `docs/references`. |
registers and operations. A local copy can be found in `docs/references`. |
|
|
|
/overview.adoc
107,7 → 107,13
vs. size trade-off and a different focus: _embrace_ concepts like documentation, platform-independence / portability, |
RISC-V compatibility, _customization_ and _ease of use_. See the <<_project_key_features>> below. |
|
Furthermore, the NEORV32 pays special focus on _execution safety_ using <<_full_virtualization>>. The CPU aims to |
provide fall-backs for _everything that could go wrong_. This includes malformed instruction words, privilege escalations |
and even memory accesses that are checked for address space holes and deterministic response times from memory-mapped |
devices. Precise exceptions allow a defined and fully-synchronized state of the CPU at every time. |
|
|
|
// #################################################################################################################### |
:sectnums: |
=== Project Key Features |
193,7 → 199,7
:sectnums: |
=== VHDL File Hierarchy |
|
All necessary VHDL hardware description files are located in the project's `rtl/core folder`. The top entity |
All necessary VHDL hardware description files are located in the project's `rtl/core` folder. The top entity |
of the entire processor including all the required configuration generics is **`neorv32_top.vhd`**. |
|
[IMPORTANT] |
243,14 → 249,14
├neorv32_wishbone.vhd - External (Wishbone) bus interface |
├neorv32_xirq.vhd - External interrupt controller |
│ |
├mem/neorv32_dmem.default.vhd - _Default_ data memory (architecture-only!) |
â””mem/neorv32_imem.default.vhd - _Default_ instruction memory (architecture-only!) |
├mem/neorv32_dmem.default.vhd - _Default_ data memory (architecture-only) |
â””mem/neorv32_imem.default.vhd - _Default_ instruction memory (architecture-only) |
................................... |
|
[NOTE] |
The processor-internal instruction and data memories (IMEM and DMEM) are split into two design files each: |
a plain entity definition (`neorv32_*mem.entity.vhd`) and the actual architecture definition |
(`mem/neorv32_*mem.default.vhd`). The **default** architecture definitions from `rtl/core/mem` provide a _generic_ and |
(`mem/neorv32_*mem.default.vhd`). The `*.default.vhd` architecture definitions from `rtl/core/mem` provide a _generic_ and |
_platform independent_ memory design that (should) infers embedded memory blocks. You can replace/modify the architecture |
source file in order to use platform-specific features (like advanced memory resources) or to improve technology mapping |
and/or timing. |
/soc.adoc
1321,32 → 1321,35
:sectnums!: |
===== Indirect Boot |
|
The _indirect_ boot scenarios **1a** and **1b** use the processor-internal <<_bootloader>>. This general setup is enabled |
by setting the <<_int_bootloader_en>> generic to true, which will implement the processor-internal <<_bootloader_rom_bootrom>>. |
The _indirect_ boot scenarios **1a** and **1b** use the processor-internal <<_bootloader>>. This boot setup is enabled |
by setting the <<_int_bootloader_en>> generic to _true_, which will implement the processor-internal <<_bootloader_rom_bootrom>>. |
This read-only memory is pre-initialized during synthesis with the default bootloader firmware. |
The bootloader provides several options to upload an executable (via UART or from external SPI flash) and copies it to |
the beginning of the _instruction address space_ so the CPU can execute it. |
|
The bootloader provides several options to upload an executable (via UART or from external SPI flash) and store it to |
the _instruction address space_ so the CPU can execute it. Boot scenario **1a** uses the processor-internal IMEM |
Boot scenario **1a** uses the processor-internal IMEM |
(<<_mem_int_imem_en>> = _true_). This scenario implements the internal <<_instruction_memory_imem>> as non-initialized |
RAM so the bootloader can write the actual executable to it. |
RAM so the bootloader can copy the actual executable to it. |
|
Boot scenario **1b** uses a processor-external IMEM (<<_mem_int_imem_en>> = _false_) that is connected via the processor's |
bus interface. In this scenario the internal <<_instruction_memory_imem>> is not implemented at all and the bootloader will |
write the executable to the processor-external memory. |
copy the executable to the processor-external memory. Hence, the external memory has to be implemented as RAM. |
|
:sectnums!: |
===== Direct Boot |
|
The _direct_ boot scenarios **2a** and **2b** do not use the processor-internal bootloader. Hence, the <<_int_bootloader_en>> |
The _direct_ boot scenarios **2a** and **2b** do not use the processor-internal bootloader since the <<_int_bootloader_en>> |
generic is set _false_. In this configuration the <<_bootloader_rom_bootrom>> is not implemented at all and the CPU will |
directly begin executing code from the instruction address space after reset. A "pre-initialization mechanism is required |
in order to provide an executable _in_ memory. |
directly begin executing code from the beginning of the instruction address space after reset. An application-specific |
"pre-initialization" mechanism is required in order to provide an executable _in_ memory. |
|
Boot scenario **2a** uses the processor-internal IMEM (<<_mem_int_imem_en>> = _true_) that is implemented as _read-only memory_ |
in this scenario. It is pre-initialized (by the bitstream) with the actual application executable. |
in this scenario. It is pre-initialized (by the bitstream) with the actual application executable during synthesis. |
|
In contrast, boot scenario **2b** uses a processor-external IMEM (<<_mem_int_imem_en>> = _false_). In this scenario the |
system designer is responsible for providing a initialized external memory that contains the actual application to be executed. |
system designer is responsible for providing an initialized external memory that contains the actual application to be executed. |
If the external is not already initialized after reset, a simple ROM containing a "polling loop" can be implemented that is |
exited as soon as the application logic has finished initializing the memory with the acutal application code. |
|
|
|
/soc_buskeeper.adoc
13,6 → 13,7
| CPU interrupts: | none | |
|======================= |
|
|
**Theory of Operation** |
|
The Bus Keeper is a fundamental component of the processor's internal bus system that ensures correct bus operations |
30,35 → 31,25
|
In case of a bus access fault exception application software can evaluate the Bus Keeper's control register |
`NEORV32_BUSKEEPER.CTRL` to retrieve further details of the bus exception. The _BUSKEEPER_ERR_FLAG_ bit indicates |
that an actual bus access fault has occurred. The bit is sticky once set is automatically cleared when reading the |
`NEORV32_BUSKEEPER.CTRL` register. The _BUSKEEPER_ERR_TYPE_ indicated the tape or bus fault: |
that an actual bus access fault has occurred. The bit is sticky once set and is automatically cleared when reading or |
writing the `NEORV32_BUSKEEPER.CTRL` register. The _BUSKEEPER_ERR_TYPE_ indicated the tape of the bus fault: |
|
* _BUSKEEPER_ERR_TYPE_ = `0` - "Device Error": The bus access exception was cause by the memory-mapped device that |
has been accessed (the device asserted it's `err_o`). |
* _BUSKEEPER_ERR_TYPE_ = `1` - "Timeout Error": The bus access exception was caused by the Bus Keeper because the |
accessed memory-mapped device did not respond within the access time window. |
accessed memory-mapped device did not respond within the access time window. Note that this error type can also be raised |
by the optional timeout feature of the <<_processor_external_memory_interface_wishbone_axi4_lite>>). |
|
[NOTE] |
Bus access fault exceptions are also raised if a physical memory protection rule is violated. In this case |
the _BUSKEEPER_ERR_FLAG_ bit remains zero. |
|
Furthermore, application software can determine the source of the bus access fault via the _BUSKEEPER_ERR_SRC_ bit: |
|
* _BUSKEEPER_ERR_SRC_ = `0`: The error was cause during access via the <<_processor_external_memory_interface_wishbone_axi4_lite>>). |
* _BUSKEEPER_ERR_SRC_ = `1`: The error was cause during access to an processor-internal module. |
|
[NOTE] |
The Bus Keeper does not track **timeout errors** of processor-external accesses via the external memory bus interface. |
However, the external memory bus interface also provides an _optional_ and independent bus timeout feature |
(see section <<_processor_external_memory_interface_wishbone_axi4_lite>>). |
|
|
.BUSKEEPER register map (`struct NEORV32_BUSKEEPER`) |
[cols="<2,<2,<4,^1,<4"] |
[options="header",grid="all"] |
|======================= |
| Address | Name [C] | Bit(s), Name [C] | R/W | Function |
.3+<| `0xffffff7C` .3+<| `NEORV32_BUSKEEPER.CTRL` <|`0` _BUSKEEPER_ERR_TYPE_ ^| r/- <| Bus error type, valid if _BUSKEEPER_ERR_FLAG_ is set: `0`=device error, `1`=access timeout |
<|`1` _BUSKEEPER_ERR_SRC_ ^| r/- <| Error source: `0`=processor-internal, `1`=processor-external (via Wishbone bus interface) |
<|`31` _BUSKEEPER_ERR_FLAG_ ^| r/- <| Sticky error flag, clears after read |
.2+<| `0xffffff7C` .2+<| `NEORV32_BUSKEEPER.CTRL` <|`0` _BUSKEEPER_ERR_TYPE_ ^| r/- <| Bus error type, valid if _BUSKEEPER_ERR_FLAG_ is set: `0`=device error, `1`=access timeout |
<|`31` _BUSKEEPER_ERR_FLAG_ ^| r/- <| Sticky error flag, clears after read or write access |
|======================= |
/soc_neoled.adoc
163,19 → 163,20
data word being written to the TX buffer making busy wait concepts obsolete and allowing maximum refresh rates. |
|
|
**Interrupt** |
**NEOLED Interrupt** |
|
The NEOLED modules features a single interrupt that becomes pending based on the current TX buffer fill level. |
The interrupt can only become pending if the NEOLED module is enabled. The specific interrupt condition |
is configured via the _NEOLED_CTRL_IRQ_CONF_ in the control register `NEORV32_NEOLED.CTRL`. |
is configured via the _NEOLED_CTRL_IRQ_CONF_ bit in the unit's control register. |
|
If _NEOLED_CTRL_IRQ_CONF_ is cleared, an interrupt is generated whenever the TX FIFO is _less than half-full_. |
If _NEOLED_CTRL_IRQ_CONF_ is cleared, an interrupt is generated whenever the TX FIFO _becomes_ less than half-full. |
In this case software can write up to _IO_NEOLED_TX_FIFO_/2 new data words to `DATA` without checking the FIFO |
status flags. The interrupt request is cleared whenever the FIFO fill level is above _half-full_ level or if |
the NEOLED module is disabled. |
status flags. If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO _becomes_ empty. |
|
If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO is _empty_. The interrupt |
request is cleared again when the FIFO contains at least one data word. |
A pending interrupt request is cleared is cleared by any of the following operations: |
* write access to `NEORV32_NEOLED.DATA` (for example to send more LED data) |
* write access to `NEORV32_NEOLED.CTRL` |
* disabling the NEOLED module |
|
[NOTE] |
The _NEOLED_CTRL_IRQ_CONF_ is hardwired to one if _IO_NEOLED_TX_FIFO_ = 1 (-> IRQ if FIFO is empty). |
/soc_slink.adoc
79,11 → 79,14
The NEORV32 processor ensures that _any_ CPU access to memory-mapped devices (including the SLINK module) |
will **time out** after a certain number of cycles (see section <<_bus_interface>>). |
Hence, blocking access to a stream link that does not complete within a certain amount of cycles will |
raise a _store bus access exception_ when writing a _full_ TX link or a _load bus access exception_ when reading |
from an _empty_ RX link. Hence, this concept should only be used when evaluating the half-full FIFO condition |
(for example via the SLINK interrupts) before actual accessing links. |
raise a _store bus access exception_ when writing to a _full_ TX link's FIFO or a _load bus access exception_ |
when reading from an _empty_ RX 's FIFO. Hence, this concept should only be used when evaluating the half-full |
FIFO condition (for example via the SLINK interrupts) before actual accessing links. |
|
[NOTE] |
There is no RX FIFO overflow mechanism available yet. |
|
|
**Non-Blocking Link Access** |
|
For a non-blocking link access concept, the FIFO status flags in `STATUS` need to be checked _before_ |
118,43 → 121,52
The SLINK handshake protocol is compatible with the https://developer.arm.com/documentation/ihi0051/a/Introduction/About-the-AXI4-Stream-protocol[AXI4-Stream] base protocol. |
|
|
**Interrupts** |
**SLINK Interrupts** |
|
The stream interface provides two independent interrupts that are _globally_ driven by the RX and TX link's |
FIFO fill level status. Each RX and TX link provides an individual interrupt enable flag and an individual |
interrupt type flag that allows to configure interrupts only for certain (or all) links and for application- |
specific interrupt conditions. The interrupt configuration is done using the `NEORV32_SLINK.IRQ` register. |
specific FIFO conditions. The interrupt configuration is done using the `NEORV32_SLINK.IRQ` register. |
Any interrupt can only become pending if the SLINK module is enabled at all. |
|
[NOTE] |
There is no RX FIFO overflow mechanism available yet. |
|
The current FIFO fill-level of a specific **RX link** can only raise an interrupt request if it's interrupt enable flag |
_SLINK_IRQ_RX_EN_ is set. Vice versa, the current FIFO fill-level of a specific **TX link** can only raise an interrupt |
request if it's interrupt enable flag _SLINK_IRQ_TX_EN_ is set. |
|
The **RX link's** _SLINK_IRQ_RX_MODE_ flags define the FIFO fill-level condition for raising an RX interrupt request: |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO is _not empty_ ("RX data available"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO is _at least half-full_ ("time to get data from RX FIFO to prevent overflow"). |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ not empty ("RX data available"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ at least half-full ("time to get data from RX FIFO to prevent overflow"). |
|
The **TX link's** _SLINK_IRQ_TX_MODE_ flags define the FIFO fill-level condition for raising an TX interrupt request: |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO is _not full_ ("space left in FIFO for new TX data"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO is _less than half-full_ ("SW can send _SLINK_TX_FIFO_/2 data words without checking any flags"). |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ not full ("space left in FIFO for new TX data"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ less than half-full ("SW can send _SLINK_TX_FIFO_/2 data words without checking any flags"). |
|
[NOTE] |
If _SLINK_RX_FIFO_ is 1 the _SLINK_IRQ_RX_MODE_ bits are hardwired to one. |
If _SLINK_TX_FIFO_ is 1 the _SLINK_IRQ_TX_MODE_ bits are hardwired to one. |
[IMPORTANT] |
The interrupt configuration register `NEORV32_SLINK.IRQ` should we written _before_ the SLINK |
module is actually enabled. |
|
[NOTE] |
There is no RX FIFO overflow mechanism available yet. |
If _SLINK_RX_FIFO_ is 1 all _SLINK_IRQ_RX_MODE_ bits are hardwired to one. |
If _SLINK_TX_FIFO_ is 1 all _SLINK_IRQ_TX_MODE_ bits are hardwired to one. |
|
If _any_ configured interrupt condition is fulfilled, the according global SLINK RX / SLINK TX CPU |
interrupt becomes pending. |
If the interrupt enable flags of several links are set, the interrupt service handler has to evaluate the SLINK |
status register is order to detect which link(s) caused the interrupt. |
A **pending RX interrupt** request is cleared by any of the following operations: |
* read access to any `NEORV32_SLINK.DATA` (for example to read incoming data) |
* write access to `NEORV32_SLINK.CTRL` |
* disabling the SLINK module |
|
[NOTE] |
If the programmed interrupt condition is fulfilled, the corresponding IRQ will become _pending_ until |
the causing interrupt conditions is resolved (for example by reading data from the according RX FIFO). |
A **pending TX interrupt** request is cleared by any of the following operations: |
* write access any `NEORV32_SLINK.DATA` (for example to send more data) |
* write access to `NEORV32_SLINK.CTRL` |
* disabling the SLINK module |
|
[TIP] |
A dummy write to to the control register (i.e. `NEORV32_SLINK.DATA = NEORV32_SLINK.DATA`) |
can be executed to acknowledge any interrupt. |
|
|
.SLINK register map (`struct NEORV32_SLINK`) |
[cols="^4,<5,^2,^2,<14"] |
[options="header",grid="all"] |
168,9 → 180,9
<| `3:0` _SLINK_CTRL_RX_NUM3_ : _SLINK_CTRL_RX_NUM0_ ^| r/- <| Number of implemented RX links |
| `0xfffffec4` | - |`31:0` | r/- | _reserved_ |
.4+<| `0xfffffec8` .4+<| `NEORV32_SLINK.IRQ` <|`31:24` _SLINK_IRQ_RX_EN_MSB_ : _SLINK_IRQ_RX_EN_LSB_ ^| r/w <| RX interrupt enable for link 7..0 |
<|`23:16` _SLINK_IRQ_RX_MODE_MSB_ : _SLINK_IRQ_RX_MODE_LSB_ ^| r/w <| RX IRQ mode for link 7..0: `0` = FIFO at least half-full; `1` = FIFO not empty |
<|`23:16` _SLINK_IRQ_RX_MODE_MSB_ : _SLINK_IRQ_RX_MODE_LSB_ ^| r/w <| RX IRQ mode for link 7..0: `0` = FIFO rises above half-full; `1` = FIFO not empty |
<|`15:8` _SLINK_IRQ_TX_EN_MSB_ : _SLINK_IRQ_TX_EN_LSB_ ^| r/w <| TX interrupt enable for link 7..0 |
<|`7:0` _SLINK_IRQ_TX_MODE_MSB_ : _SLINK_IRQ_TX_MODE_LSB_ ^| r/w <| TX IRQ mode for link 7..0: `0` = FIFO less than half-full; `1` = FIFO not full |
<|`7:0` _SLINK_IRQ_TX_MODE_MSB_ : _SLINK_IRQ_TX_MODE_LSB_ ^| r/w <| TX IRQ mode for link 7..0: `0` = FIFO falls below half-full; `1` = FIFO not full |
| `0xfffffeec` | - |`31:0` | r/- | _reserved_ |
.4+<| `0xfffffed0` .4+<| `NEORV32_SLINK.STATUS` <| `31:24` _SLINK_STATUS_TX7_HALF_ : _SLINK_STATUS_TX0_HALF_ ^| r/- <| TX link 7..0 FIFO fill level is >= half-full |
<| `23:16` _SLINK_STATUS_RX7_HALF_ : _SLINK_STATUS_RX0_HALF_ ^| r/- <| RX link 7..0 FIFO fill level is >= half-full |
/soc_spi.adoc
107,11 → 107,18
|
**SPI Interrupt** |
|
The SPI module provides a single interrupt to signal "ready for new transmission" to the CPU. Whenever the SPI |
module is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared |
by triggering a new SPI transmission or by disabling the SPI module. |
The SPI module provides a single interrupt to signal "transmission done" to the CPU. Whenever the SPI |
module completes the current transfer operation, the interrupt request is set. A pending interrupt request |
is cleared by any of the following operations: |
* read or write access to `NEORV32_SPI.DATA` (for example to trigger a new transmission) |
* write access to `NEORV32_SPI.CTRL` |
* disabling the SPI module |
|
[TIP] |
A dummy read from `NEORV32_SPI.DATA` can be executed to acknowledge the interrupt without affecting data |
or the state of the SPI module. |
|
|
.SPI register map (`struct NEORV32_SPI`) |
[cols="<2,<2,<4,^1,<7"] |
[options="header",grid="all"] |
/soc_trng.adoc
13,65 → 13,36
| CPU interrupts: | none | |
|======================= |
|
|
**Theory of Operation** |
|
The NEORV32 true random number generator provides _physical true random numbers_ for your application. |
Instead of using a pseudo RNG like a LFSR, the TRNG of the processor uses a simple, straight-forward ring |
oscillator as physical entropy source. Hence, voltage and thermal fluctuations are used to provide true |
physical random data. |
The NEORV32 true random number generator provides _physical_ true random numbers. |
Instead of using a pseudo RNG like a LFSR, the TRNG uses a simple, straight-forward ring |
oscillator concept as physical entropy source. Hence, voltage, thermal and also semiconductor manufacturing |
fluctuations are used to provide a true physical entropy source. |
|
The TRNG is based on the neoTRNG[https://github.com/stnolting/neoTRNG], which is a "spin-off project" of the |
NEORV32 processor. The TRNG uses the default neoTRNG configuration, which showed very good results in the |
`dieharder` battery of random number tests. More detailed information about the neoTRNG, it's architecture and a |
detailed evaluation of the random number quality can be found it it's repository: https://github.com/stnolting/neoTRNG |
|
[NOTE] |
The TRNG features a platform independent architecture without FPGA-specific primitives, macros or |
attributes. |
attributes so it can be synthesized for _any_ FPGA. |
|
**Architecture** |
|
The NEORV32 TRNG is based on simple ring oscillators, which are implemented as an inverter chain with |
an odd number of inverters. A **latch** is used to decouple each individual inverter. Basically, this architecture |
is some king of asynchronous LFSR. |
|
The output of several ring oscillators are synchronized using two registers and are XORed together. The |
resulting output is de-biased using a von-Neumann randomness extractor. This de-biased output is further |
processed by a simple 8-bit Fibonacci LFSR to improve whitening. After at least 8 clock cycles the state of |
the LFSR is sampled and provided as final data output. |
|
To prevent the synthesis tool from doing logic optimization and thus, removing all but one inverter, the |
TRNG uses simple latches to decouple an inverter and its actual output. The latches are reset when the |
TRNG is disabled and are enabled one by one by a "real" shift register when the TRNG is activated. This |
construct can be synthesized for any FPGA platform. Thus, the NEORV32 TRNG provides a platform |
independent architecture. |
|
**TRNG Configuration** |
|
The TRNG uses several ring-oscillators, where the next oscillator provides a slightly longer chain (more |
inverters) than the one before. This increment is constant for all implemented oscillators. This setup can be |
customized by modifying the "Advanced Configuration" constants in the TRNG's VHDL file: |
|
* The `num_roscs_c` constant defines the total number of ring oscillators in the system. num_inv_start_c |
defines the number of inverters used by the first ring oscillators (has to be an odd number). Each additional |
ring oscillator provides `num_inv_inc_c` more inverters that the one before (has to be an even number). |
* The LFSR-based post-processing can be deactivated using the `lfsr_en_c` constant. The polynomial tap |
mask of the LFSR can be customized using `lfsr_taps_c`. |
|
**Using the TRNG** |
|
The TRNG features a single register for status and data access. When the _TRNG_CTRL_EN_ control register (`CTRL`) |
bit is set, the TRNG is enabled and starts operation. As soon as the _TRNG_CTRL_VALID_ bit is set, the currently |
sampled 8-bit random data byte can be obtained from the lowest 8 bits of the `CTRL` register |
(_TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_LSB_). The _TRNG_CTRL_VALID_ bit is automatically cleared |
when reading the control register. |
(_TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_LSB_). These bits always keep the latest valid data obtained from the TRNG |
entropy source. The _TRNG_CTRL_VALID_ bit is automatically cleared when reading the control register. |
|
[IMPORTANT] |
The TRNG needs at least 8 clock cycles to generate a new random byte. During this sampling time |
the current output random data is kept stable in the output register until a valid sampling of the new byte has |
completed. |
[NOTE] |
The TRNG core does not provide a dedicated reset. In order to ensure correct operations, the TRNG should be |
disabled (=reset) by clearing the _TRNG_CTRL_EN_ and waiting some milliseconds before re-enabling it. |
|
Randomness "Quality" |
I have not verified the quality of the generated random numbers (for example using NIST test suites). The |
quality is highly effected by the actual configuration of the TRNG and the resulting FPGA mapping/routing. |
However, generating larger histograms of the generated random number shows an equal distribution (binary |
average of the random numbers = 127). A simple evaluation test/demo program can be found in |
`sw/example/demo_trng`. |
|
.TRNG register map (`struct NEORV32_TRNG`) |
[cols="<2,<2,<4,^1,<7"] |
78,7 → 49,7
[options="header",grid="all"] |
|======================= |
| Address | Name [C] | Bit(s), Name [C] | R/W | Function |
.3+<| `0xffffffb8` .3+<| `NEORV32_TRNG.CTRL` <|`7:0` _TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_MSB_ ^| r/- <| 8-bit random data output |
<|`30` _TRNG_CTRL_EN_ ^| r/w <| TRNG enable |
<|`31` _TRNG_CTRL_VALID_ ^| r/- <| random data output is valid when set |
.3+<| `0xffffffb8` .3+<| `NEORV32_TRNG.CTRL` <|`7:0` _TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_MSB_ ^| r/- <| 8-bit random data |
<|`30` _TRNG_CTRL_EN_ ^| r/w <| TRNG enable |
<|`31` _TRNG_CTRL_VALID_ ^| r/- <| random data is valid when set |
|======================= |
/soc_twi.adoc
21,8 → 21,8
clock line `twi_scl_io`) - despite of the number of connected devices - it allows easy interconnections of |
several peripheral nodes. |
|
The NEORV32 TWI implements a **TWI controller**. It features "clock stretching" (if enabled via the control |
register), so a slow peripheral can halt the transmission by pulling the SCL line low. Currently, **no multi-controller |
The NEORV32 TWI implements a **TWI controller**. It supports "clock so a slow peripheral can halt |
the transmission by pulling the SCL line low. Currently, **no multi-controller |
support** is available. Also, the NEORV32 TWI unit cannot operate in peripheral mode. |
|
The TWI is enabled via the _TWI_CTRL_EN_ bit in the `CTRL` control register. The user program can start / stop a |
70,27 → 70,34
_**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler`) |
|
|
**Interrupt** |
**TWI Interrupt** |
|
The TWI module provides a single interrupt to signal _idle state_ (= read for new transmission) to the CPU. Whenever TWI SPI module |
is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared |
by triggering a new TWI transmission or by disabling the device. |
The SPI module provides a single interrupt to signal "operation done" to the CPU. Whenever the TWI |
module completes the current operation (generate stop condition, generate start conditions or transfer byte), |
the interrupt request is set. A pending interrupt request is cleared is cleared by any of |
the following operations: |
* read or write access to `NEORV32_TWI.DATA` (for example to trigger a new transmission) |
* write access to `NEORV32_TWI.CTRL` |
* disabling the TWI module |
|
[TIP] |
A dummy read from `NEORV32_TWI.DATA` can be executed to acknowledge the interrupt without affecting data |
or the state of the TWI module. |
|
|
.TWI register map (`struct NEORV32_TWI`) |
[cols="<2,<2,<4,^1,<7"] |
[options="header",grid="all"] |
|======================= |
| Address | Name [C] | Bit(s), Name [C] | R/W | Function |
.10+<| `0xffffffb0` .10+<| `NEORV32_TWI.CTRL` <|`0` _TWI_CTRL_EN_ ^| r/w <| TWI enable |
<|`1` _TWI_CTRL_START_ ^| r/w <| generate START condition |
<|`2` _TWI_CTRL_STOP_ ^| r/w <| generate STOP condition |
<|`3` _TWI_CTRL_PRSC0_ ^| r/w .3+<| 3-bit clock prescaler select |
<|`4` _TWI_CTRL_PRSC1_ ^| r/w |
<|`5` _TWI_CTRL_PRSC2_ ^| r/w |
<|`6` _TWI_CTRL_MACK_ ^| r/w <| generate controller ACK for each transmission ("MACK") |
<|`7` _TWI_CTRL_CKSTEN_ ^| r/w <| allow clock-stretching by peripherals when set |
<|`30` _TWI_CTRL_ACK_ ^| r/- <| ACK received when set |
<|`31` _TWI_CTRL_BUSY_ ^| r/- <| transfer/START/STOP in progress when set |
.9+<| `0xffffffb0` .9+<| `NEORV32_TWI.CTRL` <|`0` _TWI_CTRL_EN_ ^| r/w <| TWI enable |
<|`1` _TWI_CTRL_START_ ^| r/w <| generate START condition |
<|`2` _TWI_CTRL_STOP_ ^| r/w <| generate STOP condition |
<|`3` _TWI_CTRL_PRSC0_ ^| r/w .3+<| 3-bit clock prescaler select |
<|`4` _TWI_CTRL_PRSC1_ ^| r/w |
<|`5` _TWI_CTRL_PRSC2_ ^| r/w |
<|`6` _TWI_CTRL_MACK_ ^| r/w <| generate controller ACK for each transmission ("MACK") |
<|`30` _TWI_CTRL_ACK_ ^| r/- <| ACK received when set |
<|`31` _TWI_CTRL_BUSY_ ^| r/- <| transfer/START/STOP in progress when set |
| `0xffffffb4` | `NEORV32_TWI.DATA` |`7:0` _TWI_DATA_MSB_ : TWI_DATA_LSB_ | r/w | receive/transmit data |
|======================= |
/soc_uart.adoc
108,29 → 108,40
received character and is cleared by reading the `DATA` register. |
|
|
**Interrupts** |
**UART Interrupts** |
|
UART0 features two independent interrupt for signaling certain RX and TX conditions. The behavior of these interrupts differ |
based on the configured FIFO size. If the according FIFO size is greater than 1, the _UART_CTRL_RX_IRQ_ and _UART_CTRL_TX_IRQ_ |
`CTRL` flags allow a more fine-grained IRQ configuration. |
UART0 features two independent interrupt for signaling certain RX and TX conditions. The behavior of these conditions differs |
based on the configured FIFO sizes. If the according FIFO size is greater than 1, the _UART_CTRL_RX_IRQ_ and _UART_CTRL_TX_IRQ_ |
`CTRL` flags allow a more fine-grained IRQ configuration. An interrupt can only become pending if the according interrupt |
condition is fulfilled and the UART is enabled at all. |
|
* If _UART0_RX_FIFO_ is exactly 1, the RX interrupt becomes pending as soon as there is data available in the RX FIFO |
(-> _UART_CTRL_RX_EMPTY_ clears). This flag is hardwired to `0` if _UART0_RX_FIFO_ = 1. |
* If _UART0_TX_FIFO_ is exactly 1, the TX interrupt becomes pending as soon as there is a free entry left in the TX FIFO |
(-> _UART_CTRL_TX_FULL_ clears). This flag is hardwired to `0` if _UART0_RX_FIFO_ = 1. |
* If _UART0_RX_FIFO_ is exactly 1, the RX interrupt goes pending when data _becomes_ available in the RX FIFO |
(-> _UART_CTRL_RX_EMPTY_ clears). _UART_CTRL_RX_IRQ_ is hardwired to `0` in this case. |
* If _UART0_TX_FIFO_ is exactly 1, the TX interrupt goes pending when at least one entry in the TX FIFO _becomes_ free |
(-> _UART_CTRL_TX_FULL_ clears). _UART_CTRL_TX_IRQ_ is hardwired to `0` in this case. |
|
* If _UART0_RX_FIFO_ is greater than 1: If _UART_CTRL_RX_IRQ_ is `0` the RX interrupt becomes pending as soon as there is data |
available in the RX FIFO (-> _UART_CTRL_RX_EMPTY_ clears). If _UART_CTRL_RX_IRQ_ is `1` the RX interrupt becomes pending as soon as |
the RX FIFO is at least half-full (-> _UART_CTRL_RX_HALF_ sets). |
* If _UART0_TX_FIFO_ is greater than 1: If _UART_CTRL_TX_IRQ_ is `0` the TX interrupt becomes pending as soon as there is a free |
entry left in the TX FIFO (-> _UART_CTRL_TX_FULL_ clears). If _UART_CTRL_TX_IRQ_ is `1` the TX interrupt becomes pending as soon as |
the RX FIFO is less than half-full (-> _UART_CTRL_TX_HALF_ clears). |
* If _UART0_RX_FIFO_ is greater than 1: If _UART_CTRL_RX_IRQ_ is `0` the RX interrupt goes pending when data _becomes_ |
available in the RX FIFO (-> _UART_CTRL_RX_EMPTY_ clears). If _UART_CTRL_RX_IRQ_ is `1` the RX interrupt becomes pending |
the RX FIFO _becomes_ at least half-full (-> _UART_CTRL_RX_HALF_ sets). |
* If _UART0_TX_FIFO_ is greater than 1: If _UART_CTRL_TX_IRQ_ is `0` the TX interrupt goes pending when at least one entry |
in the TX FIFO _becomes_ free (-> _UART_CTRL_TX_FULL_ clears). If _UART_CTRL_TX_IRQ_ is `1` the TX interrupt goes pending |
when the RX FIFO _becomes_ less than half-full (-> _UART_CTRL_TX_HALF_ clears). |
|
An interrupt can only become pending if the according interrupt condition is fulfilled and the UART is enabled at all. |
A pending interrupt is removed by resolving the interrupt-triggering conditions (for example by reading data from the |
more-than-half-full RX FIFO). |
A **pending RX interrupt** request is cleared by any of the following operations: |
* read access to `NEORV32_UART0.DATA` (for example to read incoming data) |
* write access to `NEORV32_UART0.CTRL` |
* disabling the UART module |
|
A **pending TX interrupt** request is cleared by any of the following operations: |
* write access to `NEORV32_UART0.DATA` (for example to send more data) |
* write access to `NEORV32_UART0.CTRL` |
* disabling the UART module |
|
[TIP] |
A dummy write to to the control register (i.e. `NEORV32_UART0.DATA = NEORV32_UART0.DATA`) |
can be executed to acknowledge any interrupt. |
|
|
**Simulation Mode** |
|
The default UART0 operation will transmit any data written to the `DATA` register via the serial TX line at |
/software.adoc
588,9 → 588,18
|
[source] |
---- |
<RTE> Illegal instruction @0x000002d6, MTVAL=0x00001537 </RTE> |
<RTE> Illegal instruction @ PC=0x000002d6, MTVAL=0x00001537 </RTE> |
---- |
|
For bus access faults the RTE also outputs the error code from the <<_internal_bus_monitor_buskeeper>> |
to show the cause of the access fault. Two example are shown below. |
|
[source] |
---- |
<RTE> Load access fault [TIMEOUT_ERR] @ PC=0x00000150, MTVAL=0xFFFFFF70 </RTE> |
<RTE> Store access fault [DEVICE_ERR] @ PC=0x00000162, MTVAL=0xF0000000 </RTE> |
---- |
|
To install the **actual application's trap handlers** the NEORV32 RTE provides functions for installing and |
un-installing trap handler for each implemented exception/interrupt source. |
|