Skip to content

Commit

Permalink
Merge pull request #236 from stnolting/rework_firq_v3
Browse files Browse the repository at this point in the history
⚠️ Rework FIRQ System (re-rework): use MIP to clear/ack IRQs
  • Loading branch information
stnolting authored Dec 9, 2021
2 parents f7bc3bd + 26a535f commit 6e9060b
Show file tree
Hide file tree
Showing 32 changed files with 283 additions and 454 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ defined by the `hw_version_c` constant in the main VHDL package file [`rtl/core/

| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 08.12.2021 | 1.6.4.6 | :warning: reworked **Fast Interrupt Requests (FIRQ)** system, see [PR #236](https://github.com/stnolting/neorv32/pull/236) |
| 03.12.2021 | 1.6.4.5 | added _SYSINFO_SOC_IS_SIM_ flag to SYSINFO to check if processor is being simulated (not guaranteed, depends on the toolchain's 'pragma' support), see [PR #231](https://github.com/stnolting/neorv32/pull/231) |
| 03.12.2021 | 1.6.4.4 | :bug: fixed bug in **Wishbone** bus interface: timeout configurations (via `MEM_EXT_TIMEOUT` generic) that are a power of two (e.g. 256) caused _immediate_ timeouts; timeout counter was one bit short; same problem for processor-internal bus monitor (BUSKEEPER); see [PR #230](https://github.com/stnolting/neorv32/pull/230) |
| 02.12.2021 | 1.6.4.3 | :warning: removed legacy software compatibility wrappers (`sw/lib/include/neorv32_legacy.h` and `neorv32_uart_*` functions) |
Expand Down
14 changes: 10 additions & 4 deletions docs/datasheet/cpu.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ can be found in section <<_instruction_sets_and_extensions>>.
.Hardwired R/W CSRs
[IMPORTANT]
The `misa`, `mip` and `mtval` CSRs in the NEORV32 are _read-only_.
The `misa` 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.
Expand Down Expand Up @@ -561,7 +561,7 @@ The NEORV32-specific extensions are always enabled and are indicated by the set

The most important points of the NEORV32-specific extensions are:
* The CPU provides 16 _fast interrupt_ interrupts (`FIRQ)`, which are controlled via custom bits in the `mie`
and `mip` CSR. This extension is mapped to _reserved_ CSR bits, that are available for custom use (according to the
and `mip` CSR. This extension is mapped to CSR bits, that are available for custom use (according to the
RISC-V specs). Also, custom trap codes for `mcause` are implemented.
* All undefined/unimplemented/malformed/illegal instructions do raise an illegal instruction exception (see <<_full_virtualization>>).

Expand Down Expand Up @@ -836,11 +836,17 @@ 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.

.Interrupt Signal Requirements
.Interrupt Signal Requirements - Standard RISC-V Interrupts
[IMPORTANT]
All interrupts request signals (including FIRQs) are **high-active**. A request has to stay at high-level (=asserted)
All standard RISC-V interrupts request signals 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).

.Interrupt Signal Requirements - Fast Interrupt Requests
[IMPORTANT]
The NEORV32-specific FIRQ request lines are triggered by a rising edge. Each request is buffered in the CPU control
unit until the channel is either disabled (by clearing the according `mie` CSR bit) or the request is explicitly cleared (by setting
the according `mip` CSR bit).

.Instruction Atomicity
[NOTE]
All instructions execute as atomic operations - interrupts can only trigger between two instructions.
Expand Down
22 changes: 10 additions & 12 deletions docs/datasheet/cpu_csr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ CSRs with the following notes ...
| 0x340 | <<_mscratch>> | _CSR_MSCRATCH_ | r/w | Machine scratch register |
| 0x341 | <<_mepc>> | _CSR_MEPC_ | r/w | Machine exception program counter |
| 0x342 | <<_mcause>> | _CSR_MCAUSE_ | r/w | Machine trap cause | `X`
| 0x343 | <<_mtval>> | _CSR_MTVAL_ | r/- | Machine bad address or instruction | `XR`
| 0x344 | <<_mip>> | _CSR_MIP_ | r/- | Machine interrupt pending register | `XR`
| 0x343 | <<_mtval>> | _CSR_MTVAL_ | r/- | Machine bad address or instruction | `R`
| 0x344 | <<_mip>> | _CSR_MIP_ | r/w | Machine interrupt pending register | `X`
6+^| **<<_machine_physical_memory_protection_csrs>>**
| 0x3a0 .. 0x3af | <<_pmpcfg, `pmpcfg0`>> .. <<_pmpcfg, `pmpcfg15`>> | _CSR_PMPCFG0_ .. _CSR_PMPCFG15_ | r/w | Physical memory protection config. for region 0..63 | `C`
| 0x3b0 .. 0x3ef | <<_pmpaddr, `pmpaddr0`>> .. <<_pmpaddr, `pmpaddr63`>> | _CSR_PMPADDR0_ .. _CSR_PMPADDR63_ | r/w | Physical memory protection addr. register region 0..63 |
Expand Down Expand Up @@ -446,25 +446,23 @@ 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 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 according <<_mie>> register bits.
The following CSR bits are implemented (all remaining bits are always zero and are read-only).
The bits for the standard RISC-V interrupts are read-only. Hence, these interrupts cannot be cleared using the `mip` register and must
be cleared/acknowledged within the according interrupt-generating device.
The upper 16 bits represent the status of the CPU's fast interrupt request lines (FIRQ). Once triggered, these _have to be cleared_ again by setting
the according `mip` bit in the interrupt handler routine to clear the current interrupt request.
|======

.Machine interrupt pending register
[cols="^1,<3,^1,<5"]
[options="header",grid="rows"]
|=======================
| Bit | Name [C] | R/W | Function
| 31:16 | _CSR_MIP_FIRQ15P_ : _CSR_MIP_FIRQ0P_ | r/- | fast interrupt channel 15..0 pending
| 11 | _CSR_MIP_MEIP_ | r/- | machine _external_ interrupt pending
| 7 | _CSR_MIP_MTIP_ | r/- | machine _timer_ interrupt pending
| 3 | _CSR_MIP_MSIP_ | r/- | machine _software_ interrupt pending
| 31:16 | _CSR_MIP_FIRQ15P_ : _CSR_MIP_FIRQ0P_ | r/w | fast interrupt channel 15..0 pending; cleared request by writing 1
| 11 | _CSR_MIP_MEIP_ | r/- | machine _external_ interrupt pending; _cleared by user-defined mechanism_
| 7 | _CSR_MIP_MTIP_ | r/- | machine _timer_ interrupt pending; cleared by incrementing MTIME's time compare register
| 3 | _CSR_MIP_MSIP_ | r/- | machine _software_ interrupt pending; _cleared by user-defined mechanism_
|=======================

[IMPORTAN]
The NEORV32 `mip` CSR is read-only. However, a write access will _NOT_ raise an illegal instruction exception.


<<<
// ####################################################################################################################
Expand Down
10 changes: 4 additions & 6 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1057,9 +1057,8 @@ specifications. However, bare-metal system can also repurpose these interrupts.

.Trigger type
[IMPORTANT]
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 specific memory-mapped register). Hence, pending interrupts remain pending
as long as the interrupt-causing device's state fulfills it's interrupt condition(s).
The fast interrupt request channels become pending after being triggering by **a rising edge**. A pending FIRQ has to
be explicitly cleared by setting the according `mip` CSR bit.


:sectnums:
Expand Down Expand Up @@ -1117,9 +1116,8 @@ the according FIRQ priority; 0 = highest, 15 = lowest):

.Trigger type
[IMPORTANT]
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 specific memory-mapped register). Hence, pending interrupts remain pending
as long as the interrupt-causing device's state fulfills it's interrupt condition(s).
The fast interrupt request channels become pending after being triggering by **a rising edge**. A pending FIRQ has to
be explicitly cleared by setting the according `mip` CSR bit.



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

**CFS Interrupt**

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.
The CFS provides a single rising-edge-triggered interrupt request signal mapped to the CPU's fast interrupt channel 1.
Once triggered, the interrupt becomes pending (if enabled in the `mis` CSR) and has to be explicitly cleared again by setting
the according `mip` CSR bit. See section <<_processor_interrupts>> for more information.


**CFS Configuration Generic**
Expand Down
9 changes: 3 additions & 6 deletions docs/datasheet/soc_gptmr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,20 @@ writing zero to it.

**Timer Interrupt**

The timer interrupt gets pending when the timer is enabled and `COUNT` matches `THRES`. The interrupt
request is indicated via the _GPTMR_CTRL_ALARM_ control register bit. This bit as well as the actual
interrupt keeps pending until the bit is explicitly cleared by application software or if the
timer is disabled.
The timer interrupt is triggered when the timer is enabled and `COUNT` matches `THRES`. The interrupt
remains pending until explicitly cleared by writing the according `mip` CSR bit.


.GPTMR register map (`struct NEORV32_GPTMR`)
[cols="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.6+<| `0xffffff60` .6+<| `NEORV32_GPTMR.CTRL` <|`0` _GPTMR_CTRL_EN_ ^| r/w <| Timer enable flag
.5+<| `0xffffff60` .5+<| `NEORV32_GPTMR.CTRL` <|`0` _GPTMR_CTRL_EN_ ^| r/w <| Timer enable flag
<|`1` _GPTMR_CTRL_PRSC0_ ^| r/w .3+| 3-bit clock prescaler select
<|`2` _GPTMR_CTRL_PRSC1_ ^| r/w
<|`3` _GPTMR_CTRL_PRSC2_ ^| r/w
<|`4` _GPTMR_CTRL_MODE_ ^| r/w <| Counter mode: `0`=single-shot, `1`=continuous
<|`5` _GPTMR_CTRL_ALARM_ ^| r/c <| Pending interrupt/alarm, cleared by setting bit to zero
| `0xffffff64` | `NEORV32_GPTMR.THRES` |`31:0` | r/w | Threshold value register
| `0xffffff68` | `NEORV32_GPTMR.COUNT` |`31:0` | r/w | Counter register
|=======================
7 changes: 2 additions & 5 deletions docs/datasheet/soc_neoled.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,11 @@ If _NEOLED_CTRL_IRQ_CONF_ is cleared, an interrupt is generated whenever the TX
In this case software can write up to _IO_NEOLED_TX_FIFO_/2 new data words to `DATA` without checking the FIFO
status flags. If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO _becomes_ empty.

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
One the NEOLED interrupt has been triggered and became pending, it has to explicitly cleared again by setting the
according `mip` CSR bit.

[NOTE]
The _NEOLED_CTRL_IRQ_CONF_ is hardwired to one if _IO_NEOLED_TX_FIFO_ = 1 (-> IRQ if FIFO is empty).

If the FIFO is configured to contain only a single entry (_IO_NEOLED_TX_FIFO_ = 1) the interrupt
will become pending if the FIFO (which is just a single register providing simple _double-buffering_) is empty.

Expand Down
25 changes: 7 additions & 18 deletions docs/datasheet/soc_slink.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,15 @@ _SLINK_IRQ_RX_EN_ is set. Vice versa, the current FIFO fill-level of a specific
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 _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").
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ not empty ("RX data available").
* If a link's interrupt mode flag is `1` 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 _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").
* If a link's interrupt mode flag is `0` 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 `1` 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").
Once the SLINK's RX or TX interrupt has become pending, it has to be explicitly cleared again by setting the according
`mip` CSR bit.
[IMPORTANT]
The interrupt configuration register `NEORV32_SLINK.IRQ` should we written _before_ the SLINK
Expand All @@ -152,20 +155,6 @@ module is actually enabled.
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.
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
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"]
Expand Down
11 changes: 2 additions & 9 deletions docs/datasheet/soc_spi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,8 @@ Hence, the maximum SPI clock is f~main~ / 4.
**SPI Interrupt**

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.
module completes the current transfer operation, the interrupt is triggered and has to be explicitly cleared again
by setting the according `mip` CSR bit.


.SPI register map (`struct NEORV32_SPI`)
Expand Down
11 changes: 2 additions & 9 deletions docs/datasheet/soc_twi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,8 @@ _**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler`)

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.
the interrupt is triggered. Once triggered, the interrupt has to be explicitly cleared again by setting the according
`mip` CSR bit.


.TWI register map (`struct NEORV32_TWI`)
Expand Down
15 changes: 2 additions & 13 deletions docs/datasheet/soc_uart.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,8 @@ the RX FIFO _becomes_ at least half-full (-> _UART_CTRL_RX_HALF_ sets).
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).
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.
Once the RX or TX interrupt has become pending, it has to be explicitly cleared again by setting the
according `mip` CSR bit.


**Simulation Mode**
Expand Down
3 changes: 2 additions & 1 deletion docs/datasheet/soc_wdt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ IRQ, when set the WDT will cause a system reset. The configured action can also
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.
A triggered interrupt has to be cleared again by setting the according `mip` CSR bit.

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
Expand All @@ -55,6 +55,7 @@ activated by setting bit _WDT_CTRL_LOCK_. In the locked state any write access t
ignored (see table below, "accessible if locked"). Read accesses to the control register are not effected. The
lock can only be removed by a system reset (via external reset signal or via a watchdog reset action).


.WDT register map (`struct NEORV32_WDT`)
[cols="<2,<2,<4,^1,^2,<4"]
[options="header",grid="all"]
Expand Down
3 changes: 2 additions & 1 deletion docs/datasheet/soc_xirq.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ 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 clear a pending FIRQ interrupt from the external interrupt controller, the CPU has to write _any_
In order to clear a pending FIRQ interrupt from the external interrupt controller again, the according `mip` CSR bit has
to be set. Additionally, the XIRQ interrupt has to be acknowledged by writing _any_
value to the interrupt source register `SRC`.

[NOTE]
Expand Down
8 changes: 4 additions & 4 deletions rtl/core/neorv32_cfs.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ begin
-- Interrupt ------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- The CFS features a single interrupt signal, which is connected to the CPU's "fast interrupt" channel 1.
-- The interrupt is high-level-active. When set, the interrupt appears as "pending" in the CPU's mie register
-- ready to trigger execution of the according interrupt handler.
-- Once set, the irq_o signal **has to stay set** until explicitly acknowledged by the CPU
-- (for example by reading/writing from/to a specific CFS interface register address).
-- The interrupt is triggered by a one-shot rising edge. After triggering, the interrupt appears as "pending" in the CPU's mie register
-- ready to trigger execution of the according interrupt handler. The interrupt request signal should be triggered
-- whenever an interrupt condition is fulfilled. It is the task of the application to programmer to enable/clear the CFS interrupt
-- using the CPU's mie and mip registers when reuqired.

irq_o <= '0'; -- not used for this minimal example

Expand Down
Loading

0 comments on commit 6e9060b

Please sign in to comment.