diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75c9da4c9..0d9d85d3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
+| 27.05.2024 | 1.9.9.3 | removed `XIRQ_TRIGGER_*` generics; XIRQ trigger type is now _programmable_ by dedicated configuration registers | [#911](https://github.com/stnolting/neorv32/pull/911) |
| 21.05.2024 | 1.9.9.2 | :sparkles: add SLINK routing information ports (compatible to AXI-stream's `TID` and `TDEST` signals) | [#908](https://github.com/stnolting/neorv32/pull/908) |
| 04.05.2024 | 1.9.9.1 | :sparkles: add NEORV32 as Vivado IP block | [#894](https://github.com/stnolting/neorv32/pull/894) |
| 03.05.2024 | [**:rocket:1.9.9**](https://github.com/stnolting/neorv32/releases/tag/v1.9.9) | **New release** | |
diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc
index 5eaede336..f4d500c41 100644
--- a/docs/datasheet/soc.adoc
+++ b/docs/datasheet/soc.adoc
@@ -264,8 +264,6 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| `XIP_CACHE_BLOCK_SIZE` | natural | 256 | Number of bytes per XIP cache block. Has to be a power of two, min 4.
4+^| **<<_external_interrupt_controller_xirq>>**
| `XIRQ_NUM_CH` | natural | 0 | Number of channels of the external interrupt controller. Valid values are 0..32.
-| `XIRQ_TRIGGER_TYPE` | suv(31:0) | 0xFFFFFFFF | Trigger type (one bit per channel): `0` = level-triggered, '1' = edge triggered.
-| `XIRQ_TRIGGER_POLARITY` | suv(31:0) | 0xFFFFFFFF | Trigger polarity (one bit per channel): `0` = low-level/falling-edge, '1' = high-level/rising-edge.
4+^| **Peripheral/IO Modules**
| `IO_GPIO_NUM` | natural | 0 | Number of general purpose input/output pairs of the <<_general_purpose_input_and_output_port_gpio>>.
| `IO_MTIME_EN` | boolean | false | Implement the <<_machine_system_timer_mtime>>.
diff --git a/docs/datasheet/soc_xirq.adoc b/docs/datasheet/soc_xirq.adoc
index 0e62ee5bd..94bc65c3e 100644
--- a/docs/datasheet/soc_xirq.adoc
+++ b/docs/datasheet/soc_xirq.adoc
@@ -5,62 +5,75 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
-| Hardware source file(s): | neorv32_xirq.vhd |
-| Software driver file(s): | neorv32_xirq.c |
-| | neorv32_xirq.h |
-| Top entity port: | `xirq_i` | External interrupts input (32-bit)
-| Configuration generics: | `XIRQ_NUM_CH` | Number of external IRQ channels to implement (0..32)
-| | `XIRQ_TRIGGER_TYPE` | IRQ trigger type configuration
-| | `XIRQ_TRIGGER_POLARITY` | IRQ trigger polarity configuration
-| CPU interrupts: | fast IRQ channel 8 | XIRQ (see <<_processor_interrupts>>)
+| Hardware source file(s): | neorv32_xirq.vhd |
+| Software driver file(s): | neorv32_xirq.c |
+| | neorv32_xirq.h |
+| Top entity port: | `xirq_i` | External interrupts input (32-bit)
+| Configuration generic(s): | `XIRQ_NUM_CH` | Number of external IRQ channels to implement (0..32)
+| CPU interrupts: | fast IRQ channel 8 | XIRQ (see <<_processor_interrupts>>)
|=======================
**Overview**
-The external interrupt controller provides a simple mechanism to implement up to 32 processor-external interrupt
-request signals. The external IRQ requests are prioritized, queued and signaled to the CPU via a
-_single_ CPU fast interrupt request.
+The external interrupt controller provides a simple mechanism to implement up to 32 platform-level / processor-external
+interrupt request signals. The external IRQ requests are prioritized, queued and signaled to the CPU via a
+_single_ CPU fast interrupt request channel.
**Theory of Operation**
-The XIRQ provides up to 32 external interrupt channels configured via the `XIRQ_NUM_CH` generic. Each bit in the `xirq_i`
-input signal vector represents one interrupt channel. If less than 32 channels are configured, only the LSB-aligned channels
-are used while the remaining ones are left unconnected internally. The actual interrupt trigger type is configured before
-synthesis using the `XIRQ_TRIGGER_TYPE` and `XIRQ_TRIGGER_POLARITY` generics (see table below).
+The XIRQ provides up to 32 external interrupt channels configured via the `XIRQ_NUM_CH` generic. Each bit in the
+`xirq_i` input signal vector represents one interrupt channel. If less than 32 channels are configured, only the
+LSB-aligned channels are used while the remaining ones are left unconnected internally.
+
+The external interrupt controller features five interface registers:
+
+[start=1]
+. external interrupt channel enable (`EIE`)
+. external interrupt channel pending (`EIP`)
+. external interrupt source (`ESC`)
+. trigger type configuration (`TTYP`)
+. trigger polarity configuration (`TPOL`)
+
+[TIP]
+From a functional point of view, the `EIE`, `EIP` and `ESC` registers follow the behavior
+of the RISC-V <<_mie>>, <<_mip>> and <<_mcause>> CSRs.
+
+The actual interrupt trigger type can be configured individually for each channel using the `TTYP` and `TPOL`
+registers. `TTYP` defines the actual trigger type (level-triggered or edge-triggered), while `TPOL` defines
+the trigger's polarity (low-level/falling-edge or high-level_/rising-edge). The position of each bit in these
+registers corresponds the according XIRQ channel.
.XIRQ Trigger Configuration
[cols="^2,^2,<3"]
[options="header",grid="all"]
|=======================
-| `XIRQ_TRIGGER_TYPE(i)` | `XIRQ_TRIGGER_POLARITY(i)` | Resulting Trigger of `xirq_i(i)`
-| `0` | `0` | low-level
-| `0` | `1` | high-level
-| `1` | `0` | falling-edge
-| `1` | `1` | rising-edge
+| `TTYP(i)` | `TPOL(i)` | Resulting trigger of `xirq_i(i)`
+| `0` | `0` | low-level
+| `0` | `1` | high-level
+| `1` | `0` | falling-edge
+| `1` | `1` | rising-edge
|=======================
-The interrupt controller features three interface registers: external interrupt channel enable (`EIE`), external interrupt
-channel pending (`EIP`) and external interrupt source (`ESC`). From a functional point of view, the functionality of these
-registers follow the one of the RISC-V <<_mie>>, <<_mip>> and <<_mcause>> CSRs.
-
-If the configured trigger of an interrupt channel fires (e.g. a rising edge) the according interrupt channel becomes _pending_,
-which is indicated by the according channel bit being set in the `EIP` register. This pending interrupt can be cleared at any time
-by writing zero to the according `EIP` bit.
+When the configured trigger of an interrupt channel fires the according interrupt channel becomes _pending_
+which is indicated by the according channel bit being set in the `EIP` register. This pending interrupt can
+be manually cleared at any time by writing zero to the according `EIP` bit.
-A pending interrupt can only trigger a CPU interrupt if the according is enabled via the `EIE` register. Once triggered, disabled
-channels that were triggered remain pending until explicitly cleared. The channels are prioritized in a static order, i.e. channel 0
-(`xirq_i(0)`) has the highest priority and channel 31 (`xirq_i(31)`) has the lowest priority. If any pending interrupt channel is
-actually enabled, an interrupt request is sent to the CPU.
+A pending interrupt can only generate a CPU interrupt if the according channel is enabled by the `EIE`
+register. Once triggered, disabled channels that **were already triggered** remain pending until explicitly
+(= manually) cleared. The channels are prioritized in a static order, i.e. channel 0 (`xirq_i(0)`) has the
+highest priority and channel 31 (`xirq_i(31)`) has the lowest priority. If **any** pending interrupt channel is
+also enabled, an interrupt request is sent to the CPU.
-The CPU can determine the most prioritized external interrupt request either by checking the bits in the `IPR` register or by reading
-the interrupt source register `ESC`. This register provides a 5-bit wide ID (0..31) identifying the currently firing external interrupt.
-Writing _any_ value to this register will acknowledge the _current_ XIRQ interrupt (so the XIRQ controller can issue a new CPU interrupt).
+The CPU can determine the most prioritized external interrupt request either by checking the bits in the `EIP`
+register or by reading the interrupt source register `ESC`. This register provides a 5-bit wide ID (0..31)
+identifying the currently firing external interrupt source channel. Writing _any_ value to this register will
+acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller can issue a new CPU interrupt).
In order to acknowledge an XIRQ interrupt, the interrupt handler has to...
* clear the pending XIRQ channel by clearing the according `EIP` bit
-* writing _any_ value to `ESC` to acknowledge the XIRQ interrupt
+* writing _any_ value to `ESC` to acknowledge the XIRQ CPU interrupt
**Register Map**
@@ -70,8 +83,12 @@ In order to acknowledge an XIRQ interrupt, the interrupt handler has to...
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s) | R/W | Description
-| `0xfffff300` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned)
-| `0xfffff304` | `EIP` | `31:0` | r/w | External interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears the according pending interrupt
-| `0xfffff308` | `ESC` | `4:0` | r/w | Interrupt source ID (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current XIRQ interrupt
-| `0xfffff30c` | - | `31:0` | r/- | _reserved_, read as zero
+| `0xfffff300` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned)
+| `0xfffff304` | `EIP` | `31:0` | r/w | External interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears the according pending interrupt
+| `0xfffff308` | `ESC` | `4:0` | r/w | Interrupt source ID (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current XIRQ CPU interrupt
+| `0xfffff30c` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number
+| `0xfffff310` | `TPOL` | `31:0` | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); each bit corresponds to the according channel number
+| `0xfffff314` | - | `31:0` | r/- | _reserved_, read as zero
+| `0xfffff318` | - | `31:0` | r/- | _reserved_, read as zero
+| `0xfffff31c` | - | `31:0` | r/- | _reserved_, read as zero
|=======================
diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd
index 77c71daaf..14e32fe0b 100644
--- a/rtl/core/neorv32_package.vhd
+++ b/rtl/core/neorv32_package.vhd
@@ -29,7 +29,7 @@ package neorv32_package is
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
- constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090902"; -- hardware version
+ constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090903"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width
@@ -769,8 +769,6 @@ package neorv32_package is
XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256;
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH : natural range 0 to 32 := 0;
- XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff";
- XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) := x"ffffffff";
-- Processor peripherals --
IO_GPIO_NUM : natural range 0 to 64 := 0;
IO_MTIME_EN : boolean := false;
diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd
index 4c92cf303..7ff2839c4 100644
--- a/rtl/core/neorv32_top.vhd
+++ b/rtl/core/neorv32_top.vhd
@@ -99,8 +99,6 @@ entity neorv32_top is
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH : natural range 0 to 32 := 0; -- number of external IRQ channels (0..32)
- XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger type: 0=level, 1=edge
- XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
-- Processor peripherals --
IO_GPIO_NUM : natural range 0 to 64 := 0; -- number of GPIO input/output pairs (0..64)
@@ -1434,9 +1432,7 @@ begin
if io_xirq_en_c generate
neorv32_xirq_inst: entity neorv32.neorv32_xirq
generic map (
- XIRQ_NUM_CH => XIRQ_NUM_CH,
- XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE,
- XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY
+ XIRQ_NUM_CH => XIRQ_NUM_CH
)
port map (
clk_i => clk_i,
diff --git a/rtl/core/neorv32_xirq.vhd b/rtl/core/neorv32_xirq.vhd
index c134c0461..89238154e 100644
--- a/rtl/core/neorv32_xirq.vhd
+++ b/rtl/core/neorv32_xirq.vhd
@@ -3,10 +3,7 @@
-- -------------------------------------------------------------------------------- --
-- Simple interrupt controller for platform (processor-external) interrupts. Up to --
-- 32 channels are supported that get (optionally) prioritized into a single CPU --
--- interrupt. --
--- The actual trigger configuration has to be done BEFORE synthesis using the --
--- XIRQ_TRIGGER_TYPE and XIRQ_TRIGGER_POLARITY generics. These allow to configure --
--- channel-independent low-/high-level, falling-/rising-edge triggers. --
+-- interrupt. Trigger type is programmable per channel by configuration registers. --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
@@ -24,9 +21,7 @@ use neorv32.neorv32_package.all;
entity neorv32_xirq is
generic (
- XIRQ_NUM_CH : natural range 0 to 32; -- number of IRQ channels
- XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0); -- trigger type: 0=level, 1=edge
- XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
+ XIRQ_NUM_CH : natural range 0 to 32 -- number of IRQ channels
);
port (
clk_i : in std_ulogic; -- global clock line
@@ -40,10 +35,16 @@ end neorv32_xirq;
architecture neorv32_xirq_rtl of neorv32_xirq is
+ -- register addresses --
+ constant addr_enable_c : std_ulogic_vector(2 downto 0) := "000"; -- r/w: channel enable
+ constant addr_pending_c : std_ulogic_vector(2 downto 0) := "001"; -- r/w: pending IRQs
+ constant addr_source_c : std_ulogic_vector(2 downto 0) := "010"; -- r/w: source IRQ, ACK on write
+ constant addr_ttype_c : std_ulogic_vector(2 downto 0) := "011"; -- r/w: trigger type (level/edge)
+ constant addr_tpolarity_c : std_ulogic_vector(2 downto 0) := "100"; -- r/w: trigger polarity (high/low or rising/falling)
+
-- interface registers --
- signal irq_enable : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: channel enable
- signal nclr_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: pending IRQs
- signal irq_source : std_ulogic_vector(4 downto 0); -- r/w: source IRQ, ACK on write
+ signal irq_enable, nclr_pending, irq_type, irq_polarity : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
+ signal irq_source : std_ulogic_vector(4 downto 0);
-- interrupt trigger --
signal irq_sync, irq_sync2, irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
@@ -67,6 +68,8 @@ begin
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
nclr_pending <= (others => '0');
+ irq_type <= (others => '0');
+ irq_polarity <= (others => '0');
irq_enable <= (others => '0');
elsif rising_edge(clk_i) then
-- defaults --
@@ -74,21 +77,28 @@ begin
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
nclr_pending <= (others => '1');
-
-- bus access --
if (bus_req_i.stb = '1') then
if (bus_req_i.rw = '1') then -- write access
- if (bus_req_i.addr(3 downto 2) = "00") then -- channel-enable
+ if (bus_req_i.addr(4 downto 2) = addr_enable_c) then -- channel-enable
irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
- if (bus_req_i.addr(3 downto 2) = "01") then -- clear pending IRQs
+ if (bus_req_i.addr(4 downto 2) = addr_pending_c) then -- clear pending IRQs
nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
end if;
+ if (bus_req_i.addr(4 downto 2) = addr_ttype_c) then -- trigger type
+ irq_type <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
+ end if;
+ if (bus_req_i.addr(4 downto 2) = addr_tpolarity_c) then -- trigger polarity
+ irq_polarity <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
+ end if;
else -- read access
- case bus_req_i.addr(3 downto 2) is
- when "00" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
- when "01" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs
- when others => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source
+ case bus_req_i.addr(4 downto 2) is
+ when addr_enable_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
+ when addr_pending_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs
+ when addr_source_c => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source
+ when addr_ttype_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_type; -- trigger type
+ when others => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_polarity; -- trigger polarity
end case;
end if;
end if;
@@ -112,10 +122,10 @@ begin
-- trigger type select --
irq_trigger_gen:
for i in 0 to XIRQ_NUM_CH-1 generate
- irq_trigger: process(irq_sync, irq_sync2)
+ irq_trigger: process(irq_sync, irq_sync2, irq_type, irq_polarity)
variable sel_v : std_ulogic_vector(1 downto 0);
begin
- sel_v := XIRQ_TRIGGER_TYPE(i) & XIRQ_TRIGGER_POLARITY(i);
+ sel_v := irq_type(i) & irq_polarity(i);
case sel_v is
when "00" => irq_trig(i) <= not irq_sync(i); -- low-level
when "01" => irq_trig(i) <= irq_sync(i); -- high-level
@@ -165,7 +175,8 @@ begin
if (irq_fire = '1') then
irq_active <= '1';
end if;
- elsif (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(3 downto 2) = "10") then -- acknowledge on write access
+ elsif (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and
+ (bus_req_i.addr(4 downto 2) = addr_source_c) then -- acknowledge on write access
irq_active <= '0';
end if;
end if;
diff --git a/rtl/system_integration/neorv32_vivado_ip.tcl b/rtl/system_integration/neorv32_vivado_ip.tcl
index 05e32eec2..e18a8e6c6 100644
--- a/rtl/system_integration/neorv32_vivado_ip.tcl
+++ b/rtl/system_integration/neorv32_vivado_ip.tcl
@@ -244,10 +244,6 @@ ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparams
# Configuration GUI: Peripherals
# **************************************************************
set_property display_name {External interrupt controller (XIRQ)} [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]]
-set_property display_name {External interrupt controller (XIRQ trigger type} [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_TYPE" -component [ipx::current_core]]
-set_property tooltip {0=level, 1=edge} [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_TYPE" -component [ipx::current_core]]
-set_property display_name {External interrupt controller (XIRQ trigger polarity} [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_POLARITY" -component [ipx::current_core]]
-set_property tooltip {0=low-level/falling-edge, 1=high-level/rising-edge} [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_POLARITY" -component [ipx::current_core]]
set_property display_name {GPIO port pins} [ipgui::get_guiparamspec -name "IO_GPIO_NUM" -component [ipx::current_core]]
set_property display_name {Machine timer} [ipgui::get_guiparamspec -name "IO_MTIME_EN" -component [ipx::current_core]]
set_property display_name {Primary UART (UART0)} [ipgui::get_guiparamspec -name "IO_UART0_EN" -component [ipx::current_core]]
@@ -307,9 +303,7 @@ ipgui::move_param -component [ipx::current_core] -order 24 [ipgui::get_guiparams
ipgui::move_param -component [ipx::current_core] -order 25 [ipgui::get_guiparamspec -name "IO_ONEWIRE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 26 [ipgui::get_guiparamspec -name "IO_DMA_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 27 [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
-ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_TYPE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
-ipgui::move_param -component [ipx::current_core] -order 29 [ipgui::get_guiparamspec -name "XIRQ_TRIGGER_POLARITY" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
-ipgui::move_param -component [ipx::current_core] -order 30 [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
+ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
# **************************************************************
diff --git a/rtl/system_integration/neorv32_vivado_ip.vhd b/rtl/system_integration/neorv32_vivado_ip.vhd
index 92c739a6b..eec9f3626 100644
--- a/rtl/system_integration/neorv32_vivado_ip.vhd
+++ b/rtl/system_integration/neorv32_vivado_ip.vhd
@@ -87,8 +87,6 @@ entity neorv32_vivado_ip is
XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256;
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH : natural := 0;
- XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff";
- XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) := x"ffffffff";
-- Processor peripherals --
IO_GPIO_NUM : natural range 0 to 64 := 0;
IO_MTIME_EN : boolean := false;
@@ -332,8 +330,6 @@ begin
XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE,
-- External Interrupts Controller --
XIRQ_NUM_CH => XIRQ_NUM_CH,
- XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE,
- XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY,
-- Processor peripherals --
IO_GPIO_NUM => IO_GPIO_NUM,
IO_MTIME_EN => IO_MTIME_EN,
diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd
index 42cdf8486..2ae37c837 100644
--- a/sim/neorv32_tb.vhd
+++ b/sim/neorv32_tb.vhd
@@ -249,8 +249,6 @@ begin
XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32)
- XIRQ_TRIGGER_TYPE => (others => '1'), -- trigger type: 0=level, 1=edge
- XIRQ_TRIGGER_POLARITY => (others => '1'), -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
-- Processor peripherals --
IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64)
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
diff --git a/sim/simple/neorv32_tb.simple.vhd b/sim/simple/neorv32_tb.simple.vhd
index 6b3884cd1..9aa94d647 100644
--- a/sim/simple/neorv32_tb.simple.vhd
+++ b/sim/simple/neorv32_tb.simple.vhd
@@ -225,8 +225,6 @@ begin
XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32)
- XIRQ_TRIGGER_TYPE => (others => '1'), -- trigger type: 0=level, 1=edge
- XIRQ_TRIGGER_POLARITY => (others => '1'), -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
-- Processor peripherals --
IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64)
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
diff --git a/sw/example/demo_xirq/main.c b/sw/example/demo_xirq/main.c
index 75ecb9896..8a0fb0db1 100644
--- a/sw/example/demo_xirq/main.c
+++ b/sw/example/demo_xirq/main.c
@@ -3,7 +3,7 @@
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
-// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
+// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
// # #
// # Redistribution and use in source and binary forms, with or without modification, are #
// # permitted provided that the following conditions are met: #
@@ -125,6 +125,13 @@ int main() {
}
+ // configure per-channel trigger type
+ neorv32_xirq_setup_trigger(0, XIRQ_TRIGGER_EDGE_RISING); // rising-edge
+ neorv32_xirq_setup_trigger(1, XIRQ_TRIGGER_EDGE_RISING); // rising-edge
+ neorv32_xirq_setup_trigger(2, XIRQ_TRIGGER_EDGE_RISING); // rising-edge
+ neorv32_xirq_setup_trigger(3, XIRQ_TRIGGER_EDGE_RISING); // rising-edge
+
+
// install handler functions for XIRQ channel 0,1,2,3. note that these functions are "normal" functions!
// (details: these are "third-level" interrupt handlers)
// neorv32_xirq_install() also enables the specified XIRQ channel and clears any pending interrupts
diff --git a/sw/example/processor_check/main.c b/sw/example/processor_check/main.c
index 75ea5a485..b8ac19aae 100644
--- a/sw/example/processor_check/main.c
+++ b/sw/example/processor_check/main.c
@@ -1322,6 +1322,8 @@ int main() {
xirq_err_cnt += neorv32_xirq_setup(); // initialize XIRQ
xirq_err_cnt += neorv32_xirq_install(0, xirq_trap_handler0); // install XIRQ IRQ handler channel 0
xirq_err_cnt += neorv32_xirq_install(1, xirq_trap_handler1); // install XIRQ IRQ handler channel 1
+ neorv32_xirq_setup_trigger(0, XIRQ_TRIGGER_EDGE_RISING); // configure channel 0 as rising-edge trigger
+ neorv32_xirq_setup_trigger(1, XIRQ_TRIGGER_EDGE_RISING); // configure channel 1 as rising-edge trigger
// enable XIRQ FIRQ
neorv32_cpu_csr_write(CSR_MIE, 1 << XIRQ_FIRQ_ENABLE);
diff --git a/sw/lib/include/neorv32_xirq.h b/sw/lib/include/neorv32_xirq.h
index 01b01a768..41199eb26 100644
--- a/sw/lib/include/neorv32_xirq.h
+++ b/sw/lib/include/neorv32_xirq.h
@@ -22,10 +22,14 @@
/**@{*/
/** XIRQ module prototype */
typedef volatile struct __attribute__((packed,aligned(4))) {
- uint32_t EIE; /**< offset 0: external interrupt enable register */
- uint32_t EIP; /**< offset 4: external interrupt pending register */
- uint32_t ESC; /**< offset 8: external interrupt source register */
- const uint32_t reserved; /**< offset 12: reserved */
+ uint32_t EIE; /**< offset 0: external interrupt enable register */
+ uint32_t EIP; /**< offset 4: external interrupt pending register */
+ uint32_t ESC; /**< offset 8: external interrupt source register */
+ uint32_t TTYP; /**< offset 12: external interrupt source register */
+ uint32_t TPOL; /**< offset 16: external interrupt source register */
+ const uint32_t reserved0; /**< offset 20: reserved */
+ const uint32_t reserved1; /**< offset 24: reserved */
+ const uint32_t reserved2; /**< offset 28: reserved */
} neorv32_xirq_t;
/** XIRQ module hardware access (#neorv32_xirq_t) */
@@ -33,6 +37,17 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
/**@}*/
+/**********************************************************************//**
+ * XIRQ trigger configuration
+ **************************************************************************/
+/**@{*/
+#define XIRQ_TRIGGER_LEVEL_LOW (0b00) // low-level
+#define XIRQ_TRIGGER_LEVEL_HIGH (0b01) // high-level
+#define XIRQ_TRIGGER_EDGE_FALLING (0b10) // falling-edge
+#define XIRQ_TRIGGER_EDGE_RISING (0b11) // rising-edge
+/**@}*/
+
+
/**********************************************************************//**
* @name Prototypes
**************************************************************************/
@@ -42,6 +57,7 @@ int neorv32_xirq_setup(void);
void neorv32_xirq_global_enable(void);
void neorv32_xirq_global_disable(void);
int neorv32_xirq_get_num(void);
+void neorv32_xirq_setup_trigger(int channel, int config);
void neorv32_xirq_clear_pending(int channel);
void neorv32_xirq_channel_enable(int channel);
void neorv32_xirq_channel_disable(int channel);
diff --git a/sw/lib/source/neorv32_xirq.c b/sw/lib/source/neorv32_xirq.c
index d81505dba..51013b67f 100644
--- a/sw/lib/source/neorv32_xirq.c
+++ b/sw/lib/source/neorv32_xirq.c
@@ -146,6 +146,35 @@ int neorv32_xirq_get_num(void) {
}
+/**********************************************************************//**
+ * Configure a channel's trigger type.
+ *
+ * @param[in] channel XIRQ interrupt channel (0..31).
+ * @param[in] config Trigger type: 00 = low-level, 01 = high-level, 10 = falling-edge, 11 = rising-edge.
+ **************************************************************************/
+void neorv32_xirq_setup_trigger(int channel, int config) {
+
+ if (channel > 31) {
+ return;
+ }
+
+ uint32_t t = (((uint32_t)config) >> 1) & 1;
+ uint32_t p = (((uint32_t)config) >> 0) & 1;
+
+ uint32_t trig_typ = NEORV32_XIRQ->TTYP;
+ uint32_t trig_pol = NEORV32_XIRQ->TPOL;
+
+ trig_typ &= ~(1 << channel); // clear bit
+ trig_typ |= t << channel;
+
+ trig_pol &= ~(1 << channel); // clear bit
+ trig_pol |= p << channel;
+
+ NEORV32_XIRQ->TTYP = trig_typ;
+ NEORV32_XIRQ->TPOL = trig_pol;
+}
+
+
/**********************************************************************//**
* Clear pending interrupt.
*
diff --git a/sw/svd/neorv32.svd b/sw/svd/neorv32.svd
index 823ee49a9..b5489ceab 100644
--- a/sw/svd/neorv32.svd
+++ b/sw/svd/neorv32.svd
@@ -868,7 +868,7 @@
0
- 0x10
+ 0x14
registers
@@ -888,6 +888,16 @@
IRQ source register
0x08
+
+ TTYP
+ IRQ trigger type (level/edge)
+ 0x0c
+
+
+ TPOL
+ IRQ trigger polarity (high/low, rising/falling)
+ 0x10
+