Skip to content

Commit

Permalink
Merge pull request #176 from stnolting/firq_level_triggered
Browse files Browse the repository at this point in the history
[rtl/core] make FIRQs level-triggered
  • Loading branch information
stnolting committed Oct 9, 2021
2 parents 3dc43e8 + 8c92b2f commit f2a261c
Show file tree
Hide file tree
Showing 26 changed files with 250 additions and 243 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ defined by the `hw_version_c` constant in the main VHDL package file [`rtl/core/

| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 06.10.2021 | 1.6.1.6 | :bug: fixed bugs in signal assignments and processor configuration of `setups/radiant/UPduino_v3` setup; minor CPU HPM counter fix (architecture condition for "multi-cycle ALU wait cycles" HPM event) |
| 09.10.2021 | 1.6.1.7 | :warning: reworked _fast interrupt requests_ (FIRQ) CPU interrupt system: fast interrupt requests are now also high-level-triggered (like the RISC-V standard interrupts) and stay asserted until explicitly acknowledged by software ([PR #176](https://github.com/stnolting/neorv32/pull/176)) |
| 06.10.2021 | 1.6.1.6 | :bug: fixed bugs in signal assignments and processor configuration of `setups/radiant/UPduino_v3` setup; minor CPU HPM counter fix (architecture condition for "multi-cycle ALU wait cycle" HPM event) |
| 05.10.2021 | 1.6.1.5 | :sparkles: :lock: the CPU now ensures that _all_ illegal instructions _do not commit_ any potential architecture state changes (like writing registers or triggering memory accesses); CPU logic optimization (smaller footprint) |
| 04.10.2021 | 1.6.1.4 | moved CPU's comparator logic from register file unit to ALU unit (to allow easier replacement of register file design unit by technology-optimized one) |
| 03.10.2021 | 1.6.1.3 | :bug: fixed UART signal connection in `rtl/system_integration` wrappers |
Expand Down
16 changes: 8 additions & 8 deletions docs/datasheet/cpu.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ image::riscv_logo.png[width=350,align=center]
** `DB` - debug mode
* Compatible to the RISC-V user specifications and a subset of the RISC-V privileged architecture specifications – passes the official RISC-V Architecture Tests (v2+)
* Official RISC-V open-source architecture ID
* Standard RISC-V interrupts (_external_, _timer_, _software_) plus 16 _fast_ interrupts and 1 non-maskable interrupt
* Standard RISC-V interrupts (_external_, _timer_, _software_) plus 16 _fast_ interrupts
* Supports most of the traps from the RISC-V specifications (including bus access exceptions) and traps on all unimplemented/illegal/malformed instructions
* Optional physical memory configuration (PMP), compatible to the RISC-V specifications
* Optional hardware performance monitors (HPM) for application benchmarking
Expand Down Expand Up @@ -223,6 +223,8 @@ can be found in section <<_instruction_sets_and_extensions>>.
[IMPORTANT]
The `misa`, `mip` and `mtval` CSRs in the NEORV32 are _read-only_.
Any write access to it (in machine mode) to them are ignored and will _not_ cause any exceptions or side-effects.
Pending interrupt can only be cleared by acknowledging the interrupt-causing device. However, pending interrupts
can still be ignored by clearing the according `mie` register bits.

.Physical memory protection
[IMPORTANT]
Expand Down Expand Up @@ -376,7 +378,7 @@ After the execution of the `sc` instruction, the lock is automatically removed.

The lock is broken if at least one of the following conditions occur:
. executing any data memory access instruction other than `lr.w`
. rising _any_ exception (for example an interrupt)
. raising _any_ t (for example an interrupt or a memory access exception)

[NOTE]
The atomic instructions have special requirements for memory system / bus interconnect. More
Expand Down Expand Up @@ -809,10 +811,10 @@ while all remaining exceptions are ignored. If several _interrupts_ trigger at o
is serviced first while the remaining ones stay _pending_. After completing the interrupt handler the interrupt with
the second highest priority will get serviced and so on until no further interrupt are pending.

.RISC-V interrupts
.Interrupt Signal Requirements
[IMPORTANT]
All RISC-V defined machine level interrupts request signals are high-active. A request has to stay at high-level until
it is acknowledged by the CPU (for example by writing to a specific memory-mapped register).
All interrupts request signals (including FIRQs) are **high-active**. A request has to stay at high-level (=asserted)
until it is explicitly acknowledged by the CPU software (for example by writing to a specific memory-mapped register).

.Instruction Atomicity
[NOTE]
Expand All @@ -835,10 +837,8 @@ memory protection fault do not trigger a bus write-operation at all.

As a custom extension, the NEORV32 CPU features 16 fast interrupt request (FIRQ) lines via the `firq_i` CPU top
entity signals. These interrupts have custom configuration and status flags in the `mie` and `mip` CSRs and also
provide custom trap codes in `mcause`. These FIRQs are reserved for processor-internal usage only.
provide custom trap codes in `mcause`. These FIRQs are reserved for NEORV32 processor-internal usage only.

[NOTE]
The fast interrupt request lines trigger on a **rising-edge**.


<<<
Expand Down
5 changes: 3 additions & 2 deletions docs/datasheet/cpu_csr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,9 @@ The NEORV32 `mtval` CSR is read-only. However, a write access will _NOT_ raise a
|======
| 0x344 | **Machine interrupt Pending** | `mip`
3+| Reset value: _0x00000000_
3+| The `mip` CSR is _partly_ compatible to the RISC-V specifications and also provides custom extensions. It shows currently pending interrupts. Since this register is
read-only, pending interrupts of processor-internal modules can only be cleared by disabling and re-enabling the according `mie` CSR bit.
3+| The `mip` CSR is compatible to the RISC-V specifications and also provides custom extensions. It shows currently _pending_ interrupts.
Since this register is read-only, pending interrupts of processor-internal modules can only be cleared by acknowledging the interrupt-causing
device. However, pending interrupts can be ignored by clearing the accordind <<_mie>> register bits.
The following CSR bits are implemented (all remaining bits are always zero and are read-only).
|======

Expand Down
6 changes: 6 additions & 0 deletions docs/datasheet/on_chip_debugger.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ The CPU debug-mode is entered when one of the following events appear:
From a hardware point of view, these "entry conditions" are special synchronous (`ebreak` instruction) or asynchronous
(single-stepping "interrupt"; halt request "interrupt") traps, that are handled invisibly by the control logic.

.WFI instruction
[WARNING]
The wait-for-interrupt instruction `wfi` puts the CPU into sleep mode. The CPU will resume normale operation
when at least one interrupt source becomes pending (= at least one bit in `mip` CSR is set).
However, the CPU will _also resume_ from sleep mode if there is a halt request from the debug module (DM).

Whenever the CPU **enters debug-mode** it performs the following operations:

* move `pc` to `dpcs`
Expand Down
15 changes: 9 additions & 6 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -964,8 +964,9 @@ specifications. However, bare-metal system can also repurpose these interrupts.

.Trigger type
[IMPORTANT]
These IRQs trigger on **high-level** and must _stay asserted_ until explicitly acknowledged by the CPU (for example
by writing to a specific memory-mapped register).
The fast interrupt request channel trigger on **high-level** and have to stay asserted until explicitly acknowledged
by the software (for example by writing to a specifc memory-mapped register). Hence, pending interrupts remain pending
as long as the interrupt-causing device's state fulfills it's interrupt condition(s).


:sectnums:
Expand All @@ -986,14 +987,15 @@ fast interrupt request so a software handler is required to differentiate / prio
[IMPORTANT]
The trigger for these interrupt can be defined via generics. See section
<<_external_interrupt_controller_xirq>> for more information. Depending on the trigger type, users can
implement custom acknowledge mechanisms.
implement custom acknowledge mechanisms. All _external interrupts_ are mapped to a single processor-internal
_fast interrupt request_ (see below).


:sectnums:
==== NEORV32-Specific Fast Interrupt Requests

As part of the custom/NEORV32-specific CPU extensions, the CPU features 16 fast interrupt request signals
(`FIRQ0``FIRQ15`). These are used for _processor-internal_ modules only (for example for the communication
(`FIRQ0``FIRQ15`). These are reserved for _processor-internal_ modules only (for example for the communication
interfaces to signal "available incoming data" or "ready to send new data").

The mapping of the 16 FIRQ channels is shown in the following table (the channel number also corresponds to
Expand Down Expand Up @@ -1021,8 +1023,9 @@ the according FIRQ priority; 0 = highest, 15 = lowest):

.Trigger type
[IMPORTANT]
The fast interrupt request channel trigger on a single **rising-edge** and do not require any kind of explicit
acknowledgment at all.
The fast interrupt request channel trigger on **high-level** and have to stay asserted until explicitly acknowledged
by the software (for example by writing to a specifc memory-mapped register). Hence, pending interrupts remain pending
as long as the interrupt-causing device's state fulfills it's interrupt condition(s).



Expand Down
5 changes: 3 additions & 2 deletions docs/datasheet/soc_cfs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ uint32_t temp = NEORV32_CFS.REG[20]; // read from CFS register 20

**CFS Interrupt**

The CFS provides a single one-shot interrupt request signal mapped to the CPU's fast interrupt channel 1.
See section <<_processor_interrupts>> for more information.
The CFS provides a single high-level-triggered interrupt request signal mapped to the CPU's fast interrupt channel 1.
Once set, the interrupt has to stay asserted until explicitly acknowledged by the software (for example by
writing to a specific CFS register). See section <<_processor_interrupts>> for more information.

**CFS Configuration Generic**

Expand Down
1 change: 1 addition & 0 deletions docs/datasheet/soc_mtime.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The 64-bit system time can be accessed via the `TIME_LO` and `TIME_HI` memory-ma
the CPU's `time[h]` CSRs (read-only). A 64-bit time compare register – accessible via memory-mapped `TIMECMP_LO` and `TIMECMP_HI`
registers – is used to configure an interrupt to the CPU. The interrupt is triggered
whenever `TIME` (high & low part) >= `TIMECMP` (high & low part) and is directly forwarded to the CPU's `MTI` interrupt.
The interrupt remain active (=pending) until `TIME` < `TIMECMP` (either by modifying `TIME` or `TIMECMP`).

.MTIME register map (`struct NEORV32_MTIME`)
[cols="<3,<3,^1,^1,<6"]
Expand Down
10 changes: 7 additions & 3 deletions docs/datasheet/soc_neoled.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,13 @@ data word being written to the TX buffer making busy wait concepts obsolete and

**Interrupt**

The NEOLED modules features a single interrupt that is triggered whenever the TX FIFO's fill level
falls below _half-full_ level. 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 NEOLED modules features a single interrupt that becomes pending) whenever the TX FIFO's fill level
is below _half-full_ level. 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.
If the FIFO is configured to contain only a single entry (__IO_NEOLED_TX_FIFO_ = 1) the interrupt
will become pending if the FIFO is empty. In any case the NEOLED module has to be enabled
to allow generation of interrupts.
This highly relaxes time constraints for sending a continuous data stream to the LEDs
(as an idle time beyond 50μs will trigger the LED's a RESET command).
Expand Down
22 changes: 13 additions & 9 deletions docs/datasheet/soc_slink.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,25 @@ to the actual link access, which will reduce performance for high-bandwidth data

**Interrupts**

The stream interface provides two interrupts that are _globally_ driven by the RX and TX link's
The stream interface provides two independent interrupts that are _globally_ driven by the RX and TX link's
FIFO fill level status. The behavior of these interrupts differs if the FIFO depth is exactly 1 (minimal)
or if it is greater than 1.

When _SLINK_*X_FIFO_ is 1 a TX interrupt will fire if **any** TX link _was full_ and _becomes empty_ again.
Accordingly, if the FIFO of **any** RX link _was empty_ and a _new data word_ appears in it, the RX interrupt fires.
[NOTE]
If the according interrupt condition is fulfilled, the corresposnding IRQ will become _pending_ until
the causing interrupt conditions is resolved (for example by reading the according RX FIFO).

When _SLINK_*X_FIFO_ is greater than 1 the TX interrupt will fire if _any_ TX link's FIFO _falls below_ half-full fill level.
Accordingly, the RX interrupt will fire if _any_ RX link's FIFO _exceeds_ half-full fill level.
* When _SLINK_TX_FIFO_ is 1 a TX interrupt will become pending if **any** TX link is _idle_ ("ready to send new data").
* When _SLINK_TX_FIFO_ is greater than 1 the TX interrupt will become pending if **any** TX link's FIFO
is not at least _half_full_ ("still more room for new data to be send").
The interrupt service handler has to evaluate the SLINK status register is order to detect which link(s) has caused the
interrupt. No further interrupt can fire until the CPU acknowledges the last interrupt by _reading the SLINK status register_.
However, further IRQ conditions are buffered and will trigger another interrupt after the current one has been acknowledged.
* When _SLINK_RX_FIFO_ is 1 a RX interrupt will become pending if **any** RX link is has new data that has not
been fetched by the CPU yet ("new incoming data available").
* When _SLINK_RX_FIFO_ is greater than 1 the RX interrupt will become pending if the FIFO of **any** RX
link is at least _half-full_ ("incoming data needs to be read to avoid FIFO overflow").
Note that these interrupts can only fire if the SLINK module is actually enabled by setting the
The interrupt service handler has to evaluate the SLINK status register is order to detect which link(s) has caused the
interrupt. Note that these interrupts can only fire if the SLINK module is actually enabled by setting the
_SLINK_CTRL_EN_ bit in the unit's control register.

**Stream Link Interface & Protocol**
Expand Down
11 changes: 9 additions & 2 deletions docs/datasheet/soc_spi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ signal.
The SPI unit is enabled via the _SPI_CTRL_EN_ bit in the `CTRL` control register. The idle clock polarity is configured via the _SPI_CTRL_CPHA_
bit and can be low (`0`) or high (`1`) during idle. The data quantity to be transferred within a
single transmission is defined via the _SPI_CTRL_SIZEx bits_. The unit supports 8-bit (`00`), 16-bit (`01`), 24-
bit (`10`) and 32-bit (`11`) transfers. Whenever a transfer is completed, the "transmission done interrupt" is triggered.
A transmission is still in progress as long as the _SPI_CTRL_BUSY_ flag is set.
bit (`10`) and 32-bit (`11`) transfers.

The SPI controller features 8 dedicated chip-select lines. These lines are controlled via the control register's _SPI_CTRL_CSx_ bits. When
a specifc _SPI_CTRL_CSx_ bit is **set**, the according chip select line `spi_csn_o(x)` goes **low** (low-active chip select lines).
Expand All @@ -50,6 +49,14 @@ A transmission is started when writing data to the `DATA` register. The data mus
the SPI transceiver is configured for less than 32-bit transfers data quantity, the transmit data must be placed
into the lowest 8/16/24 bit of `DATA`. Vice versa, the received data is also always LSB-aligned.


**Interrupt**

The SPI module provides a single interrupt to singal _idle state_ (= read 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 device.


.SPI register map (`struct NEORV32_SPI`)
[cols="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
Expand Down
8 changes: 8 additions & 0 deletions docs/datasheet/soc_twi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ Based on the _TWI_CTRL_PRSCx_ configuration, the actual TWI clock frequency f~SC

_**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler`)


**Interrupt**

The TWI module provides a single interrupt to singal _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.


.TWI register map (`struct NEORV32_TWI`)
[cols="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
Expand Down
9 changes: 7 additions & 2 deletions docs/datasheet/soc_uart.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,13 @@ between devices.

**Interrupts**

The UART features two interrupts: the "TX done interrupt" is triggered when a transmit operation (sending) has finished. The "RX
done interrupt" is triggered when a data byte has been received. If the UART0 is not implemented, the UART0 interrupts are permanently tied to zero.
The UART features two interrupts:
* The "TX done interrupt" is active as long as the transmitter unit is idle (=ready for new data to be send). The interrupt
request is cleared by triggering a new transmission or by disabling the UART.
*The "RX done interrupt" is active when a data byte has been received and has not been fetched by the CPU yet. The interrupt
request is cleared by fetching the available data or by disabling the UART.
If the UART0 is not implemented, the UART0 interrupts are permanently tied to zero.
[NOTE]
The UART's RX interrupt is always triggered when a new data word has arrived – regardless of the
Expand Down
7 changes: 5 additions & 2 deletions docs/datasheet/soc_wdt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ _WDT_CTRL_CLK_SELx_ prescaler:

Whenever the internal timer overflows the watchdog executes one of two possible actions: Either a hard
processor reset is triggered or an interrupt is requested at CPU's fast interrupt channel #0. The
WDT_CTRL_MODE bit defines the action to be taken on an overflow: When cleared, the Watchdog will trigger an
IRQ, when set the WDT will cause a system reset. The configured actions can also be triggered manually at
WDT_CTRL_MODE bit definess the action to be taken on an overflow: When cleared, the Watchdog will assert an
IRQ, when set the WDT will cause a system reset. The configured action can also be triggered manually at
any time by setting the _WDT_CTRL_FORCE_ bit. The watchdog is reset by setting the _WDT_CTRL_RESET_ bit.

A watchdog interrupt can only occur if the watchdog is enabled and interrupt mode is enabled.
A pending interrupt is cleared by either disabling the watchdog or by resetting the watchdog.

The cause of the last action of the watchdog can be determined via the _WDT_CTRL_RCAUSE_ flag. If this flag is
zero, the processor has been reset via the external reset signal. If this flag is set the last system reset was
initiated by the watchdog.
Expand Down
6 changes: 3 additions & 3 deletions docs/datasheet/soc_xirq.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ bit. As soon as there is a least one pending interrupt in the buffer, an interru
[NOTE]
A disabled interrupt channel can still be pending if it has been triggered before clearing the according `IER` bit.

The CPU can determine firing interrupt request either by checking the bits in the `IPR` register, which show all
The CPU can determine active external interrupt request either by checking the bits in the `IPR` register, which show all
pending interrupt channels, or by reading the interrupt source register `SCR`.
This register provides a 5-bit wide ID (0..31) that shows the interrupt request with _highest priority_.
Interrupt channel `xirq_i(0)` has highest priority and `xirq_i(_XIRQ_NUM_CH_-1)` has lowest priority.
This priority assignment is fixed and cannot be altered by software.
The CPU can use the ID from `SCR` to service IRQ according to their priority. To acknowledge the according
interrupt the CPU can write `1 << SCR` to `IPR`.

In order to acknowledge the interrupt from the external interrupt controller, the CPU has to write _any_
value to interrupt source register `SRC`.
In order to clear a pending FIRQ interrupt from the external interrupt controller, the CPU has to write _any_
value to the interrupt source register `SRC`.

[NOTE]
An interrupt handler should clear the interrupt pending bit that caused the interrupt first before
Expand Down
Loading

0 comments on commit f2a261c

Please sign in to comment.