diff --git a/CHANGELOG.md b/CHANGELOG.md index 8503a0799..211564d87 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 | |:----:|:-------:|:--------|:------:| +| 15.01.2025 | 1.10.9.7 | :sparkles: add GPIO interrupt(s); :warning: remove XIRQ controller, constrain GPIO input/output ports from 64-bit to 32-bit | [#1159](https://github.com/stnolting/neorv32/pull/1159) | | 13.01.2025 | 1.10.9.6 | add WDT and OCD rest outputs to top module | [#1152](https://github.com/stnolting/neorv32/pull/1152) | | 11.01.2025 | 1.10.9.5 | minor rtl cleanups; :bug: fix minor bug (multiple drivers on ICC nets; introduced in version 1.10.9.2) | [#1151](https://github.com/stnolting/neorv32/pull/1151) | | 11.01.2025 | 1.10.9.4 | :warning: RTE: use a single, global trap handler table that applies to _both_ cores | [#1150](https://github.com/stnolting/neorv32/pull/1150) | diff --git a/README.md b/README.md index 0648129cb..62e72611c 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ allows booting application code via UART, TWI or from external SPI flash [TWI](https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi) (I²C host), [TWD](https://stnolting.github.io/neorv32/#_two_wire_serial_device_controller_twd) (I²C device), [ONEWIRE/1-Wire](https://stnolting.github.io/neorv32/#_one_wire_serial_interface_controller_onewire)) -* general purpose IOs ([GPIO](https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio)) and +* interrupt-capable general purpose IOs ([GPIO](https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio)) and [PWM](https://stnolting.github.io/neorv32/#_pulse_width_modulation_controller_pwm) * smart LED interface ([NEOLED](https://stnolting.github.io/neorv32/#_smart_led_interface_neoled)) to directly control NeoPixel(TM) LEDs @@ -177,8 +177,6 @@ allows booting application code via UART, TWI or from external SPI flash [wrappers](https://github.com/stnolting/neorv32/blob/main/rtl/system_integration) for AXI4-Lite and Avalon-MM host interfaces * stream link interface with independent RX and TX channels - AXI4-Stream compatible ([SLINK](https://stnolting.github.io/neorv32/#_stream_link_interface_slink)) -* external interrupts controller with up to 32 channels -([XIRQ](https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq)) **Advanced** diff --git a/docs/datasheet/overview.adoc b/docs/datasheet/overview.adoc index c435c248a..0e3071ea6 100644 --- a/docs/datasheet/overview.adoc +++ b/docs/datasheet/overview.adoc @@ -231,8 +231,7 @@ rtl/core ├-neorv32_uart.vhd - Universal async. receiver/transmitter ├-neorv32_wdt.vhd - Watchdog timer ├-neorv32_xbus.vhd - External (Wishbone) bus interface gateways -├-neorv32_xip.vhd - Execute in place module -└-neorv32_xirq.vhd - External interrupt controller +└-neorv32_xip.vhd - Execute in place module ................................... .Replacing Modules for Customization or Optimization diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc index 72775d0fa..e4a6a4d98 100644 --- a/docs/datasheet/soc.adoc +++ b/docs/datasheet/soc.adoc @@ -31,14 +31,13 @@ image::neorv32_processor.png[align=center] * _optional_ 8-bit serial data device interface (<<_serial_data_interface_controller_spi,**SDI**>>) * _optional_ two-wire serial interface controller (<<_two_wire_serial_interface_controller_twi,**TWI**>>), compatible to the I²C standard * _optional_ two-wire serial device controller (<<_two_wire_serial_device_controller_twd,**TWD**>>), compatible to the I²C standard -* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 64xOut, 64xIn +* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 32 inputs (interrupt capable), 32 outputs * _optional_ 32-bit external bus interface, Wishbone b4 / AXI4-Lite compatible (<<_processor_external_bus_interface_xbus,**XBUS**>>) * _optional_ watchdog timer (<<_watchdog_timer_wdt,**WDT**>>) * _optional_ PWM controller with up to 16 individual channels (<<_pulse_width_modulation_controller_pwm,**PWM**>>) * _optional_ ring-oscillator-based true random number generator (<<_true_random_number_generator_trng,**TRNG**>>) * _optional_ custom functions subsystem for custom co-processor extensions (<<_custom_functions_subsystem_cfs,**CFS**>>) * _optional_ NeoPixel(TM)/WS2812-compatible smart LED interface (<<_smart_led_interface_neoled,**NEOLED**>>) -* _optional_ external interrupt controller with up to 32 channels and programmable interrupt triggers (<<_external_interrupt_controller_xirq,**XIRQ**>>) * _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>) * _optional_ execute in-place module (<<_execute_in_place_module_xip,**XIP**>>) * _optional_ 1-wire serial interface controller (<<_one_wire_serial_interface_controller_onewire,**ONEWIRE**>>), compatible to the 1-wire standard @@ -123,8 +122,8 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda | `xip_dat_i` | 1 | in | `'L'` | serial data input | `xip_dat_o` | 1 | out | - | serial data output 5+^| **<<_general_purpose_input_and_output_port_gpio>>** -| `gpio_o` | 64 | out | - | general purpose parallel output -| `gpio_i` | 64 | in | `'L'` | general purpose parallel input +| `gpio_o` | 32 | out | - | general purpose parallel output +| `gpio_i` | 32 | in | `'L'` | general purpose parallel input (interrupt-capable) 5+^| **<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>** | `uart0_txd_o` | 1 | out | - | serial transmitter | `uart0_rxd_i` | 1 | in | `'L'` | serial receiver @@ -167,8 +166,6 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda | `neoled_o` | 1 | out | - | asynchronous serial data output 5+^| **<<_core_local_interruptor_clint>>** | `mtime_time_o` | 64 | out | - | CLINT.MTIMER system time output -5+^| **<<_external_interrupt_controller_xirq>>** -| `xirq_i` | 32 | in | `'L'` | external interrupt requests 5+^| **RISC-V Machine-Mode <<_processor_interrupts>>** | `mtime_irq_i` | 1 | in | `'L'` | machine timer interrupt (RISC-V), high-level-active; for chip-internal usage only | `msw_irq_i` | 1 | in | `'L'` | machine software interrupt (RISC-V), high-level-active; for chip-internal usage only @@ -285,11 +282,9 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `XIP_CACHE_EN` | boolean | false | Implement XIP cache. | `XIP_CACHE_NUM_BLOCKS` | natural | 8 | Number of blocks in XIP cache. Has to be a power of two. | `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. 4+^| **Peripheral/IO Modules** | `IO_DISABLE_SYSINFO` | boolean | false | Disable <<_system_configuration_information_memory_sysinfo>> module; ⚠️ not recommended - for advanced users only! -| `IO_GPIO_NUM` | natural | 0 | Number of general purpose input/output pairs of the <<_general_purpose_input_and_output_port_gpio>>. +| `IO_GPIO_NUM` | natural | 0 | Number of general purpose input/output pairs of the <<_general_purpose_input_and_output_port_gpio>>, max 32. | `IO_CLINT_EN` | boolean | false | Implement the <<_core_local_interruptor_clint>>. | `IO_UART0_EN` | boolean | false | Implement the <<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>. | `IO_UART0_RX_FIFO` | natural | 1 | UART0 RX FIFO depth, has to be a power of two, minimum value is 1, max 32768. @@ -455,7 +450,7 @@ table (the channel number also corresponds to the according FIRQ priority: 0 = h | 5 | <<_secondary_universal_asynchronous_receiver_and_transmitter_uart1,UART1>> | UART1 TX FIFO level interrupt | 6 | <<_serial_peripheral_interface_controller_spi,SPI>> | SPI FIFO level interrupt | 7 | <<_two_wire_serial_interface_controller_twi,TWI>> | TWI FIFO level interrupt -| 8 | <<_external_interrupt_controller_xirq,XIRQ>> | External interrupt controller interrupt +| 8 | <<_general_purpose_input_and_output_port_gpio,GPIO>> | GPIO input pin(s) interrupt | 9 | <<_smart_led_interface_neoled,NEOLED>> | NEOLED TX FIFO level interrupt | 10 | <<_direct_memory_access_controller_dma,DMA>> | DMA transfer done interrupt | 11 | <<_serial_data_interface_controller_sdi,SDI>> | SDI FIFO level interrupt @@ -826,8 +821,6 @@ include::soc_cfs.adoc[] include::soc_neoled.adoc[] -include::soc_xirq.adoc[] - include::soc_gptmr.adoc[] include::soc_xip.adoc[] diff --git a/docs/datasheet/soc_gpio.adoc b/docs/datasheet/soc_gpio.adoc index 363b6cbb7..09e270222 100644 --- a/docs/datasheet/soc_gpio.adoc +++ b/docs/datasheet/soc_gpio.adoc @@ -8,29 +8,65 @@ | Hardware source files: | neorv32_gpio.vhd | | Software driver files: | neorv32_gpio.c | link:https://stnolting.github.io/neorv32/sw/neorv32__gpio_8c.html[Online software reference (Doxygen)] | | neorv32_gpio.h | link:https://stnolting.github.io/neorv32/sw/neorv32__gpio_8h.html[Online software reference (Doxygen)] -| Top entity ports: | `gpio_o` | 64-bit parallel output port -| | `gpio_i` | 64-bit parallel input port -| Configuration generics: | `IO_GPIO_NUM` | number of input/output pairs to implement (0..64) -| CPU interrupts: | none | +| Top entity ports: | `gpio_o` | 32-bit parallel output port +| | `gpio_i` | 32-bit parallel input port +| Configuration generics: | `IO_GPIO_NUM` | number of input/output pairs to implement (0..32) +| CPU interrupts: | fast IRQ channel 8 | GPIO (see <<_processor_interrupts>>) |======================= **Overview** -The general purpose parallel IO unit provides a simple parallel input and output port. These ports can be used +The general purpose IO unit provides simple uni-directional input and output port. These ports can be used chip-externally (for example to drive status LEDs, connect buttons, etc.) or chip-internally to provide control -signals for other IP modules. +signals for other IP modules. The input port features programmable pin-individual level or edge interrupts +capabilities. + +Data written to the `PORT_OUT` will appear on the processor's `gpio_o` port. Vice versa, the `PORT_IN` register +represents the current state of the processor's `gpio_i`. The actual number of input/output pairs is defined by the `IO_GPIO_NUM` generic. When set to zero, the GPIO module is excluded from synthesis and the output port `gpio_o` is tied to all-zero. If `IO_GPIO_NUM` is less than the -maximum value of 64, only the LSB-aligned bits in `gpio_o` and `gpio_i` are actually connected while the remaining -bits are tied to zero or are left unconnected, respectively. +maximum value of 32, only the LSB-aligned bits in `gpio_o` and `gpio_i` are actually connected while the remaining +bits are tied to zero or are left unconnected, respectively. This also applies to all memory-mapped interface +registers of the GPIO module (i.e. the according most-significant bits are hardwired to zero). + + +**Input Pin Interrupts** + +Each input pin (`gpio_i`) provides an individual programmable interrupt trigger. The actual interrupt trigger +type can be configured individually for each input pin using the `IRQ_TYPE` and `IRQ_POLARITY` registers. +`IRQ_TYPE` defines the actual trigger type (level-triggered or edge-triggered), while `IRQ_POLARITY` 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 `gpio_i` input pin. + +Each pin interrupt channel can be enabled or disabled individually using the `IRQ_ENABLE` register. Each bit +in this register corresponds to the according input pin. If the programmed trigger of a disabled input +(`IRQ_ENABLE(i) = 0`) fires, the interrupt request is entirely ignored. + +.GPIO Trigger Configuration for Pin _i_ +[cols="^2,^2,^2,<4"] +[options="header",grid="all"] +|======================= +| `IRQ_ENABLE(i)` | `IRQ_TYPE(i)` | `IRQ_POLARITY(i)` | Resulting trigger of `gpio_i(i)` +| `1` | `0` | `0` | low-level (`GPIO_TRIG_LEVEL_LOW`) +| `1` | `0` | `1` | high-level (`GPIO_TRIG_LEVEL_HIGH`) +| `1` | `1` | `0` | falling-edge (`GPIO_TRIG_EDGE_FALLING`) +| `1` | `1` | `1` | rising-edge (`GPIO_TRIG_EDGE_RISING`) +| `0` | `-` | `-` | interrupt disabled +|======================= + +If the configured trigger of an enabled input pin (`IRQ_ENABLE(i) = 1`) fires, the according interrupt request +is buffered internally in the `IRQ_PENDING` register. When this register contains a non-zero value (i.e. any +bit becomes set) an interrupt request is sent to the CPU via FIRQ channel 8 (see <<_processor_interrupts>>). + +The CPU can determine the interrupt-triggering pins by reading the `IRQ_PENDING` register. Each set bit in this +register indicates that the according input pin's interrupt trigger has fired. Then, the CPU can clear those +pending interrupt pin by setting all set bits to zero. -.Access Atomicity -[NOTE] -The GPIO modules uses two memory-mapped registers (each 32-bit) each for accessing the input and -output signals. Since the CPU can only process 32-bit "at once" updating the entire output cannot -be performed within a single clock cycle. +.GPIO Interrupts Demo Program +[TIP] +A demo program for the GPIO input interrupts can be found in `sw/example/demo_gpio`. **Register Map** @@ -39,9 +75,13 @@ be performed within a single clock cycle. [cols="<2,<2,^1,^1,<6"] [options="header",grid="rows"] |======================= -| Address | Name [C] | Bit(s) | R/W | Function -| `0xfffc0000` | `INPUT[0]` | 31:0 | r/- | parallel input port pins 31:0 -| `0xfffc0004` | `INPUT[1]` | 31:0 | r/- | parallel input port pins 63:32 -| `0xfffc0008` | `OUTPUT[0]` | 31:0 | r/w | parallel output port pins 31:0 -| `0xfffc000c` | `OUTPUT[1]` | 31:0 | r/w | parallel output port pins 63:32 +| Address | Name [C] | Bit(s) | R/W | Function +| `0xfffc0000` | `PORT_IN` | 31:0 | r/- | Parallel input port; `PORT_IN(i)` corresponds to `gpio_i(i)` +| `0xfffc0004` | `PORT_OUT` | 31:0 | r/w | Parallel output port; `PORT_OUT(i)` corresponds to `gpio_o(i)` +| `0xfffc0008` | - | 31:0 | r/- | _reserved_, read as zero +| `0xfffc000c` | - | 31:0 | r/- | _reserved_, read as zero +| `0xfffc0010` | `IRQ_TYPE` | 31:0 | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); `IRQ_TYPE(i)` corresponds to `gpio_i(i)` +| `0xfffc0014` | `IRQ_POLARITY` | 31:0 | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); `IRQ_POLARITY(i)` corresponds to `gpio_i(i)` +| `0xfffc0018` | `IRQ_ENABLE` | 31:0 | r/w | Per-pin interrupt enable; `IRQ_ENABLE(i)` corresponds to `gpio_i(i)` +| `0xfffc001c` | `IRQ_PENDING` | 31:0 | r/c | Per-pin interrupt pending, can be cleared by writing zero to the according bit(s); `IRQ_PENDING(i)` corresponds to `gpio_i(i)` |======================= diff --git a/docs/datasheet/soc_sysinfo.adoc b/docs/datasheet/soc_sysinfo.adoc index 9d14fb3d8..7d99a2e16 100644 --- a/docs/datasheet/soc_sysinfo.adoc +++ b/docs/datasheet/soc_sysinfo.adoc @@ -99,7 +99,7 @@ Bit fields in this register are set to all-zero if the according memory system i | `24` | `SYSINFO_SOC_IO_SDI` | set if SDI is implemented (via top's `IO_SDI_EN` generic) | `25` | `SYSINFO_SOC_IO_UART1` | set if secondary UART1 is implemented (via top's `IO_UART1_EN` generic) | `26` | `SYSINFO_SOC_IO_NEOLED` | set if NEOLED is implemented (via top's `IO_NEOLED_EN` generic) -| `27` | `SYSINFO_SOC_IO_XIRQ` | set if XIRQ is implemented (via top's `XIRQ_NUM_CH` generic) +| `27` | - |_reserved_, read as zero | `28` | `SYSINFO_SOC_IO_GPTMR` | set if GPTMR is implemented (via top's `IO_GPTMR_EN` generic) | `29` | `SYSINFO_SOC_IO_SLINK` | set if stream link interface is implemented (via top's `IO_SLINK_EN` generic) | `30` | `SYSINFO_SOC_IO_ONEWIRE` | set if ONEWIRE interface is implemented (via top's `IO_ONEWIRE_EN` generic) diff --git a/docs/datasheet/soc_xirq.adoc b/docs/datasheet/soc_xirq.adoc deleted file mode 100644 index 2c8b9bbad..000000000 --- a/docs/datasheet/soc_xirq.adoc +++ /dev/null @@ -1,82 +0,0 @@ -<<< -:sectnums: -==== External Interrupt Controller (XIRQ) - -[cols="<3,<3,<4"] -[grid="none"] -|======================= -| Hardware source files: | neorv32_xirq.vhd | -| Software driver files: | neorv32_xirq.c | link:https://stnolting.github.io/neorv32/sw/neorv32__xirq_8c.html[Online software reference (Doxygen)] -| | neorv32_xirq.h | link:https://stnolting.github.io/neorv32/sw/neorv32__xirq_8h.html[Online software reference (Doxygen)] -| Top entity ports: | `xirq_i` | External interrupts input (32-bit) -| Configuration generics: | `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 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 external interrupt controller features four interface registers: - -[start=1] -. external interrupt channel enable (`EIE`) -. external interrupt source (`ESC`) -. trigger type configuration (`TTYP`) -. trigger polarity configuration (`TPOL`) - -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"] -|======================= -| `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 -|======================= - -Each interrupt channel can be enabled or disabled individually using the `EIE` register. If the trigger of a -disabled channel fires the interrupt request is entirely ignored. - -If the configured trigger of an _enabled_ channels fires, the according interrupt request is buffered internally -and an interrupt request is sent to the CPU. If more than one trigger fires at one a prioritization is used: -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. - -The CPU can determine the most prioritized external interrupt request 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 as -well as a single bit (the MSB) that -Writing _any_ value to this register will acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller -can issue a new CPU interrupt). - - -**Register Map** - -.XIRQ register map (`struct NEORV32_XIRQ`) -[cols="^4,<2,^2,^2,<14"] -[options="header",grid="all"] -|======================= -| Address | Name [C] | Bit(s) | R/W | Description -| `0xfff30000` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned) -.3+^| `0xfff30004` .3+<| `ESC` ^| `31` ^| r/c <| XIRQ interrupt when set; write any value to this register to acknowledge the current XIRQ interrupt - ^| `30:5` ^| r/- <| _reserved_, read as zero - ^| `4:0` ^| r/c <| Interrupt source ID (0..31) of firing IRQ (prioritized!) -| `0xfff30008` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number -| `0xfff3000c` | `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 -|======================= diff --git a/docs/datasheet/software.adoc b/docs/datasheet/software.adoc index 69ed0fe13..49132e0ff 100644 --- a/docs/datasheet/software.adoc +++ b/docs/datasheet/software.adoc @@ -89,7 +89,6 @@ The NEORV32 HAL consists of the following files. | `neorv32_uart.c` | `neorv32_uart.h` | <<_primary_universal_asynchronous_receiver_and_transmitter_uart0>> and UART1 HAL | `neorv32_wdt.c` | `neorv32_wdt.h` | <<_watchdog_timer_wdt>> HAL | `neorv32_xip.c` | `neorv32_xip.h` | <<_execute_in_place_module_xip>> HAL -| `neorv32_xirq.c` | `neorv32_xirq.h` | <<_external_interrupt_controller_xirq>> HAL | `neorv32_newlib.c` | - | Platform-specific system calls for _newlib_ |======================= diff --git a/docs/figures/neorv32_processor.png b/docs/figures/neorv32_processor.png index bdf9d2e45..ce23b74c4 100644 Binary files a/docs/figures/neorv32_processor.png and b/docs/figures/neorv32_processor.png differ diff --git a/docs/userguide/adding_custom_hw_modules.adoc b/docs/userguide/adding_custom_hw_modules.adoc index 23170d77b..7810b58ef 100644 --- a/docs/userguide/adding_custom_hw_modules.adoc +++ b/docs/userguide/adding_custom_hw_modules.adoc @@ -23,9 +23,7 @@ https://stnolting.github.io/neorv32/#_serial_peripheral_interface_controller_spi https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi[TWI]. The SPI and especially the GPIO interfaces might be the most straightforward approaches since they -have a minimal protocol overhead. Device-specific interrupt capabilities could be added using the -https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq[External Interrupt Controller (XIRQ)]. - +have a minimal protocol overhead. Beyond simplicity, these interface only provide a very limited bandwidth and require more sophisticated software handling ("bit-banging" for the GPIO). Hence, it is not recommend to use them for _chip-internal_ communication. diff --git a/docs/userguide/application_specific_configuration.adoc b/docs/userguide/application_specific_configuration.adoc index 01e1600d1..37f2d8f98 100644 --- a/docs/userguide/application_specific_configuration.adoc +++ b/docs/userguide/application_specific_configuration.adoc @@ -38,7 +38,7 @@ concept and maximum RISC-V compatibility. * This is obvious, but exclude all unused optional IO/peripheral modules from synthesis via the processor configuration generics. * If an IO module provides an option to configure the number of "channels", constrain this number to the -actually required value (e.g. the PWM module `IO_PWM_NUM_CH` or the external interrupt controller `XIRQ_NUM_CH`). +actually required value (e.g. the PWM module's `IO_PWM_NUM_CH` generic). * Disable the instruction cache (`ICACHE_EN => false`) if the design only uses processor-internal IMEM and DMEM memories. * _To be continued..._ diff --git a/rtl/core/neorv32_application_image.vhd b/rtl/core/neorv32_application_image.vhd index f2162b293..ddf85babb 100644 --- a/rtl/core/neorv32_application_image.vhd +++ b/rtl/core/neorv32_application_image.vhd @@ -1,7 +1,7 @@ -- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32 -- Auto-generated memory initialization image (for internal IMEM) -- Source: demo_blink_led/build/main.bin --- Built: 10.01.2025 10:25:11 +-- Built: 15.01.2025 21:11:45 library ieee; use ieee.std_logic_1164.all; @@ -11,7 +11,7 @@ use neorv32.neorv32_package.all; package neorv32_application_image is -constant application_init_size_c : natural := 1216; -- bytes +constant application_init_size_c : natural := 1204; -- bytes constant application_init_image_c : mem32_t := ( x"f14020f3", x"80002217", @@ -27,7 +27,7 @@ x"18830313", x"30531073", x"30401073", x"00000397", -x"48c38393", +x"48038393", x"80000417", x"fc440413", x"80000497", @@ -87,9 +87,9 @@ x"00052023", x"00450513", x"ff5ff06f", x"00000417", -x"39c40413", +x"39040413", x"00000497", -x"39448493", +x"38848493", x"00945a63", x"00042083", x"000080e7", @@ -109,9 +109,9 @@ x"30551073", x"f1402473", x"02041463", x"00000417", -x"34440413", +x"33840413", x"00000497", -x"33c48493", +x"33048493", x"00945a63", x"00042083", x"000080e7", @@ -138,19 +138,17 @@ x"34002473", x"30200073", x"ff010113", x"00000513", -x"00000593", x"00112623", x"00812423", -x"140000ef", +x"13c000ef", x"00000513", x"00150413", -x"00000593", x"0ff57513", x"12c000ef", x"0fa00513", x"038000ef", x"00040513", -x"fe5ff06f", +x"fe9ff06f", x"fff4c7b7", x"ffc7a583", x"ff87a503", @@ -171,11 +169,11 @@ x"3e800593", x"00112e23", x"00812c23", x"00912a23", -x"19c000ef", +x"198000ef", x"00c12603", x"00000693", x"00000593", -x"0ec000ef", +x"0e8000ef", x"00050413", x"00058493", x"fc0027f3", @@ -222,8 +220,7 @@ x"00000013", x"ff1ff06f", x"f95ff06f", x"fffc07b7", -x"00a7a423", -x"00b7a623", +x"00a7a223", x"00008067", x"00050613", x"00000513", diff --git a/rtl/core/neorv32_bootloader_image.vhd b/rtl/core/neorv32_bootloader_image.vhd index d2858cfaa..092bb9bfb 100644 --- a/rtl/core/neorv32_bootloader_image.vhd +++ b/rtl/core/neorv32_bootloader_image.vhd @@ -1,7 +1,7 @@ -- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32 -- Auto-generated memory initialization image (for internal BOOTROM) -- Source: bootloader/build/main.bin --- Built: 10.01.2025 10:24:53 +-- Built: 15.01.2025 21:12:00 library ieee; use ieee.std_logic_1164.all; @@ -11,7 +11,7 @@ use neorv32.neorv32_package.all; package neorv32_bootloader_image is -constant bootloader_init_size_c : natural := 4032; -- bytes +constant bootloader_init_size_c : natural := 4028; -- bytes constant bootloader_init_image_c : mem32_t := ( x"f14020f3", x"80200217", @@ -27,7 +27,7 @@ x"0f830313", x"30531073", x"30401073", x"00001397", -x"f8c38393", +x"f8838393", x"80200417", x"fc440413", x"80200497", @@ -109,7 +109,7 @@ x"ffe017b7", x"00112823", x"00812623", x"00912423", -x"a3478793", +x"a2c78793", x"30579073", x"fffe07b7", x"0087a783", @@ -147,12 +147,11 @@ x"000016b7", x"60068693", x"00d76733", x"00e7a023", -x"474000ef", -x"00050a63", +x"470000ef", +x"00050863", x"fffc07b7", x"00100713", -x"00e7a423", -x"0007a623", +x"00e7a223", x"fff507b7", x"0007a023", x"00009737", @@ -193,54 +192,54 @@ x"30479073", x"00800793", x"3007a073", x"ffe01537", -x"db050513", +x"da450513", x"6b4000ef", x"f1302573", x"648000ef", x"ffe01537", -x"de850513", +x"ddc50513", x"6a0000ef", x"fffe0437", x"00042503", x"630000ef", x"ffe01537", -x"df050513", +x"de450513", x"688000ef", x"30102573", x"61c000ef", x"ffe01537", -x"df850513", +x"dec50513", x"674000ef", x"fc002573", x"608000ef", x"ffe01537", -x"e0050513", +x"df450513", x"660000ef", x"00842503", x"00100493", x"5f0000ef", x"ffe01537", -x"e0850513", +x"dfc50513", x"648000ef", x"00444503", x"00a49533", x"ffc57513", x"5d4000ef", x"ffe01537", -x"e1050513", +x"e0450513", x"62c000ef", x"00544783", x"00f49533", x"ffc57513", x"5b8000ef", x"ffe014b7", -x"dac48513", +x"da048513", x"610000ef", x"00842783", x"00f79713", x"06075063", x"ffe01537", -x"e1850513", +x"e0c50513", x"5f8000ef", x"2e0000ef", x"00042703", @@ -260,13 +259,13 @@ x"00f69613", x"0a065463", x"ffe01537", x"00472783", -x"e4450513", +x"e3850513", x"5a8000ef", x"ffe017b7", -x"e5078513", +x"e4478513", x"59c000ef", x"ffe01537", -x"ed050513", +x"ec450513", x"590000ef", x"fff507b7", x"0007a703", @@ -276,14 +275,14 @@ x"0047a403", x"0ff47413", x"00040513", x"4f4000ef", -x"dac48513", +x"da048513", x"568000ef", x"f9b40413", x"0ff47413", x"01300793", x"2287e863", x"ffe017b7", -x"f4c78793", +x"f4078793", x"00241413", x"00f40433", x"00042783", @@ -306,34 +305,34 @@ x"f285e8e3", x"00b41463", x"f2f564e3", x"00100513", -x"6f8000ef", -x"dac48513", +x"6f4000ef", +x"da048513", x"4ec000ef", x"00000513", -x"031000ef", +x"02d000ef", x"ffe002b7", x"00028067", x"00000513", -x"6d8000ef", +x"6d4000ef", x"f39ff06f", x"800007b7", x"0047a403", x"00041863", x"ffe01537", -x"ed850513", +x"ecc50513", x"f1dff06f", x"ffe01537", -x"ef450513", +x"ee850513", x"4ac000ef", x"00040513", x"440000ef", x"ffe01537", -x"efc50513", +x"ef050513", x"498000ef", x"00400537", x"42c000ef", x"ffe01537", -x"f1450513", +x"f0850513", x"484000ef", x"fff507b7", x"0007a703", @@ -351,7 +350,7 @@ x"00050663", x"00300513", x"498000ef", x"ffe01537", -x"f2050513", +x"f1450513", x"43c000ef", x"01045793", x"00178793", @@ -389,7 +388,7 @@ x"00850513", x"40e005b3", x"2a8000ef", x"ffe01537", -x"d9450513", +x"d8850513", x"e09ff06f", x"00f12223", x"1ec000ef", @@ -415,14 +414,14 @@ x"800007b7", x"0047a783", x"e60790e3", x"ffe01537", -x"f3050513", +x"f2450513", x"da1ff06f", x"fffe07b7", x"0087a783", x"2007f793", x"00079863", x"ffe01537", -x"f4050513", +x"f3450513", x"d85ff06f", x"00100513", x"e35ff06f", @@ -611,7 +610,7 @@ x"01c00493", x"00945733", x"ffe017b7", x"00f77713", -x"f9c78793", +x"f9078793", x"00e787b3", x"0007c503", x"ffc48493", @@ -647,23 +646,22 @@ x"ff810113", x"00812023", x"00050413", x"ffe01537", -x"d3c50513", +x"d3050513", x"00112223", x"f99ff0ef", x"00241793", x"ffe01537", x"008787b3", -x"fac50513", +x"fa050513", x"00f50533", x"f81ff0ef", x"00800793", x"3007b073", x"c79ff0ef", -x"00050a63", +x"00050863", x"fffc07b7", x"00100713", -x"00e7a423", -x"0007a623", +x"00e7a223", x"10500073", x"ffdff06f", x"fd010113", @@ -683,17 +681,17 @@ x"342024f3", x"800007b7", x"00778793", x"08f49e63", -x"c15ff0ef", +x"c19ff0ef", x"00050a63", x"fffc0737", -x"00872783", +x"00472783", x"0017c793", -x"00f72423", +x"00f72223", x"fffe0437", x"00842783", x"00f79713", x"02075e63", -x"bd5ff0ef", +x"bd9ff0ef", x"00042783", x"0027d793", x"00a78533", @@ -727,58 +725,59 @@ x"800007b7", x"0007a783", x"00078663", x"00100513", -x"eb1ff0ef", +x"eb5ff0ef", x"34102473", x"fffe07b7", x"0087a783", x"00e79713", x"04075263", x"ffe01537", -x"d4450513", -x"e41ff0ef", +x"d3850513", +x"e45ff0ef", x"00048513", -x"dd5ff0ef", +x"dd9ff0ef", x"02000513", -x"db5ff0ef", +x"db9ff0ef", x"00040513", -x"dc5ff0ef", +x"dc9ff0ef", x"02000513", -x"da5ff0ef", +x"da9ff0ef", x"34302573", -x"db5ff0ef", +x"db9ff0ef", x"ffe01537", -x"dac50513", -x"e0dff0ef", +x"da050513", +x"e11ff0ef", x"00440413", x"34141073", x"f51ff06f", x"fe010113", -x"00912a23", x"00100793", -x"800004b7", +x"80000737", x"00112e23", x"00812c23", +x"00912a23", x"00a12023", -x"00f4a023", -x"02051863", +x"00f72023", +x"02f50a63", x"ffe01537", -x"d5050513", -x"dd1ff0ef", +x"d4450513", +x"dd5ff0ef", +x"00000413", x"00012503", -x"004005b7", +x"00040593", x"b71ff0ef", x"4788d7b7", x"afe78793", -x"04f50863", +x"04f50a63", x"00000513", x"0380006f", x"ffe01537", -x"d7050513", +x"d6450513", x"da5ff0ef", x"00400537", x"d39ff0ef", x"ffe01537", -x"d8c50513", +x"d8050513", x"d91ff0ef", x"fffe07b7", x"0087a783", @@ -787,53 +786,52 @@ x"00074663", x"00300513", x"dc9ff0ef", x"c19ff0ef", -x"fa0502e3", -x"ff1ff06f", +x"fe051ae3", +x"00400437", +x"f9dff06f", x"00012503", -x"004005b7", -x"00458593", +x"00440593", x"b09ff0ef", -x"00050413", +x"00050493", x"00012503", -x"004005b7", -x"00858593", -x"af5ff0ef", -x"00050693", -x"ffc47613", -x"00000713", +x"00840593", +x"af9ff0ef", +x"00c40613", +x"00050713", +x"ffc4f693", x"00000793", -x"004005b7", -x"00c58593", -x"00b705b3", -x"02c71e63", -x"00d787b3", +x"00000413", +x"00f605b3", +x"04d79063", +x"00e40433", x"00200513", -x"fa0792e3", +x"fa0416e3", x"ffe01537", -x"d9450513", -x"d11ff0ef", -x"800007b7", -x"0087a223", +x"d8850513", +x"d19ff0ef", x"01c12083", x"01812403", -x"0004a023", +x"800007b7", +x"0097a223", +x"800007b7", +x"0007a023", x"01412483", x"02010113", x"00008067", x"00012503", -x"00c12823", -x"00e12623", -x"00d12423", -x"00f12223", -x"a85ff0ef", -x"00c12703", -x"00412783", -x"01012603", -x"00a72023", -x"00812683", -x"00a787b3", -x"00470713", -x"f85ff06f", +x"00d12823", +x"00f12623", +x"00c12423", +x"00e12223", +x"a89ff0ef", +x"00c12783", +x"01012683", +x"00812603", +x"00a7a023", +x"00412703", +x"00a40433", +x"00478793", +x"f89ff06f", x"ff810113", x"00112223", x"00812023", @@ -844,18 +842,17 @@ x"40a00533", x"e0400437", x"00a47433", x"ffe01537", -x"d9850513", -x"c89ff0ef", +x"d8c50513", +x"c8dff0ef", x"00040513", -x"c1dff0ef", +x"c21ff0ef", x"ffe01537", -x"da850513", -x"c75ff0ef", -x"975ff0ef", -x"00050863", +x"d9c50513", +x"c79ff0ef", +x"979ff0ef", +x"00050663", x"fffc07b7", -x"0007a423", -x"0007a623", +x"0007a223", x"fff50737", x"00072783", x"fe07cee3", @@ -899,7 +896,7 @@ x"0a3e3e20", x"444c420a", x"4a203a56", x"31206e61", -x"30322030", +x"30322035", x"480a3532", x"203a5657", x"00000020", @@ -992,26 +989,26 @@ x"00002e65", x"61766e49", x"2064696c", x"00444d43", -x"ffe00638", -x"ffe00660", -x"ffe00660", -x"ffe003e4", -x"ffe00660", -x"ffe00660", -x"ffe00660", -x"ffe00630", -x"ffe00660", -x"ffe00660", -x"ffe00660", -x"ffe00660", -x"ffe00660", -x"ffe004a8", -x"ffe004bc", -x"ffe00660", -x"ffe004b0", -x"ffe00660", -x"ffe00660", -x"ffe00650", +x"ffe00634", +x"ffe0065c", +x"ffe0065c", +x"ffe003e0", +x"ffe0065c", +x"ffe0065c", +x"ffe0065c", +x"ffe0062c", +x"ffe0065c", +x"ffe0065c", +x"ffe0065c", +x"ffe0065c", +x"ffe0065c", +x"ffe004a4", +x"ffe004b8", +x"ffe0065c", +x"ffe004ac", +x"ffe0065c", +x"ffe0065c", +x"ffe0064c", x"33323130", x"37363534", x"62613938", @@ -1019,8 +1016,10 @@ x"66656463", x"00455845", x"5a495300", x"48430045", -x"4600534b", -x"0048534c" +x"5300534b", +x"00004950", +x"00495754", +x"00000000" ); end neorv32_bootloader_image; diff --git a/rtl/core/neorv32_gpio.vhd b/rtl/core/neorv32_gpio.vhd index 2461eb8c5..2c3ba5613 100644 --- a/rtl/core/neorv32_gpio.vhd +++ b/rtl/core/neorv32_gpio.vhd @@ -1,5 +1,5 @@ -- ================================================================================ -- --- NEORV32 SoC - General Purpose Parallel Input/Output Port (GPIO) -- +-- NEORV32 SoC - Interrupt-Capable General Purpose Input/Output Port (GPIO) Module -- -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- @@ -16,21 +16,37 @@ use neorv32.neorv32_package.all; entity neorv32_gpio is generic ( - GPIO_NUM : natural range 0 to 64 -- number of GPIO input/output pairs (0..64) + GPIO_NUM : natural range 0 to 32 -- number of GPIO input/output pairs (0..32) ); port ( clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async bus_req_i : in bus_req_t; -- bus request bus_rsp_o : out bus_rsp_t; -- bus response - gpio_o : out std_ulogic_vector(63 downto 0); -- parallel output - gpio_i : in std_ulogic_vector(63 downto 0) -- parallel input + gpio_o : out std_ulogic_vector(31 downto 0); -- general purpose input port + gpio_i : in std_ulogic_vector(31 downto 0); -- general purpose output port + cpu_irq_o : out std_ulogic -- CPU interrupt ); end neorv32_gpio; architecture neorv32_gpio_rtl of neorv32_gpio is - signal din, din_rd, dout, dout_rd : std_ulogic_vector(63 downto 0); + -- register addresses -- + constant addr_in_c : std_ulogic_vector(2 downto 0) := "000"; -- r/-: input port + constant addr_out_c : std_ulogic_vector(2 downto 0) := "001"; -- r/w: output port + -- + constant addr_tt_c : std_ulogic_vector(2 downto 0) := "100"; -- r/w: trigger type (level/edge) + constant addr_tp_c : std_ulogic_vector(2 downto 0) := "101"; -- r/w: trigger polarity (high/low or rising/falling) + constant addr_ie_c : std_ulogic_vector(2 downto 0) := "110"; -- r/w: interrupt enable + constant addr_ip_c : std_ulogic_vector(2 downto 0) := "111"; -- r/c: interrupt pending + + -- interface registers -- + signal port_in, port_out : std_ulogic_vector(GPIO_NUM-1 downto 0); + signal irq_typ, irq_pol : std_ulogic_vector(GPIO_NUM-1 downto 0); + signal irq_en, irq_clrn : std_ulogic_vector(GPIO_NUM-1 downto 0); + + -- interrupt generator -- + signal port_in2, irq_trig, irq_pend : std_ulogic_vector(GPIO_NUM-1 downto 0); begin @@ -40,58 +56,92 @@ begin begin if (rstn_i = '0') then bus_rsp_o <= rsp_terminate_c; - dout <= (others => '0'); + port_out <= (others => '0'); + irq_typ <= (others => '0'); + irq_pol <= (others => '0'); + irq_en <= (others => '0'); + irq_clrn <= (others => '0'); elsif rising_edge(clk_i) then - -- bus handshake -- + -- defaults -- bus_rsp_o.ack <= bus_req_i.stb; bus_rsp_o.err <= '0'; bus_rsp_o.data <= (others => '0'); + irq_clrn <= (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) = "10") then - dout(31 downto 00) <= bus_req_i.data; - end if; - if (bus_req_i.addr(3 downto 2) = "11") then - dout(63 downto 32) <= bus_req_i.data; - end if; + case bus_req_i.addr(4 downto 2) is + when addr_out_c => port_out <= bus_req_i.data(GPIO_NUM-1 downto 0); -- output port + when addr_tt_c => irq_typ <= bus_req_i.data(GPIO_NUM-1 downto 0); -- trigger type + when addr_tp_c => irq_pol <= bus_req_i.data(GPIO_NUM-1 downto 0); -- trigger polarity + when addr_ie_c => irq_en <= bus_req_i.data(GPIO_NUM-1 downto 0); -- interrupt enable + when addr_ip_c => irq_clrn <= bus_req_i.data(GPIO_NUM-1 downto 0); -- interrupt pending (clear-only) + when others => NULL; + end case; else -- read access - case bus_req_i.addr(3 downto 2) is - when "00" => bus_rsp_o.data <= din_rd(31 downto 00); - when "01" => bus_rsp_o.data <= din_rd(63 downto 32); - when "10" => bus_rsp_o.data <= dout_rd(31 downto 00); - when others => bus_rsp_o.data <= dout_rd(63 downto 32); + case bus_req_i.addr(4 downto 2) is + when addr_in_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= port_in; -- input port + when addr_out_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= port_out; -- output port + when addr_tt_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= irq_typ; -- trigger type + when addr_tp_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= irq_pol; -- trigger polarity + when addr_ie_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= irq_en; -- interrupt enable + when addr_ip_c => bus_rsp_o.data(GPIO_NUM-1 downto 0) <= irq_pend; -- interrupt pending + when others => NULL; end case; end if; - end if; end if; end process bus_access; + -- input sampling -- + input_stage: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + port_in <= (others => '0'); + port_in2 <= (others => '0'); + elsif rising_edge(clk_i) then + port_in <= gpio_i(GPIO_NUM-1 downto 0); + port_in2 <= port_in; + end if; + end process input_stage; - -- Physical Pin Mapping ------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - pin_mapping: process(din, dout) + -- direct output -- + output_stage: process(port_out) begin - din_rd <= (others => '0'); - dout_rd <= (others => '0'); - for i in 0 to GPIO_NUM-1 loop - din_rd(i) <= din(i); - dout_rd(i) <= dout(i); - end loop; - end process pin_mapping; - - -- output -- - gpio_o <= dout_rd; - - -- synchronize input -- - input_sync: process(rstn_i, clk_i) + gpio_o <= (others => '0'); + gpio_o(GPIO_NUM-1 downto 0) <= port_out; + end process output_stage; + + + -- IRQ Generator -------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + irq_trigger_gen: + for i in 0 to GPIO_NUM-1 generate + irq_trigger: process(port_in, port_in2, irq_typ, irq_pol) + variable sel_v : std_ulogic_vector(1 downto 0); + begin + sel_v := irq_typ(i) & irq_pol(i); + case sel_v is + when "00" => irq_trig(i) <= not port_in(i); -- low-level + when "01" => irq_trig(i) <= port_in(i); -- high-level + when "10" => irq_trig(i) <= (not port_in(i)) and port_in2(i); -- falling-edge + when "11" => irq_trig(i) <= port_in(i) and (not port_in2(i)); -- rising-edge + when others => irq_trig(i) <= '0'; + end case; + end process irq_trigger; + end generate; + + -- buffer pending interrupts until manually cleared -- + irq_buffer: process(rstn_i, clk_i) begin if (rstn_i = '0') then - din <= (others => '0'); + irq_pend <= (others => '0'); + cpu_irq_o <= '0'; elsif rising_edge(clk_i) then - din <= gpio_i; + irq_pend <= irq_en and ((irq_pend and irq_clrn) or irq_trig); + cpu_irq_o <= or_reduce_f(irq_pend); end if; - end process input_sync; + end process irq_buffer; -end neorv32_gpio_rtl; +end neorv32_gpio_rtl; \ No newline at end of file diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 43e9d38ee..b2adcdc1c 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"01100906"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100907"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -79,7 +79,7 @@ package neorv32_package is constant base_io_pwm_c : std_ulogic_vector(31 downto 0) := x"fff00000"; constant base_io_gptmr_c : std_ulogic_vector(31 downto 0) := x"fff10000"; constant base_io_onewire_c : std_ulogic_vector(31 downto 0) := x"fff20000"; - constant base_io_xirq_c : std_ulogic_vector(31 downto 0) := x"fff30000"; +--constant base_io_???_c : std_ulogic_vector(31 downto 0) := x"fff30000"; -- reserved constant base_io_clint_c : std_ulogic_vector(31 downto 0) := x"fff40000"; constant base_io_uart0_c : std_ulogic_vector(31 downto 0) := x"fff50000"; constant base_io_uart1_c : std_ulogic_vector(31 downto 0) := x"fff60000"; @@ -802,8 +802,6 @@ package neorv32_package is XIP_CACHE_EN : boolean := false; XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; - -- External Interrupts Controller (XIRQ) -- - XIRQ_NUM_CH : natural range 0 to 32 := 0; -- Processor peripherals -- IO_DISABLE_SYSINFO : boolean := false; IO_GPIO_NUM : natural range 0 to 64 := 0; @@ -880,8 +878,8 @@ package neorv32_package is xip_dat_i : in std_ulogic := 'L'; xip_dat_o : out std_ulogic; -- GPIO (available if IO_GPIO_NUM > 0) -- - gpio_o : out std_ulogic_vector(63 downto 0); - gpio_i : in std_ulogic_vector(63 downto 0) := (others => 'L'); + gpio_o : out std_ulogic_vector(31 downto 0); + gpio_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- primary UART0 (available if IO_UART0_EN = true) -- uart0_txd_o : out std_ulogic; uart0_rxd_i : in std_ulogic := 'L'; @@ -924,8 +922,6 @@ package neorv32_package is neoled_o : out std_ulogic; -- Machine timer system time (available if IO_CLINT_EN = true) -- mtime_time_o : out std_ulogic_vector(63 downto 0); - -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- - xirq_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- CPU Interrupts -- mtime_irq_i : in std_ulogic := 'L'; msw_irq_i : in std_ulogic := 'L'; diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd index 168eea9d6..7f0c34159 100644 --- a/rtl/core/neorv32_sysinfo.vhd +++ b/rtl/core/neorv32_sysinfo.vhd @@ -3,7 +3,7 @@ -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- -- Licensed under the BSD-3-Clause license, see LICENSE for details. -- -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- @@ -55,7 +55,6 @@ entity neorv32_sysinfo is IO_TRNG_EN : boolean; -- implement true random number generator (TRNG)? IO_CFS_EN : boolean; -- implement custom functions subsystem (CFS)? IO_NEOLED_EN : boolean; -- implement NeoPixel-compatible smart LED interface (NEOLED)? - IO_XIRQ_EN : boolean; -- implement external interrupts controller (XIRQ)? IO_GPTMR_EN : boolean; -- implement general purpose timer (GPTMR)? IO_ONEWIRE_EN : boolean; -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN : boolean; -- implement direct memory access controller (DMA)? @@ -138,7 +137,7 @@ begin sysinfo(2)(24) <= '1' when IO_SDI_EN else '0'; -- serial data interface (SDI) implemented? sysinfo(2)(25) <= '1' when IO_UART1_EN else '0'; -- secondary universal asynchronous receiver/transmitter (UART1) implemented? sysinfo(2)(26) <= '1' when IO_NEOLED_EN else '0'; -- NeoPixel-compatible smart LED interface (NEOLED) implemented? - sysinfo(2)(27) <= '1' when IO_XIRQ_EN else '0'; -- external interrupt controller (XIRQ) implemented? + sysinfo(2)(27) <= '0'; -- reserved sysinfo(2)(28) <= '1' when IO_GPTMR_EN else '0'; -- general purpose timer (GPTMR) implemented? sysinfo(2)(29) <= '1' when IO_SLINK_EN else '0'; -- stream link interface (SLINK) implemented? sysinfo(2)(30) <= '1' when IO_ONEWIRE_EN else '0'; -- 1-wire interface (ONEWIRE) implemented? diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 2088bad3f..6f1bd72d3 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -110,12 +110,9 @@ entity neorv32_top is XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; -- number of blocks (min 1), has to be a power of 2 XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- block size in bytes (min 4), has to be a power of 2 - -- External Interrupts Controller (XIRQ) -- - XIRQ_NUM_CH : natural range 0 to 32 := 0; -- number of external IRQ channels (0..32) - -- Processor peripherals -- IO_DISABLE_SYSINFO : boolean := false; -- disable the SYSINFO module (for advanced users only) - IO_GPIO_NUM : natural range 0 to 64 := 0; -- number of GPIO input/output pairs (0..64) + IO_GPIO_NUM : natural range 0 to 32 := 0; -- number of GPIO input/output pairs (0..32) IO_CLINT_EN : boolean := false; -- implement core local interruptor (CLINT)? IO_UART0_EN : boolean := false; -- implement primary universal asynchronous receiver/transmitter (UART0)? IO_UART0_RX_FIFO : natural range 1 to 2**15 := 1; -- RX FIFO depth, has to be a power of two, min 1 @@ -194,8 +191,8 @@ entity neorv32_top is xip_dat_o : out std_ulogic; -- controller data output -- GPIO (available if IO_GPIO_NUM > 0) -- - gpio_o : out std_ulogic_vector(63 downto 0); -- parallel output - gpio_i : in std_ulogic_vector(63 downto 0) := (others => 'L'); -- parallel input + gpio_o : out std_ulogic_vector(31 downto 0); -- parallel output + gpio_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- parallel input; interrupt-capable -- primary UART0 (available if IO_UART0_EN = true) -- uart0_txd_o : out std_ulogic; -- UART0 send data @@ -250,9 +247,6 @@ entity neorv32_top is -- Machine timer system time (available if IO_CLINT_EN = true) -- mtime_time_o : out std_ulogic_vector(63 downto 0); -- current system time - -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- - xirq_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- IRQ channels - -- CPU interrupts (for chip-internal usage only) -- mtime_irq_i : in std_ulogic := 'L'; -- machine timer interrupt, available if IO_CLINT_EN = false msw_irq_i : in std_ulogic := 'L'; -- machine software interrupt, available if IO_CLINT_EN = false @@ -279,7 +273,6 @@ architecture neorv32_top_rtl of neorv32_top is -- auto-configuration -- constant num_cores_c : natural := cond_sel_natural_f(DUAL_CORE_EN, 2, 1); constant io_gpio_en_c : boolean := boolean(IO_GPIO_NUM > 0); - constant io_xirq_en_c : boolean := boolean(XIRQ_NUM_CH > 0); constant io_pwm_en_c : boolean := boolean(IO_PWM_NUM_CH > 0); constant cpu_smpmp_c : boolean := boolean(PMP_NUM_REGIONS > 0); constant io_sysinfo_en_c : boolean := not IO_DISABLE_SYSINFO; @@ -332,8 +325,8 @@ architecture neorv32_top_rtl of neorv32_top is -- bus: IO devices -- type io_devices_enum_t is ( - IODEV_BOOTROM, IODEV_OCD, IODEV_SYSINFO, IODEV_NEOLED, IODEV_GPIO, IODEV_WDT, IODEV_TRNG, IODEV_TWI, - IODEV_SPI, IODEV_SDI, IODEV_UART1, IODEV_UART0, IODEV_CLINT, IODEV_XIRQ, IODEV_ONEWIRE, + IODEV_BOOTROM, IODEV_OCD, IODEV_SYSINFO, IODEV_NEOLED, IODEV_GPIO, IODEV_WDT, IODEV_TRNG, + IODEV_TWI, IODEV_SPI, IODEV_SDI, IODEV_UART1, IODEV_UART0, IODEV_CLINT, IODEV_ONEWIRE, IODEV_GPTMR, IODEV_PWM, IODEV_XIP, IODEV_CRC, IODEV_DMA, IODEV_SLINK, IODEV_CFS, IODEV_TWD ); type iodev_req_t is array (io_devices_enum_t) of bus_req_t; @@ -344,7 +337,7 @@ architecture neorv32_top_rtl of neorv32_top is -- IRQs -- type firq_enum_t is ( FIRQ_TWD, FIRQ_UART0_RX, FIRQ_UART0_TX, FIRQ_UART1_RX, FIRQ_UART1_TX, FIRQ_SPI, FIRQ_SDI, FIRQ_TWI, - FIRQ_CFS, FIRQ_NEOLED, FIRQ_XIRQ, FIRQ_GPTMR, FIRQ_ONEWIRE, FIRQ_DMA, FIRQ_SLINK_RX, FIRQ_SLINK_TX + FIRQ_CFS, FIRQ_NEOLED, FIRQ_GPIO, FIRQ_GPTMR, FIRQ_ONEWIRE, FIRQ_DMA, FIRQ_SLINK_RX, FIRQ_SLINK_TX ); type firq_t is array (firq_enum_t) of std_ulogic; signal firq : firq_t; @@ -394,7 +387,6 @@ begin cond_sel_string_f(IO_TRNG_EN, "TRNG ", "") & cond_sel_string_f(IO_CFS_EN, "CFS ", "") & cond_sel_string_f(IO_NEOLED_EN, "NEOLED ", "") & - cond_sel_string_f(io_xirq_en_c, "XIRQ ", "") & cond_sel_string_f(IO_GPTMR_EN, "GPTMR ", "") & cond_sel_string_f(IO_ONEWIRE_EN, "ONEWIRE ", "") & cond_sel_string_f(IO_DMA_EN, "DMA ", "") & @@ -489,7 +481,7 @@ begin cpu_firq(5) <= firq(FIRQ_UART1_TX); cpu_firq(6) <= firq(FIRQ_SPI); cpu_firq(7) <= firq(FIRQ_TWI); - cpu_firq(8) <= firq(FIRQ_XIRQ); + cpu_firq(8) <= firq(FIRQ_GPIO); cpu_firq(9) <= firq(FIRQ_NEOLED); cpu_firq(10) <= firq(FIRQ_DMA); cpu_firq(11) <= firq(FIRQ_SDI); @@ -1047,7 +1039,7 @@ begin DEV_16_EN => io_pwm_en_c, DEV_16_BASE => base_io_pwm_c, DEV_17_EN => IO_GPTMR_EN, DEV_17_BASE => base_io_gptmr_c, DEV_18_EN => IO_ONEWIRE_EN, DEV_18_BASE => base_io_onewire_c, - DEV_19_EN => io_xirq_en_c, DEV_19_BASE => base_io_xirq_c, + DEV_19_EN => false, DEV_19_BASE => (others => '0'), -- reserved DEV_20_EN => IO_CLINT_EN, DEV_20_BASE => base_io_clint_c, DEV_21_EN => IO_UART0_EN, DEV_21_BASE => base_io_uart0_c, DEV_22_EN => IO_UART1_EN, DEV_22_BASE => base_io_uart1_c, @@ -1085,7 +1077,7 @@ begin dev_16_req_o => iodev_req(IODEV_PWM), dev_16_rsp_i => iodev_rsp(IODEV_PWM), dev_17_req_o => iodev_req(IODEV_GPTMR), dev_17_rsp_i => iodev_rsp(IODEV_GPTMR), dev_18_req_o => iodev_req(IODEV_ONEWIRE), dev_18_rsp_i => iodev_rsp(IODEV_ONEWIRE), - dev_19_req_o => iodev_req(IODEV_XIRQ), dev_19_rsp_i => iodev_rsp(IODEV_XIRQ), + dev_19_req_o => open, dev_19_rsp_i => rsp_terminate_c, -- reserved dev_20_req_o => iodev_req(IODEV_CLINT), dev_20_rsp_i => iodev_rsp(IODEV_CLINT), dev_21_req_o => iodev_req(IODEV_UART0), dev_21_rsp_i => iodev_rsp(IODEV_UART0), dev_22_req_o => iodev_req(IODEV_UART1), dev_22_rsp_i => iodev_rsp(IODEV_UART1), @@ -1195,7 +1187,8 @@ begin bus_req_i => iodev_req(IODEV_GPIO), bus_rsp_o => iodev_rsp(IODEV_GPIO), gpio_o => gpio_o, - gpio_i => gpio_i + gpio_i => gpio_i, + cpu_irq_o => firq(FIRQ_GPIO) ); end generate; @@ -1203,6 +1196,7 @@ begin if not io_gpio_en_c generate iodev_rsp(IODEV_GPIO) <= rsp_terminate_c; gpio_o <= (others => '0'); + firq(FIRQ_GPIO) <= '0'; end generate; @@ -1514,31 +1508,6 @@ begin end generate; - -- External Interrupt Controller (XIRQ) --------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - neorv32_xirq_enabled: - if io_xirq_en_c generate - neorv32_xirq_inst: entity neorv32.neorv32_xirq - generic map ( - NUM_CH => XIRQ_NUM_CH - ) - port map ( - clk_i => clk_i, - rstn_i => rstn_sys, - bus_req_i => iodev_req(IODEV_XIRQ), - bus_rsp_o => iodev_rsp(IODEV_XIRQ), - xirq_i => xirq_i(XIRQ_NUM_CH-1 downto 0), - cpu_irq_o => firq(FIRQ_XIRQ) - ); - end generate; - - neorv32_xirq_disabled: - if not io_xirq_en_c generate - iodev_rsp(IODEV_XIRQ) <= rsp_terminate_c; - firq(FIRQ_XIRQ) <= '0'; - end generate; - - -- General Purpose Timer (GPTMR) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_gptmr_enabled: @@ -1698,7 +1667,6 @@ begin IO_TRNG_EN => IO_TRNG_EN, IO_CFS_EN => IO_CFS_EN, IO_NEOLED_EN => IO_NEOLED_EN, - IO_XIRQ_EN => io_xirq_en_c, IO_GPTMR_EN => IO_GPTMR_EN, IO_ONEWIRE_EN => IO_ONEWIRE_EN, IO_DMA_EN => IO_DMA_EN, diff --git a/rtl/core/neorv32_xirq.vhd b/rtl/core/neorv32_xirq.vhd deleted file mode 100644 index 76467efc5..000000000 --- a/rtl/core/neorv32_xirq.vhd +++ /dev/null @@ -1,201 +0,0 @@ --- ================================================================================ -- --- NEORV32 SoC - External Interrupt Controller (XIRQ) -- --- -------------------------------------------------------------------------------- -- --- Simple interrupt controller for platform (processor-external) interrupts. Up to -- --- 32 channels are supported that get prioritized into a single CPU interrupt. -- --- Trigger type is programmable per-channel by configuration registers. -- --- -------------------------------------------------------------------------------- -- --- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- --- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- --- Licensed under the BSD-3-Clause license, see LICENSE for details. -- --- SPDX-License-Identifier: BSD-3-Clause -- --- ================================================================================ -- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library neorv32; -use neorv32.neorv32_package.all; - -entity neorv32_xirq is - generic ( - NUM_CH : natural range 0 to 32 -- number of IRQ channels - ); - port ( - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active - bus_req_i : in bus_req_t; -- bus request - bus_rsp_o : out bus_rsp_t; -- bus response - xirq_i : in std_ulogic_vector(NUM_CH-1 downto 0); -- external IRQ channels - cpu_irq_o : out std_ulogic -- CPU interrupt - ); -end neorv32_xirq; - -architecture neorv32_xirq_rtl of neorv32_xirq is - - -- register addresses -- - constant addr_eie_c : std_ulogic_vector(1 downto 0) := "00"; -- r/w: channel enable - constant addr_esc_c : std_ulogic_vector(1 downto 0) := "01"; -- r/w: source IRQ, ACK on write - constant addr_ttyp_c : std_ulogic_vector(1 downto 0) := "10"; -- r/w: trigger type (level/edge) - constant addr_tpol_c : std_ulogic_vector(1 downto 0) := "11"; -- r/w: trigger polarity (high/low or rising/falling) - - -- configuration registers -- - signal irq_enable, irq_type, irq_polarity : std_ulogic_vector(NUM_CH-1 downto 0); - - -- interrupt trigger -- - signal irq_sync1, irq_sync2, irq_trig : std_ulogic_vector(NUM_CH-1 downto 0); - - -- pending interrupt(s) -- - signal irq_pending : std_ulogic_vector(NUM_CH-1 downto 0); - - -- priority encoder -- - type prio_enc_t is array (0 to NUM_CH-1) of std_ulogic_vector(4 downto 0); - signal prio_enc : prio_enc_t; - - -- interrupt arbiter -- - signal irq_state : std_ulogic_vector(1 downto 0); - signal irq_source : std_ulogic_vector(4 downto 0); - signal irq_clear : std_ulogic_vector(31 downto 0); - -begin - - -- Bus Access ----------------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - bus_access: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - bus_rsp_o <= rsp_terminate_c; - irq_type <= (others => '0'); - irq_polarity <= (others => '0'); - irq_enable <= (others => '0'); - elsif rising_edge(clk_i) then - -- defaults -- - bus_rsp_o.ack <= bus_req_i.stb; - bus_rsp_o.err <= '0'; - bus_rsp_o.data <= (others => '0'); - -- 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) = addr_eie_c) then -- channel-enable - irq_enable <= bus_req_i.data(NUM_CH-1 downto 0); - end if; - if (bus_req_i.addr(3 downto 2) = addr_ttyp_c) then -- trigger type - irq_type <= bus_req_i.data(NUM_CH-1 downto 0); - end if; - if (bus_req_i.addr(3 downto 2) = addr_tpol_c) then -- trigger polarity - irq_polarity <= bus_req_i.data(NUM_CH-1 downto 0); - end if; - else -- read access - case bus_req_i.addr(3 downto 2) is - when addr_eie_c => -- channel-enable - bus_rsp_o.data(NUM_CH-1 downto 0) <= irq_enable; - when addr_esc_c => - bus_rsp_o.data(31) <= irq_state(1); -- active interrupt waiting for ACK - bus_rsp_o.data(4 downto 0) <= irq_source; -- interrupt source (channel number) - when addr_ttyp_c => -- trigger type - bus_rsp_o.data(NUM_CH-1 downto 0) <= irq_type; - when others => -- trigger polarity - bus_rsp_o.data(NUM_CH-1 downto 0) <= irq_polarity; - end case; - end if; - end if; - end if; - end process bus_access; - - - -- IRQ Trigger -------------------------------------------------------------- - -- ----------------------------------------------------------------------------- - synchronizer: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - irq_sync1 <= (others => '0'); - irq_sync2 <= (others => '0'); - elsif rising_edge(clk_i) then - irq_sync1 <= xirq_i(NUM_CH-1 downto 0); - irq_sync2 <= irq_sync1; - end if; - end process synchronizer; - - -- trigger type select -- - irq_trigger_gen: - for i in 0 to NUM_CH-1 generate - irq_trigger: process(irq_sync1, irq_sync2, irq_type, irq_polarity) - variable sel_v : std_ulogic_vector(1 downto 0); - begin - sel_v := irq_type(i) & irq_polarity(i); - case sel_v is - when "00" => irq_trig(i) <= not irq_sync1(i); -- low-level - when "01" => irq_trig(i) <= irq_sync1(i); -- high-level - when "10" => irq_trig(i) <= (not irq_sync1(i)) and irq_sync2(i); -- falling-edge - when "11" => irq_trig(i) <= irq_sync1(i) and (not irq_sync2(i)); -- rising-edge - when others => irq_trig(i) <= '0'; - end case; - end process irq_trigger; - end generate; - - - -- Interrupt-Pending Buffer ------------------------------------------------- - -- ----------------------------------------------------------------------------- - irq_buffer: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - irq_pending <= (others => '0'); - elsif rising_edge(clk_i) then - irq_pending <= irq_enable and ((irq_pending and (not irq_clear(NUM_CH-1 downto 0))) or irq_trig); - end if; - end process irq_buffer; - - - -- Priority Encoder (structural code: mux-chain) ---------------------------- - -- ----------------------------------------------------------------------------- - priority_encoder_gen: - for i in 0 to NUM_CH-1 generate -- start with highest priority (=0) - priority_encoder_gen_chain: -- inside chain - if i < NUM_CH-1 generate - prio_enc(i) <= std_ulogic_vector(to_unsigned(i, 5)) when (irq_pending(i) = '1') else prio_enc(i+1); - end generate; - priority_encoder_gen_last: -- end of chain - if i = NUM_CH-1 generate - prio_enc(NUM_CH-1) <= std_ulogic_vector(to_unsigned(NUM_CH-1, 5)); -- lowest priority - end generate; - end generate; - - - -- IRQ Arbiter -------------------------------------------------------------- - -- ----------------------------------------------------------------------------- - irq_arbiter: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - irq_clear <= (others => '0'); - irq_source <= (others => '0'); - irq_state <= (others => '0'); - elsif rising_edge(clk_i) then - irq_clear <= (others => '0'); -- default - case irq_state is - - when "00" => -- wait for pending interrupt - irq_source <= prio_enc(0); -- highest-priority channel - if (or_reduce_f(irq_pending) = '1') then - irq_state <= "01"; - end if; - - when "01" => -- clear triggering channel - irq_clear(to_integer(unsigned(irq_source))) <= '1'; -- ACK/clear according pending bit - irq_state <= "11"; - - when others => -- wait for CPU acknowledge - if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(3 downto 2) = addr_esc_c) then -- acknowledge on write access - irq_state <= "00"; - end if; - - end case; - end if; - end process irq_arbiter; - - -- CPU interrupt -- - cpu_irq_o <= irq_state(0); - - -end neorv32_xirq_rtl; diff --git a/rtl/file_list_soc.f b/rtl/file_list_soc.f index 76da9d04d..1382c5a8f 100644 --- a/rtl/file_list_soc.f +++ b/rtl/file_list_soc.f @@ -39,7 +39,6 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_pwm.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_trng.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_neoled.vhd -NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_xirq.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_gptmr.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_onewire.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_slink.vhd diff --git a/rtl/system_integration/neorv32_vivado_ip.tcl b/rtl/system_integration/neorv32_vivado_ip.tcl index 0fa8029e3..2b99f2a0a 100644 --- a/rtl/system_integration/neorv32_vivado_ip.tcl +++ b/rtl/system_integration/neorv32_vivado_ip.tcl @@ -136,7 +136,6 @@ proc setup_ip_gui {} { set_property enablement_dependency {$IO_PWM_EN} [ipx::get_ports pwm_o -of_objects [ipx::current_core]] set_property enablement_dependency {$IO_CFS_EN} [ipx::get_ports cfs_* -of_objects [ipx::current_core]] set_property enablement_dependency {$IO_NEOLED_EN} [ipx::get_ports neoled_o -of_objects [ipx::current_core]] - set_property enablement_dependency {$XIRQ_EN} [ipx::get_ports xirq_i -of_objects [ipx::current_core]] set_property enablement_dependency {$IO_CLINT_EN} [ipx::get_ports mtime_time_o -of_objects [ipx::current_core]] set_property enablement_dependency {!$IO_CLINT_EN} [ipx::get_ports mtime_irq_i -of_objects [ipx::current_core]] set_property enablement_dependency {!$IO_CLINT_EN} [ipx::get_ports msw_irq_i -of_objects [ipx::current_core]] @@ -308,16 +307,10 @@ proc setup_ip_gui {} { # ************************************************************** set page [add_page {Peripherals}] - set group [add_group $page {External Interrupt Controller (XIRQ)}] - add_params $group { - { XIRQ_EN {Enable XIRQ} } - { XIRQ_NUM_CH {Number of Channels} {} {$XIRQ_EN} } - } - set group [add_group $page {General-Purpose Input/Output Controller (GPIO)}] add_params $group { { IO_GPIO_EN {Enable GPIO} } - { IO_GPIO_IN_NUM {Number of Inputs} {} {$IO_GPIO_EN} } + { IO_GPIO_IN_NUM {Number of Inputs} {Interrupt-capable} {$IO_GPIO_EN} } { IO_GPIO_OUT_NUM {Number of Outputs} {} {$IO_GPIO_EN} } } diff --git a/rtl/system_integration/neorv32_vivado_ip.vhd b/rtl/system_integration/neorv32_vivado_ip.vhd index 53687868e..4d3457b4d 100644 --- a/rtl/system_integration/neorv32_vivado_ip.vhd +++ b/rtl/system_integration/neorv32_vivado_ip.vhd @@ -98,13 +98,10 @@ entity neorv32_vivado_ip is XIP_CACHE_EN : boolean := false; XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; - -- External Interrupts Controller (XIRQ) -- - XIRQ_EN : boolean := false; - XIRQ_NUM_CH : natural range 1 to 32 := 1; -- variable-sized ports must be at least 0 downto 0; #974 -- Processor peripherals -- IO_GPIO_EN : boolean := false; - IO_GPIO_IN_NUM : natural range 1 to 64 := 1; -- variable-sized ports must be at least 0 downto 0; #974 - IO_GPIO_OUT_NUM : natural range 1 to 64 := 1; + IO_GPIO_IN_NUM : natural range 1 to 32 := 1; -- variable-sized ports must be at least 0 downto 0; #974 + IO_GPIO_OUT_NUM : natural range 1 to 32 := 1; IO_CLINT_EN : boolean := false; IO_UART0_EN : boolean := false; IO_UART0_RX_FIFO : natural range 1 to 2**15 := 1; @@ -254,8 +251,6 @@ entity neorv32_vivado_ip is neoled_o : out std_logic; -- Machine timer system time (available if IO_CLINT_EN = true) -- mtime_time_o : out std_logic_vector(63 downto 0); - -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- - xirq_i : in std_logic_vector(XIRQ_NUM_CH-1 downto 0) := (others => '0'); -- variable-sized ports must be at least 0 downto 0; #974 -- CPU Interrupts -- mtime_irq_i : in std_logic := '0'; msw_irq_i : in std_logic := '0'; @@ -267,7 +262,6 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is -- auto-configuration -- constant num_gpio_c : natural := cond_sel_natural_f(IO_GPIO_EN, max_natural_f(IO_GPIO_IN_NUM, IO_GPIO_OUT_NUM), 0); - constant num_xirq_c : natural := cond_sel_natural_f(XIRQ_EN, XIRQ_NUM_CH, 0); constant num_pwm_c : natural := cond_sel_natural_f(IO_PWM_EN, IO_PWM_NUM_CH, 0); -- AXI4-Lite bridge -- @@ -333,10 +327,9 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is signal mtime_time_aux : std_ulogic_vector(63 downto 0); -- constrained size ports -- - signal gpio_o_aux : std_ulogic_vector(63 downto 0); - signal gpio_i_aux : std_ulogic_vector(63 downto 0); + signal gpio_o_aux : std_ulogic_vector(31 downto 0); + signal gpio_i_aux : std_ulogic_vector(31 downto 0); signal pwm_o_aux : std_ulogic_vector(15 downto 0); - signal xirq_i_aux : std_ulogic_vector(31 downto 0); -- internal wishbone bus -- signal xbus_adr : std_ulogic_vector(31 downto 0); -- address @@ -430,8 +423,6 @@ begin XIP_CACHE_EN => XIP_CACHE_EN, XIP_CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS, XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE, - -- External Interrupts Controller -- - XIRQ_NUM_CH => num_xirq_c, -- Processor peripherals -- IO_DISABLE_SYSINFO => false, IO_GPIO_NUM => num_gpio_c, @@ -551,8 +542,6 @@ begin neoled_o => neoled_aux, -- Machine timer system time (available if IO_MTIME_EN = true) -- mtime_time_o => mtime_time_aux, - -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- - xirq_i => xirq_i_aux, -- CPU Interrupts -- mtime_irq_i => std_ulogic(mtime_irq_i), msw_irq_i => std_ulogic(msw_irq_i), @@ -627,15 +616,6 @@ begin pwm_o(i) <= std_logic(pwm_o_aux(i)); end generate; - -- XIRQ -- - xirq_mapping: process(xirq_i) - begin - xirq_i_aux <= (others => '0'); - for i in 0 to XIRQ_NUM_CH-1 loop - xirq_i_aux(i) <= std_ulogic(xirq_i(i)); - end loop; - end process xirq_mapping; - -- Wishbone-to-AXI4-Lite Bridge ----------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd index f5de05570..1b5ec48fb 100644 --- a/sim/neorv32_tb.vhd +++ b/sim/neorv32_tb.vhd @@ -79,7 +79,7 @@ architecture neorv32_tb_rtl of neorv32_tb is -- IO connection -- signal uart0_txd, uart0_cts, uart1_txd, uart1_cts : std_ulogic; - signal gpio : std_ulogic_vector(63 downto 0); + signal gpio : std_ulogic_vector(31 downto 0); signal i2c_scl, i2c_sda : std_logic; signal twi_scl_i, twi_scl_o, twi_sda_i, twi_sda_o : std_ulogic; signal twd_scl_i, twd_scl_o, twd_sda_i, twd_sda_o : std_ulogic; @@ -190,10 +190,8 @@ begin XIP_CACHE_EN => true, XIP_CACHE_NUM_BLOCKS => 4, XIP_CACHE_BLOCK_SIZE => 256, - -- External Interrupts Controller (XIRQ) -- - XIRQ_NUM_CH => 32, -- Processor peripherals -- - IO_GPIO_NUM => 64, + IO_GPIO_NUM => 32, IO_CLINT_EN => true, IO_UART0_EN => true, IO_UART0_RX_FIFO => 32, @@ -311,8 +309,6 @@ begin neoled_o => open, -- Machine timer system time -- mtime_time_o => open, - -- External platform interrupts -- - xirq_i => gpio(31 downto 0), -- CPU Interrupts -- mtime_irq_i => mti, msw_irq_i => msi, diff --git a/sw/example/demo_xirq/makefile b/sw/example/demo_gpio/Makefile similarity index 84% rename from sw/example/demo_xirq/makefile rename to sw/example/demo_gpio/Makefile index c2c0d4f9e..7715e365b 100644 --- a/sw/example/demo_xirq/makefile +++ b/sw/example/demo_gpio/Makefile @@ -2,7 +2,7 @@ # Use this makefile to configure all relevant CPU / compiler options. # Override the default CPU ISA -MARCH = rv32i_zicsr_zifencei +MARCH = rv32ia_zicsr_zifencei # Override the default RISC-V GCC prefix #RISCV_PREFIX ?= riscv-none-elf- @@ -20,7 +20,7 @@ USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k # Adjust maximum heap size -#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3k # Additional sources #APP_SRC += $(wildcard ./*.c) @@ -30,4 +30,4 @@ USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k NEORV32_HOME ?= ../../.. # Include the main NEORV32 makefile -include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file +include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_gpio/main.c b/sw/example/demo_gpio/main.c new file mode 100644 index 000000000..e0b7e25f6 --- /dev/null +++ b/sw/example/demo_gpio/main.c @@ -0,0 +1,93 @@ +// ================================================================================ // +// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // +// Copyright (c) NEORV32 contributors. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // +// Licensed under the BSD-3-Clause license, see LICENSE for details. // +// SPDX-License-Identifier: BSD-3-Clause // +// ================================================================================ // + +/**********************************************************************//** + * @file demo_gpio/main.c + * @brief GPIO input pins interrupt example. + **************************************************************************/ +#include + +/** User configuration */ +#define BAUD_RATE 19200 + + +/**********************************************************************//** + * GPIO input pin(s) interrupt handler. + **************************************************************************/ +void gpio_interrupt_handler(void) { + + // get bit mask of all those input pin that caused this interrupt + uint32_t active = neorv32_gpio_irq_get(); + + // clear the active pins that we are "handling" here + neorv32_gpio_irq_clr(active); + + // "handle" the individual pin interrupts: + // we just print the pin number of the triggering inputs + int i; + neorv32_uart0_printf("\nGPIO interrupt from pin(s): "); + for (i=0; i<32; i++) { + if (active & 1) { + neorv32_uart0_printf("%u ", i); + } + active = active >> 1; + } + neorv32_uart0_printf("\n"); +} + + +/**********************************************************************//** + * Configure GPIO input interrupt. + * + * @attention This program requires the UART0 and the GPIO controller with + * at least 1 input/output pair. + * + * @return Irrelevant (but can be inspected by the debugger). + **************************************************************************/ +int main(void) { + + // setup NEORV32 runtime-environment (RTE) + neorv32_rte_setup(); + + // setup UART0 at default baud rate, no interrupts + if (neorv32_uart0_available() == 0) { // UART0 available? + return -1; + } + neorv32_uart0_setup(BAUD_RATE, 0); + neorv32_uart0_printf("\n<< NEORV32 Simple SMP Dual-Core Demo >>\n\n"); + + // check hardware/software configuration + if (neorv32_gpio_available() == 0) { // GPIO available? + neorv32_uart0_printf("[ERROR] GPIO module not available!\n"); + return -1; + } + + // configure CPU's GPIO controller interrupt + neorv32_rte_handler_install(GPIO_RTE_ID, gpio_interrupt_handler); // install GPIO trap handler + neorv32_cpu_csr_set(CSR_MIE, 1 << GPIO_FIRQ_ENABLE); // enable GPIO FIRQ channel + neorv32_cpu_csr_set(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE); // enable machine-mode interrupts + + // configure GPIO input's IRQ trigger + int i; + for (i=0; i<32; i+=4) { + neorv32_gpio_irq_setup(i+0, GPIO_TRIG_LEVEL_LOW); // this pin's interrupt fires on low-level + neorv32_gpio_irq_setup(i+1, GPIO_TRIG_LEVEL_HIGH); // this pin's interrupt fires on high-level + neorv32_gpio_irq_setup(i+2, GPIO_TRIG_EDGE_FALLING); // this pin's interrupt fires on a falling edge + neorv32_gpio_irq_setup(i+3, GPIO_TRIG_EDGE_RISING); // this pin's interrupt fires on a rising edge + } + + // enable all GPIO input pin interrupts + neorv32_gpio_irq_enable(0xffffffff); // argument is an "enable bit mask" - one bit for each input pin + + // wait in sleep mode for interrupts + while(1) { + neorv32_cpu_sleep(); + } + + return 0; +} diff --git a/sw/example/demo_xirq/main.c b/sw/example/demo_xirq/main.c deleted file mode 100644 index ce81d3ca7..000000000 --- a/sw/example/demo_xirq/main.c +++ /dev/null @@ -1,184 +0,0 @@ -// ================================================================================ // -// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // -// Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // -// Licensed under the BSD-3-Clause license, see LICENSE for details. // -// SPDX-License-Identifier: BSD-3-Clause // -// ================================================================================ // - - -/**********************************************************************//** - * @file demo_xirq/main.c - * @author Stephan Nolting - * @brief External interrupt controller (XIRQ) demo program (using hardware-assisted prioritization). - **************************************************************************/ - -#include - - -/**********************************************************************//** - * @name User configuration - **************************************************************************/ -/**@{*/ -/** UART BAUD rate */ -#define BAUD_RATE 19200 -/**@}*/ - - -/**********************************************************************//** - * XIRQ handler channel 0. - * @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! - **************************************************************************/ -void xirq_handler_ch0(void) { - neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 0); -} - -/**********************************************************************//** - * XIRQ handler channel 1. - * @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! - **************************************************************************/ -void xirq_handler_ch1(void) { - neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 1); -} - -/**********************************************************************//** - * XIRQ handler channel 2. - * @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! - **************************************************************************/ -void xirq_handler_ch2(void) { - neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 2); -} - -/**********************************************************************//** - * XIRQ handler channel 3. - * @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! - **************************************************************************/ -void xirq_handler_ch3(void) { - neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 3); -} - - -/**********************************************************************//** - * Main function - * - * @note This program requires the XIRQ and the UART to be synthesized. - * - * @return 0 if execution was successful - **************************************************************************/ -int main() { - - // initialize the neorv32 runtime environment - // this will take care of handling all CPU traps - neorv32_rte_setup(); - - // setup UART at default baud rate, no interrupts - neorv32_uart0_setup(BAUD_RATE, 0); - - // check if XIRQ unit is implemented at all - if (neorv32_xirq_available() == 0) { - neorv32_uart0_printf("XIRQ not synthesized!\n"); - return 1; - } - - - // intro - neorv32_uart0_printf("<< External Interrupts Controller (XIRQ) Demo Program >>\n\n"); - - int err_cnt = 0; - - - // initialize XIRQ controller - // this will disable all XIRQ channels and will also clear any pending external interrupts - // (details: this will register the XIRQ's second-level interrupt handler in the NEORV32 RTE) - err_cnt = neorv32_xirq_setup(); - - // check if setup went fine - if (err_cnt) { - neorv32_uart0_printf("Error during XIRQ setup!\n"); - return 1; - } - - - // 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 - err_cnt = 0; - err_cnt += neorv32_xirq_install(0, xirq_handler_ch0); // handler function for channel 0 - err_cnt += neorv32_xirq_install(1, xirq_handler_ch1); // handler function for channel 1 - err_cnt += neorv32_xirq_install(2, xirq_handler_ch2); // handler function for channel 2 - err_cnt += neorv32_xirq_install(3, xirq_handler_ch3); // handler function for channel 3 - - // check if installation went fine - if (err_cnt) { - neorv32_uart0_printf("Error during XIRQ install!\n"); - return 1; - } - - // enable XIRQ channels - neorv32_xirq_channel_enable(0); - neorv32_xirq_channel_enable(1); - neorv32_xirq_channel_enable(2); - neorv32_xirq_channel_enable(3); - - - // allow XIRQ to trigger CPU interrupt - neorv32_xirq_global_enable(); - - // enable machine-mode interrupts - neorv32_cpu_csr_set(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE); - - - // the code below assumes the XIRQ inputs are connected to the processor's GPIO output port - // so we can trigger the IRQs from software; if you have connected the XIRQs to buttons you - // can remove the code below (note the trigger configuration using the XIRQ generics!) - { - neorv32_uart0_printf("Triggering XIRQs...\n"); - // trigger XIRQs 3:0 at once - // assumes xirq_i(31:0) <= gpio.output(31:0) - - // due to the prioritization this will execute - // 1. xirq_handler_ch0 - // 2. xirq_handler_ch1 - // 3. xirq_handler_ch2 - // 4. xirq_handler_ch3 - neorv32_gpio_port_set(0xF); // set output pins 3:0 -> trigger XIRQ 3:0 - neorv32_gpio_port_set(0x0); - } - - // All incoming XIRQ interrupt requests are "prioritized" in this example. The XIRQ FIRQ handler - // reads the ID of the interrupt with the highest priority from the XIRQ controller ("source" register) and calls the according - // handler function (installed via neorv32_xirq_install();). - - asm volatile ("nop"); - asm volatile ("nop"); - asm volatile ("nop"); - asm volatile ("nop"); - - - // just as an example: to disable certain XIRQ interrupt channels, we can - // un-install the according handler. this will also disable the according channel. - neorv32_xirq_uninstall(0); // disable XIRQ channel 0 and remove associated handler - neorv32_xirq_uninstall(1); // disable XIRQ channel 1 and remove associated handler - neorv32_xirq_uninstall(2); // disable XIRQ channel 2 and remove associated handler - neorv32_xirq_uninstall(3); // disable XIRQ channel 3 and remove associated handler - - // manually enable and disable XIRQ channels - neorv32_xirq_channel_enable(0); // enable channel 0 - neorv32_xirq_channel_disable(0); // disable channel 0 - - // globally enable/disable XIRQ CPU interrupt - // this will not affect the XIRQ configuration / pending interrupts - neorv32_xirq_global_enable(); - neorv32_xirq_global_disable(); - - neorv32_uart0_printf("Program completed.\n"); - - return 0; -} \ No newline at end of file diff --git a/sw/example/processor_check/main.c b/sw/example/processor_check/main.c index eb14f6f21..951acd965 100644 --- a/sw/example/processor_check/main.c +++ b/sw/example/processor_check/main.c @@ -64,8 +64,7 @@ void vectored_global_handler(void); void vectored_mei_handler(void); void hw_breakpoint_handler(void); void trigger_module_dummy(void); -void xirq_trap_handler0(void); -void xirq_trap_handler1(void); +void gpio_trap_handler(void); void test_ok(void); void test_fail(void); int core1_main(void); @@ -79,7 +78,7 @@ volatile int cnt_ok = 0; // global counter for successful tests volatile int cnt_test = 0; // global counter for total number of tests volatile uint32_t num_hpm_cnts_global = 0; // global number of available hpms volatile int vectored_mei_handler_ack = 0; // vectored mei trap handler acknowledge -volatile uint32_t xirq_trap_handler_ack = 0; // xirq trap handler acknowledge +volatile uint32_t gpio_trap_handler_ack = 0; // gpio trap handler acknowledge volatile uint32_t hw_brk_mscratch_ok = 0; // set when mepc was correct in trap handler volatile uint32_t constr_test = 0; // for constructor test @@ -1337,33 +1336,33 @@ int main() { // ---------------------------------------------------------- - // Fast interrupt channel 8 (XIRQ) + // Fast interrupt channel 8 (GPIO) // ---------------------------------------------------------- neorv32_cpu_csr_write(CSR_MCAUSE, mcause_never_c); - PRINT_STANDARD("[%i] FIRQ8 (XIRQ) ", cnt_test); + PRINT_STANDARD("[%i] FIRQ8 (GPIO) ", cnt_test); - if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_XIRQ)) { + if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_GPIO)) { cnt_test++; - int xirq_err_cnt = 0; - xirq_trap_handler_ack = 0; + gpio_trap_handler_ack = 0; + neorv32_gpio_port_set(0b0101); - neorv32_gpio_port_set(0); + // install GPIO input trap handler and enable GPIO IRQ source + neorv32_rte_handler_install(GPIO_RTE_ID, gpio_trap_handler); + neorv32_cpu_csr_set(CSR_MIE, 1 << GPIO_FIRQ_ENABLE); + neorv32_cpu_csr_set(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE); - 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 - neorv32_xirq_channel_enable(0); // enable XIRQ channel 0 - neorv32_xirq_channel_enable(1); // enable XIRQ channel 1 + // setup triggers for the first 4 input pins + neorv32_gpio_irq_setup(0, GPIO_TRIG_LEVEL_LOW); + neorv32_gpio_irq_setup(1, GPIO_TRIG_LEVEL_HIGH); + neorv32_gpio_irq_setup(2, GPIO_TRIG_EDGE_FALLING); + neorv32_gpio_irq_setup(3, GPIO_TRIG_EDGE_RISING); - // enable XIRQ FIRQ - neorv32_cpu_csr_write(CSR_MIE, 1 << XIRQ_FIRQ_ENABLE); + // enable input pin interrupts + neorv32_gpio_irq_enable((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); - // trigger XIRQ channel 1 and 0 - neorv32_gpio_port_set(3); - neorv32_gpio_port_set(0); + // trigger interrupts of first 4 inputs + neorv32_gpio_port_toggle(-1); // wait for interrupt asm volatile ("nop"); @@ -1371,9 +1370,8 @@ int main() { neorv32_cpu_csr_write(CSR_MIE, 0); - if ((neorv32_cpu_csr_read(CSR_MCAUSE) == XIRQ_TRAP_CODE) && // FIRQ8 IRQ - (xirq_err_cnt == 0) && // no errors during XIRQ configuration - (xirq_trap_handler_ack == 4)) { // XIRQ channel handler 0 executed before handler 1 + if ((neorv32_cpu_csr_read(CSR_MCAUSE) == GPIO_TRAP_CODE) && // GPIO IRQ + (gpio_trap_handler_ack == 0x0000000f)) { // input 0..3 all fired test_ok(); } else { @@ -2365,20 +2363,13 @@ void __attribute__ ((noinline,naked,aligned(4))) trigger_module_dummy(void) { /**********************************************************************//** - * XIRQ handler channel 0. - **************************************************************************/ -void xirq_trap_handler0(void) { - - xirq_trap_handler_ack += 2; -} - - -/**********************************************************************//** - * XIRQ handler channel 1. + * GPIO input interrupt handler . **************************************************************************/ -void xirq_trap_handler1(void) { +void gpio_trap_handler(void) { - xirq_trap_handler_ack *= 2; + gpio_trap_handler_ack = neorv32_gpio_irq_get(); // get currently pending pin interrupts + neorv32_gpio_irq_clr(gpio_trap_handler_ack); // clear currently pending pin interrupts + neorv32_gpio_irq_disable(-1); // disable all input pin interrupts } diff --git a/sw/lib/include/neorv32.h b/sw/lib/include/neorv32.h index 24b8bcc57..72c289e94 100644 --- a/sw/lib/include/neorv32.h +++ b/sw/lib/include/neorv32.h @@ -9,8 +9,6 @@ /** * @file neorv32.h * @brief Main NEORV32 core library / driver / HAL include file. - * - * @see https://stnolting.github.io/neorv32/sw/files.html */ #ifndef neorv32_h @@ -61,7 +59,7 @@ extern "C" { #define NEORV32_PWM_BASE (0xFFF00000U) /**< Pulse Width Modulation Controller (PWM) */ #define NEORV32_GPTMR_BASE (0xFFF10000U) /**< General Purpose Timer (GPTMR) */ #define NEORV32_ONEWIRE_BASE (0xFFF20000U) /**< 1-Wire Interface Controller (ONEWIRE) */ -#define NEORV32_XIRQ_BASE (0xFFF30000U) /**< External Interrupt Controller (XIRQ) */ +//#define NEORV32_???_BASE (0xFFF30000U) /**< reserved */ #define NEORV32_CLINT_BASE (0xFFF40000U) /**< Core Local Interruptor (CLINT) */ #define NEORV32_UART0_BASE (0xFFF50000U) /**< Primary Universal Asynchronous Receiver and Transmitter (UART0) */ #define NEORV32_UART1_BASE (0xFFF60000U) /**< Secondary Universal Asynchronous Receiver and Transmitter (UART1) */ @@ -131,12 +129,12 @@ extern "C" { #define TWI_RTE_ID RTE_TRAP_FIRQ_7 /**< RTE entry code (#NEORV32_RTE_TRAP_enum) */ #define TWI_TRAP_CODE TRAP_CODE_FIRQ_7 /**< MCAUSE CSR trap code (#NEORV32_EXCEPTION_CODES_enum) */ /**@}*/ -/** @name External Interrupt Controller (XIRQ) */ +/** @name General Purpose Input/Output Controller (GPIO) */ /**@{*/ -#define XIRQ_FIRQ_ENABLE CSR_MIE_FIRQ8E /**< MIE CSR bit (#NEORV32_CSR_MIE_enum) */ -#define XIRQ_FIRQ_PENDING CSR_MIP_FIRQ8P /**< MIP CSR bit (#NEORV32_CSR_MIP_enum) */ -#define XIRQ_RTE_ID RTE_TRAP_FIRQ_8 /**< RTE entry code (#NEORV32_RTE_TRAP_enum) */ -#define XIRQ_TRAP_CODE TRAP_CODE_FIRQ_8 /**< MCAUSE CSR trap code (#NEORV32_EXCEPTION_CODES_enum) */ +#define GPIO_FIRQ_ENABLE CSR_MIE_FIRQ8E /**< MIE CSR bit (#NEORV32_CSR_MIE_enum) */ +#define GPIO_FIRQ_PENDING CSR_MIP_FIRQ8P /**< MIP CSR bit (#NEORV32_CSR_MIP_enum) */ +#define GPIO_RTE_ID RTE_TRAP_FIRQ_8 /**< RTE entry code (#NEORV32_RTE_TRAP_enum) */ +#define GPIO_TRAP_CODE TRAP_CODE_FIRQ_8 /**< MCAUSE CSR trap code (#NEORV32_EXCEPTION_CODES_enum) */ /**@}*/ /** @name Smart LED Controller (NEOLED) */ /**@{*/ @@ -281,7 +279,6 @@ typedef union { #include "neorv32_uart.h" #include "neorv32_wdt.h" #include "neorv32_xip.h" -#include "neorv32_xirq.h" #ifdef __cplusplus diff --git a/sw/lib/include/neorv32_gpio.h b/sw/lib/include/neorv32_gpio.h index fb8097e71..0568a70ec 100644 --- a/sw/lib/include/neorv32_gpio.h +++ b/sw/lib/include/neorv32_gpio.h @@ -9,10 +9,6 @@ /** * @file neorv32_gpio.h * @brief General purpose input/output port unit (GPIO) HW driver header file. - * - * @note These functions should only be used if the GPIO unit was synthesized (IO_GPIO_EN = true). - * - * @see https://stnolting.github.io/neorv32/sw/files.html */ #ifndef neorv32_gpio_h @@ -27,8 +23,13 @@ /**@{*/ /** GPIO module prototype */ typedef volatile struct __attribute__((packed,aligned(4))) { - const uint32_t INPUT[2]; /**< offset 0: parallel input port, read-only */ - uint32_t OUTPUT[2]; /**< offset 8: parallel output port */ + const uint32_t PORT_IN; /**< parallel input port, read-only */ + uint32_t PORT_OUT; /**< parallel output port */ + const uint32_t reserved[2]; /**< reserved */ + uint32_t IRQ_TYPE; /**< trigger type (#GPIO_TRIGGER_enum MSB) */ + uint32_t IRQ_POLARITY; /**< trigger polarity (#GPIO_TRIGGER_enum LSB) */ + uint32_t IRQ_ENABLE; /**< interrupt enable */ + uint32_t IRQ_PENDING; /**< interrupt pending */ } neorv32_gpio_t; /** GPIO module hardware access (#neorv32_gpio_t) */ @@ -36,6 +37,17 @@ typedef volatile struct __attribute__((packed,aligned(4))) { /**@}*/ +/**********************************************************************//** + * @name Trigger types + **************************************************************************/ +enum GPIO_TRIGGER_enum { + GPIO_TRIG_LEVEL_LOW = 0b00, // low-level + GPIO_TRIG_LEVEL_HIGH = 0b01, // high-level + GPIO_TRIG_EDGE_FALLING = 0b10, // falling-edge + GPIO_TRIG_EDGE_RISING = 0b11 // rising-edge +}; + + /**********************************************************************//** * @name Prototypes **************************************************************************/ @@ -44,9 +56,14 @@ int neorv32_gpio_available(void); void neorv32_gpio_pin_set(int pin, int value); void neorv32_gpio_pin_toggle(int pin); uint32_t neorv32_gpio_pin_get(int pin); -void neorv32_gpio_port_set(uint64_t d); -void neorv32_gpio_port_toggle(uint64_t toggle); -uint64_t neorv32_gpio_port_get(void); +void neorv32_gpio_port_set(uint32_t pin_mask); +void neorv32_gpio_port_toggle(uint32_t pin_mask); +uint32_t neorv32_gpio_port_get(void); +void neorv32_gpio_irq_setup(int pin, int trigger); +void neorv32_gpio_irq_enable(uint32_t pin_mask); +void neorv32_gpio_irq_disable(uint32_t pin_mask); +uint32_t neorv32_gpio_irq_get(void); +void neorv32_gpio_irq_clr(uint32_t pin_mask); /**@}*/ diff --git a/sw/lib/include/neorv32_sysinfo.h b/sw/lib/include/neorv32_sysinfo.h index ad58e28bd..a8db2b5c8 100644 --- a/sw/lib/include/neorv32_sysinfo.h +++ b/sw/lib/include/neorv32_sysinfo.h @@ -70,7 +70,7 @@ enum NEORV32_SYSINFO_SOC_enum { SYSINFO_SOC_IO_SDI = 24, /**< SYSINFO_SOC (24) (r/-): Serial data interface implemented when 1 (via IO_SDI_EN generic) */ SYSINFO_SOC_IO_UART1 = 25, /**< SYSINFO_SOC (25) (r/-): Secondary universal asynchronous receiver/transmitter 1 implemented when 1 (via IO_UART1_EN generic) */ SYSINFO_SOC_IO_NEOLED = 26, /**< SYSINFO_SOC (26) (r/-): NeoPixel-compatible smart LED interface implemented when 1 (via IO_NEOLED_EN generic) */ - SYSINFO_SOC_IO_XIRQ = 27, /**< SYSINFO_SOC (27) (r/-): External interrupt controller implemented when 1 (via XIRQ_NUM_IO generic) */ + SYSINFO_SOC_IO_GPTMR = 28, /**< SYSINFO_SOC (28) (r/-): General purpose timer implemented when 1 (via IO_GPTMR_EN generic) */ SYSINFO_SOC_IO_SLINK = 29, /**< SYSINFO_SOC (29) (r/-): Stream link interface implemented when 1 (via IO_SLINK_EN generic) */ SYSINFO_SOC_IO_ONEWIRE = 30, /**< SYSINFO_SOC (30) (r/-): 1-wire interface controller implemented when 1 (via IO_ONEWIRE_EN generic) */ diff --git a/sw/lib/include/neorv32_xirq.h b/sw/lib/include/neorv32_xirq.h deleted file mode 100644 index c160118b8..000000000 --- a/sw/lib/include/neorv32_xirq.h +++ /dev/null @@ -1,67 +0,0 @@ -// ================================================================================ // -// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // -// Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // -// Licensed under the BSD-3-Clause license, see LICENSE for details. // -// SPDX-License-Identifier: BSD-3-Clause // -// ================================================================================ // - -/** - * @file neorv32_xirq.h - * @brief External Interrupt controller HW driver header file. - * - * @see https://stnolting.github.io/neorv32/sw/files.html - */ - -#ifndef neorv32_xirq_h -#define neorv32_xirq_h - -#include - - -/**********************************************************************//** - * @name IO Device: External Interrupt Controller (XIRQ) - **************************************************************************/ -/**@{*/ -/** XIRQ module prototype */ -typedef volatile struct __attribute__((packed,aligned(4))) { - uint32_t EIE; /**< offset 0: external interrupt enable register */ - uint32_t ESC; /**< offset 4: external interrupt source register */ - uint32_t TTYP; /**< offset 8: external interrupt source register */ - uint32_t TPOL; /**< offset 12: external interrupt source register */ -} neorv32_xirq_t; - -/** XIRQ module hardware access (#neorv32_xirq_t) */ -#define NEORV32_XIRQ ((neorv32_xirq_t*) (NEORV32_XIRQ_BASE)) -/**@}*/ - - -/**********************************************************************//** - * XIRQ trigger type configuration - **************************************************************************/ -enum XIRQ_TRIGGER_enum { - XIRQ_TRIGGER_LEVEL_LOW = 0b00, // low-level - XIRQ_TRIGGER_LEVEL_HIGH = 0b01, // high-level - XIRQ_TRIGGER_EDGE_FALLING = 0b10, // falling-edge - XIRQ_TRIGGER_EDGE_RISING = 0b11 // rising-edge -}; - - -/**********************************************************************//** - * @name Prototypes - **************************************************************************/ -/**@{*/ -int neorv32_xirq_available(void); -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_channel_enable(int channel); -void neorv32_xirq_channel_disable(int channel); -int neorv32_xirq_install(int channel, void (*handler)(void)); -int neorv32_xirq_uninstall(int channel); -/**@}*/ - - -#endif // neorv32_xirq_h diff --git a/sw/lib/source/neorv32_aux.c b/sw/lib/source/neorv32_aux.c index ab98fb5ad..f7f7c543a 100644 --- a/sw/lib/source/neorv32_aux.c +++ b/sw/lib/source/neorv32_aux.c @@ -527,7 +527,6 @@ void neorv32_aux_print_hw_config(void) { if (tmp & (1 << SYSINFO_SOC_IO_UART1)) { neorv32_uart0_printf("UART1 "); } if (tmp & (1 << SYSINFO_SOC_IO_WDT)) { neorv32_uart0_printf("WDT "); } if (tmp & (1 << SYSINFO_SOC_XIP)) { neorv32_uart0_printf("XIP "); } - if (tmp & (1 << SYSINFO_SOC_IO_XIRQ)) { neorv32_uart0_printf("XIRQ "); } neorv32_uart0_printf("\n\n"); } diff --git a/sw/lib/source/neorv32_gpio.c b/sw/lib/source/neorv32_gpio.c index 2bb0b86b2..2ee228c0e 100644 --- a/sw/lib/source/neorv32_gpio.c +++ b/sw/lib/source/neorv32_gpio.c @@ -1,7 +1,7 @@ // ================================================================================ // // The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // // Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // // Licensed under the BSD-3-Clause license, see LICENSE for details. // // SPDX-License-Identifier: BSD-3-Clause // // ================================================================================ // @@ -9,10 +9,7 @@ /** * @file neorv32_gpio.c * @brief General purpose input/output port unit (GPIO) HW driver source file. - * - * @note These functions should only be used if the GPIO unit was synthesized (IO_GPIO_EN = true). - * - * @see https://stnolting.github.io/neorv32/sw/files.html +#include */ #include @@ -37,19 +34,18 @@ int neorv32_gpio_available(void) { /**********************************************************************//** * Set single pin of GPIO's output port. * - * @param[in] pin Output pin number to be set (0..63). + * @param[in] pin Output pin number to be set (0..31). * @param[in] value Set pint high (1) or low (0). **************************************************************************/ void neorv32_gpio_pin_set(int pin, int value) { - uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); - int lohi = (pin < 32) ? 0 : 1; + uint32_t mask = (uint32_t)(1 << pin); if (value) { - NEORV32_GPIO->OUTPUT[lohi] |= mask; + NEORV32_GPIO->PORT_OUT |= mask; } else { - NEORV32_GPIO->OUTPUT[lohi] &= ~mask; + NEORV32_GPIO->PORT_OUT &= ~mask; } } @@ -57,71 +53,126 @@ void neorv32_gpio_pin_set(int pin, int value) { /**********************************************************************//** * Toggle single pin of GPIO's output port. * - * @param[in] pin Output pin number to be toggled (0..63). + * @param[in] pin Output pin number to be toggled (0..31). **************************************************************************/ void neorv32_gpio_pin_toggle(int pin) { - uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); - int lohi = (pin < 32) ? 0 : 1; - NEORV32_GPIO->OUTPUT[lohi] ^= mask; + NEORV32_GPIO->PORT_OUT ^= (uint32_t)(1 << pin); } /**********************************************************************//** * Get single pin of GPIO's input port. * - * @param[in] pin Input pin to be read (0..63). - * @return =0 if pin is low, !=0 if pin is high. + * @param[in] pin Input pin to be read (0..31). + * @return zero if pin is low, non-zero if pin is high. **************************************************************************/ uint32_t neorv32_gpio_pin_get(int pin) { - uint32_t mask = (uint32_t)(1 << (pin & 0x1f)); - int lohi = (pin < 32) ? 0 : 1; - return NEORV32_GPIO->INPUT[lohi] & mask; + return NEORV32_GPIO->PORT_IN & (uint32_t)(1 << pin); } /**********************************************************************//** * Set complete GPIO output port. * - * @param[in] port_data New output port value (64-bit). + * @param[in] pin_mask New output port value (32-bit). **************************************************************************/ -void neorv32_gpio_port_set(uint64_t port_data) { +void neorv32_gpio_port_set(uint32_t pin_mask) { - subwords64_t data; - - data.uint64 = port_data; - NEORV32_GPIO->OUTPUT[0] = data.uint32[0]; - NEORV32_GPIO->OUTPUT[1] = data.uint32[1]; + NEORV32_GPIO->PORT_OUT = pin_mask; } /**********************************************************************//** * Toggle bit in entire GPIO output port. * - * @param[in] toggle Bit mask; set bits will toggle the according output port (64-bit). + * @param[in] pin_mask Bit mask; set bits will toggle the according output pins (32-bit). **************************************************************************/ -void neorv32_gpio_port_toggle(uint64_t toggle) { - - subwords64_t data; +void neorv32_gpio_port_toggle(uint32_t pin_mask) { - data.uint64 = toggle; - NEORV32_GPIO->OUTPUT[0] ^= data.uint32[0]; - NEORV32_GPIO->OUTPUT[1] ^= data.uint32[1]; + NEORV32_GPIO->PORT_OUT ^= pin_mask; } /**********************************************************************//** * Get complete GPIO input port. * - * @return Current input port state (64-bit). + * @return Current input port state (32-bit). + **************************************************************************/ +uint32_t neorv32_gpio_port_get(void) { + + return NEORV32_GPIO->PORT_IN; +} + + +/**********************************************************************//** + * Configure pin interrupt trigger. + * + * @param[in] pin Input pin select (0..31). + * @param[in] trigger Trigger select (#GPIO_TRIGGER_enum). + **************************************************************************/ +void neorv32_gpio_irq_setup(int pin, int trigger) { + + uint32_t mask = (uint32_t)(1 << pin); + + // trigger type + if ((trigger == GPIO_TRIG_EDGE_FALLING) || (trigger == GPIO_TRIG_EDGE_RISING)) { + NEORV32_GPIO->IRQ_TYPE |= mask; // set = edge + } + else { + NEORV32_GPIO->IRQ_TYPE &= ~mask; // clear = level + } + + // polarity type + if ((trigger == GPIO_TRIG_EDGE_RISING) || (trigger == GPIO_TRIG_LEVEL_HIGH)) { + NEORV32_GPIO->IRQ_POLARITY |= mask; // set = rising edge / high level + } + else { + NEORV32_GPIO->IRQ_POLARITY &= ~mask; // clear = falling edge / low level + } +} + + +/**********************************************************************//** + * Enable input pin interrupt(s). + * + * @param[in] pin_mask Pin-IRQ enable mask (set to 1 to enable the according pin). + **************************************************************************/ +void neorv32_gpio_irq_enable(uint32_t pin_mask) { + + NEORV32_GPIO->IRQ_ENABLE |= pin_mask; +} + + +/**********************************************************************//** + * Disable input pin interrupt(s). + * + * @param[in] pin_mask Pin-IRQ enable mask (set to 1 to disable the according pin). **************************************************************************/ -uint64_t neorv32_gpio_port_get(void) { +void neorv32_gpio_irq_disable(uint32_t pin_mask) { - subwords64_t data; + NEORV32_GPIO->IRQ_ENABLE &= ~pin_mask; +} - data.uint32[0] = NEORV32_GPIO->INPUT[0]; - data.uint32[1] = NEORV32_GPIO->INPUT[1]; - return data.uint64; +/**********************************************************************//** + * Get currently pending GPIO input interrupts. + * + * @param[in] Pending inputs (bit mask; high = pending). + **************************************************************************/ +uint32_t neorv32_gpio_irq_get(void) { + + return NEORV32_GPIO->IRQ_PENDING; +} + + +/**********************************************************************//** + * Clear pending GPIO input interrupts via bit mask. + * + * @param[in] clr_mask Clear mask (bit high = clear according pending interrupt). + **************************************************************************/ +void neorv32_gpio_irq_clr(uint32_t clr_mask) { + + NEORV32_GPIO->IRQ_PENDING = ~clr_mask; } diff --git a/sw/lib/source/neorv32_xirq.c b/sw/lib/source/neorv32_xirq.c deleted file mode 100644 index 81fde4182..000000000 --- a/sw/lib/source/neorv32_xirq.c +++ /dev/null @@ -1,251 +0,0 @@ -// ================================================================================ // -// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // -// Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // -// Licensed under the BSD-3-Clause license, see LICENSE for details. // -// SPDX-License-Identifier: BSD-3-Clause // -// ================================================================================ // - -/** - * @file neorv32_xirq.c - * @brief External Interrupt controller HW driver source file. - * - * @note These functions should only be used if the XIRQ controller was synthesized. - * - * @see https://stnolting.github.io/neorv32/sw/files.html - */ - -#include - - -// the private trap vector look-up table -static uint32_t __neorv32_xirq_vector_lut[32] __attribute__((unused)); - -// private functions -static void __neorv32_xirq_core(void); -static void __neorv32_xirq_dummy_handler(void); - - -/**********************************************************************//** - * Check if external interrupt controller was synthesized. - * - * @return 0 if XIRQ was not synthesized, 1 if EXTIRQ is available. - **************************************************************************/ -int neorv32_xirq_available(void) { - - if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_XIRQ)) { - return 1; - } - else { - return 0; - } -} - - -/**********************************************************************//** - * Initialize XIRQ controller. - * - * @note All interrupt channels will be deactivated and all installed - * handlers addresses will be deleted. - * - * @return 0 if success, != 0 if error. - **************************************************************************/ -int neorv32_xirq_setup(void) { - - NEORV32_XIRQ->EIE = 0; // disable all channels - NEORV32_XIRQ->ESC = 0; // acknowledge (clear) XIRQ interrupt - - int i; - for (i=0; i<32; i++) { - __neorv32_xirq_vector_lut[i] = (uint32_t)(&__neorv32_xirq_dummy_handler); - } - - // register XIRQ handler in NEORV32 RTE - return neorv32_rte_handler_install(XIRQ_RTE_ID, __neorv32_xirq_core); -} - - -/**********************************************************************//** - * Globally enable XIRQ interrupts (via according FIRQ channel). - * - * @note Triggered / triggering XIRQ will remain pending. - **************************************************************************/ -void neorv32_xirq_global_enable(void) { - - // enable XIRQ fast interrupt channel - neorv32_cpu_csr_set(CSR_MIE, 1 << XIRQ_FIRQ_ENABLE); -} - - -/**********************************************************************//** - * Globally disable XIRQ interrupts (via according FIRQ channel). - * - * @note Triggered / triggering XIRQ will remain pending. - **************************************************************************/ -void neorv32_xirq_global_disable(void) { - - // enable XIRQ fast interrupt channel - neorv32_cpu_csr_clr(CSR_MIE, 1 << XIRQ_FIRQ_ENABLE); -} - - -/**********************************************************************//** - * Get number of implemented XIRQ channels - * - * @return Number of implemented channels (0..32). - **************************************************************************/ -int neorv32_xirq_get_num(void) { - - uint32_t prev_mie, prev_xirq_eie, mask; - int i, cnt; - - if (neorv32_xirq_available()) { - - // save previous registers - prev_mie = neorv32_cpu_csr_read(CSR_MIE); - prev_xirq_eie = NEORV32_XIRQ->EIE; - - neorv32_cpu_csr_clr(CSR_MIE, 1 << XIRQ_FIRQ_ENABLE); // make sure XIRQ cannot fire - NEORV32_XIRQ->EIE = 0xffffffffU; // try to set all enable bits - mask = NEORV32_XIRQ->EIE; // read back actually set flags - - // restore previous registers - NEORV32_XIRQ->EIE = prev_xirq_eie; - neorv32_cpu_csr_write(CSR_MIE, prev_mie); - - // count set bits - cnt = 0; - for (i=0; i<32; i++) { - cnt += mask & 1; - mask >>= 1; - } - return cnt; - } - else { - return 0; - } -} - - -/**********************************************************************//** - * Configure a channel's trigger type. - * - * @param[in] channel XIRQ interrupt channel (0..31). - * @param[in] config Trigger type (#XIRQ_TRIGGER_enum). - **************************************************************************/ -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; -} - - -/**********************************************************************//** - * Enable IRQ channel. - * - * @param[in] channel XIRQ interrupt channel (0..31). - **************************************************************************/ -void neorv32_xirq_channel_enable(int channel) { - - NEORV32_XIRQ->EIE |= 1 << (channel & 0x1f); -} - - -/**********************************************************************//** - * Disable IRQ channel. - * - * @param[in] channel XIRQ interrupt channel (0..31). - **************************************************************************/ -void neorv32_xirq_channel_disable(int channel) { - - NEORV32_XIRQ->EIE &= ~(1 << (channel & 0x1f)); -} - - -/**********************************************************************//** - * Install interrupt handler function for XIRQ channel. - * - * @param[in] channel XIRQ interrupt channel (0..31). - * @param[in] handler The actual handler function for the specified interrupt; - * function has to be of type "void function(void)". - * @return 0 if success, -1 if invalid channel. - **************************************************************************/ -int neorv32_xirq_install(int channel, void (*handler)(void)) { - - // channel valid? - if (channel < 32) { - __neorv32_xirq_vector_lut[channel] = (uint32_t)handler; // install handler - return 0; - } - else { - return -1; - } -} - - -/**********************************************************************//** - * Uninstall interrupt handler function for XIRQ channel. - * - * @note This will also deactivate the according XIRQ channel. - * - * @param[in] channel XIRQ interrupt channel (0..31). - * @return 0 if success, -1 if invalid channel. - **************************************************************************/ -int neorv32_xirq_uninstall(int channel) { - - // channel valid? - if (channel < 32) { - __neorv32_xirq_vector_lut[channel] = (uint32_t)(&__neorv32_xirq_dummy_handler); // override using dummy handler - neorv32_xirq_channel_disable(channel); // disable channel - return 0; - } - else { - return -1; - } -} - - -/**********************************************************************//** - * This is the actual second-level (F)IRQ handler for the XIRQ. It will - * call the previously installed handler if an XIRQ fires. - * - * @note The XIRQ's channel interrupt is acknowledge AFTER the handler has been executed. - **************************************************************************/ -static void __neorv32_xirq_core(void) { - - // get highest-priority XIRQ channel - uint32_t src = NEORV32_XIRQ->ESC & 0x1f; // mask for channel ID - - // execute handler - typedef void handler_t(); - handler_t* handler = (handler_t*)__neorv32_xirq_vector_lut[src]; - handler(); - - // acknowledge XIRQ channel interrupt - NEORV32_XIRQ->ESC = 0; -} - - -/**********************************************************************//** - * XIRQ dummy handler. - **************************************************************************/ -static void __neorv32_xirq_dummy_handler(void) { - - asm volatile ("nop"); -} diff --git a/sw/svd/neorv32.svd b/sw/svd/neorv32.svd index 0e564199d..1398b3a4e 100644 --- a/sw/svd/neorv32.svd +++ b/sw/svd/neorv32.svd @@ -847,45 +847,6 @@ - - - - XIRQ - External interrupts controller - 0xFFF30000 - - XIRQ_FIRQ8 - - - 0 - 0x14 - registers - - - - - EIE - External IRQ channel enable register - 0x00 - - - ESC - External IRQ source register - 0x04 - - - TTYP - External IRQ trigger type (level/edge) - 0x08 - - - TPOL - External IRQ trigger polarity (high/low, rising/falling) - 0x0c - - - - @@ -1600,34 +1561,45 @@ General purpose input/output port 0xFFFC0000 + GPIO_FIRQ8 + 0 - 0x10 + 0x20 registers - INPUT[0] - Parallel input register - low + PORT_IN + Parallel input port 0x00 read-only - INPUT[1] - Parallel input register - high + PORT_OUT + Parallel output port 0x04 - read-only - OUTPUT[0] - Parallel output register - low - 0x08 + IRQ_TYPE + Interrupt trigger type (level/edge) for each input pin + 0x10 - OUTPUT[1] - Parallel output register - high - 0x0C + IRQ_POLARITY + Interrupt trigger polarity (rising/falling or high/low) for each input pin + 0x14 + + + IRQ_ENABLE + Interrupt enable for each input pin + 0x18 + + + IRQ_PENDING + Interrupt pending for each input pin; cleared by writing zero + 0x1C @@ -1796,7 +1768,6 @@ SYSINFO_SOC_IO_SDI[24:24]Serial data interface implemented SYSINFO_SOC_IO_UART1[25:25]Secondary universal asynchronous receiver/transmitter 1 implemented SYSINFO_SOC_IO_NEOLED[26:26]NeoPixel-compatible smart LED interface implemented - SYSINFO_SOC_IO_XIRQ[27:27]External interrupt controller implemented SYSINFO_SOC_IO_GPTMR[28:28]General purpose timer implemented SYSINFO_SOC_IO_SLINK[29:29]Stream link interface implemented SYSINFO_SOC_IO_ONEWIRE[30:30]1-wire interface controller implemented