Rework high interrupt code to be able to link to external handlers; add psram test that swarms cpu with interrupts

This commit is contained in:
Jeroen Domburg 2017-03-21 17:01:25 +08:00
parent b63921a99c
commit 202a5db2d2
11 changed files with 365 additions and 283 deletions

View file

@ -25,7 +25,7 @@
#include "esp_system.h"
#endif
const char *TAG = "boot_rng";
static const char *TAG = "boot_rng";
void bootloader_fill_random(void *buffer, size_t length)
{

View file

@ -165,6 +165,13 @@ config SPIRAM_CACHE_WORKAROUND
when the cache line needs to be fetched from external RAM and an interrupt occurs. This enables a
fix in the compiler that makes sure the specific code that is vulnerable to this will not be emitted.
config SPIRAM_CACHE_WORKAROUND_TEST
bool "Debug: Test workaround by generating a lot of interrupts"
default "n"
help
This setting helps testing the SPIRAM cache workaround. It generates a lot of interrupts so
the bug, if still existing, triggers quicker.
choice MEMMAP_SPIRAM_TYPE
prompt "Type of SPI RAM chip in use"
default MEMMAP_SPIRAM_TYPE_ESPPSRAM32

View file

@ -31,6 +31,8 @@ COMPONENT_ADD_LDFLAGS := -lesp32 \
$(addprefix -l,$(LIBS)) \
-L $(COMPONENT_PATH)/ld \
-T esp32_out.ld \
-u ld_include_panic_highint_hdl \
-u ld_include_psram_tst \
$(addprefix -T ,$(LINKER_SCRIPTS))
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))

View file

@ -64,6 +64,7 @@
#include "esp_app_trace.h"
#include "esp_clk.h"
#include "trax.h"
#include "esp_psram_tst.h"
#include "esp_psram.h"
@ -278,6 +279,10 @@ void start_cpu0_default(void)
esp_core_dump_init();
#endif
#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST
psram_tst_setup();
#endif
xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0);
@ -306,6 +311,9 @@ void start_cpu1_default(void)
esp_cache_err_int_init();
esp_crosscore_int_init();
esp_dport_access_int_init();
#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST
psram_tst_setup();
#endif
ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
xPortStartScheduler();

View file

@ -0,0 +1,3 @@
void psram_tst_setup();

View file

@ -0,0 +1,119 @@
#include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include <xtensa/simcall.h>
#include "freertos/xtensa_context.h"
#include "esp_panic.h"
#include "sdkconfig.h"
#include "soc/soc.h"
/*
In some situations, the panic handler needs to be invoked even when (low/medium priority) interrupts
are disabled. In that case, we use a high interrupt to panic anyway. This is the high-level interrupt
handler for such a situation.
*/
.section .iram1,"ax"
.type xt_highint4,@function
.align 4
xt_highint4:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 4<<2
beqz a0, 1f
.Ln_xt_highint4_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* On the ESP32, this level is used for panic events that are detected by hardware and should
also panic when interrupts are disabled. At the moment, these are the interrupt watchdog
as well as the cache invalid access interrupt. (24 and 25) */
/* Allocate exception frame and save minimal context. */
mov a0, sp
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_A1
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -12 /* for debug backtrace */
#endif
rsr a0, PS /* save interruptee's PS */
s32i a0, sp, XT_STK_PS
rsr a0, EPC_4 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -16 /* for debug backtrace */
#endif
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
call0 _xt_context_save
/* Save vaddr into exception frame */
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
/* Figure out reason, save into EXCCAUSE reg */
rsr a0, INTERRUPT
extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */
beqz a0, 1f
/* Kill this interrupt; we cannot reset it. */
rsr a0, INTENABLE
movi a4, ~(1<<ETS_CACHEERR_INUM)
and a0, a4, a0
wsr a0, INTENABLE
movi a0, PANIC_RSN_CACHEERR
j 9f
1:
#if CONFIG_INT_WDT_CHECK_CPU1
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 2f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
j 9f
2:
#endif
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
9:
/* Found the reason, now save it. */
s32i a0, sp, XT_STK_EXCCAUSE
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_4 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler
mov a6,sp
call4 panicHandler
call0 _xt_context_restore
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
wsr a0, PS
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
wsr a0, EPC_1
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
l32i sp, sp, XT_STK_A1 /* remove exception frame */
rsync /* ensure PS and EPC written */
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
/* The linker has no reason to link in this file; all symbols it exports are already defined
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
linker inspect this anyway. */
.global ld_include_panic_highint_hdl
ld_include_panic_highint_hdl:

View file

@ -0,0 +1,43 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <esp_types.h>
#include "esp_err.h"
#include "esp_intr.h"
#include "esp_attr.h"
#include "esp_freertos_hooks.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "xtensa/core-macros.h"
#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST
void psram_tst_setup() {
esp_err_t err;
XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT()+1000);
err=esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_IRAM, NULL, NULL, NULL);
assert(err==ESP_OK);
}
#endif

View file

@ -0,0 +1,36 @@
#include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include <xtensa/simcall.h>
#include "esp_panic.h"
#include "sdkconfig.h"
#include "soc/soc.h"
#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST
.section .iram1,"ax"
.global xt_highint5
.type xt_highint5,@function
.align 4
xt_highint5:
esync
rsr a0, CCOUNT
addi a0, a0, 40
wsr a0, CCOMPARE2
esync
.L_xt_highint5_exit:
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#endif
/* The linker has no reason to link in this file; all symbols it exports are already defined
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
linker inspect this anyway. */
.global ld_include_psram_tst
ld_include_psram_tst:

View file

@ -0,0 +1,5 @@
.global xt_highint5
.global _xt_highint5
.weak xt_highint5
.set xt_highint5, _xt_highint5

View file

@ -0,0 +1,126 @@
#include "xtensa_rtos.h"
#include "esp_panic.h"
#include "sdkconfig.h"
#include "soc/soc.h"
/*
This file contains the default handlers for the high interrupt levels. The default behavious
is to just exit the interrupt.
*/
#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
.global xt_highint2
.weak xt_highint2
.set xt_highint2, _xt_highint2
.section .iram1,"ax"
.type _xt_highint2,@function
.align 4
_xt_highint2:
/* Default handler does nothing; just returns */
.align 4
.L_xt_highint2_exit:
rsr a0, EXCSAVE_2 /* restore a0 */
rfi 2
#endif /* Level 2 */
#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
.global xt_highint3
.weak xt_highint3
.set xt_highint3, _xt_highint3
.section .iram1,"ax"
.type _xt_highint3,@function
.align 4
_xt_highint3:
/* Default handler does nothing; just returns */
.align 4
.L_xt_highint3_exit:
rsr a0, EXCSAVE_3 /* restore a0 */
rfi 3
#endif /* Level 3 */
#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
.global xt_highint4
.weak xt_highint4
.set xt_highint4, _xt_highint4
.section .iram1,"ax"
.type _xt_highint4,@function
.align 4
_xt_highint4:
/* Default handler does nothing; just returns */
.align 4
.L_xt_highint4_exit:
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
#endif /* Level 4 */
#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
.global xt_highint5
.weak xt_highint5
.set xt_highint5, _xt_highint5
.section .iram1,"ax"
.type _xt_highint5,@function
.align 4
_xt_highint5:
/* Default handler does nothing; just returns */
.align 4
.L_xt_highint5_exit:
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#endif /* Level 5 */
#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
.global _xt_highint6
.global xt_highint6
.weak xt_highint6
.set xt_highint6, _xt_highint6
.section .iram1,"ax"
.type _xt_highint6,@function
.align 4
_xt_highint6:
/* Default handler does nothing; just returns */
.align 4
.L_xt_highint6_exit:
rsr a0, EXCSAVE_6 /* restore a0 */
rfi 6
#endif /* Level 6 */
#if XCHAL_HAVE_NMI
.global _xt_nmi
.global xt_nmi
.weak xt_nmi
.set xt_nmi, _xt_nmi
.section .iram1,"ax"
.type _xt_nmi,@function
.align 4
_xt_nmi:
/* Default handler does nothing; just returns */
.align 4
.L_xt_nmi_exit:
rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */
rfi XCHAL_NMILEVEL
#endif /* NMI */

View file

@ -1522,9 +1522,9 @@ the minimum necessary before jumping to the handler in the .text section.
*******************************************************************************/
/*
Currently only shells for high priority interrupt handlers are provided
here. However a template and example can be found in the Cadence Design Systems tools
documentation: "Microprocessor Programmer's Guide".
These stubs just call xt_highintX/xt_nmi to handle the real interrupt. Please define
these in an external assembly source file. If these symbols are not defined anywhere
else, the defaults in xtensa_vector_defaults.S are used.
*/
#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
@ -1533,37 +1533,14 @@ documentation: "Microprocessor Programmer's Guide".
.section .Level2InterruptVector.text, "ax"
.global _Level2Vector
.type _Level2Vector,@function
.global xt_highint2
.align 4
_Level2Vector:
wsr a0, EXCSAVE_2 /* preserve a0 */
call0 _xt_highint2 /* load interrupt handler */
call0 xt_highint2 /* load interrupt handler */
.end literal_prefix
.section .iram1,"ax"
.type _xt_highint2,@function
.align 4
_xt_highint2:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 2<<2
beqz a0, 1f
.Ln_xt_highint2_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xt_highint2_exit:
rsr a0, EXCSAVE_2 /* restore a0 */
rfi 2
#endif /* Level 2 */
#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
@ -1572,38 +1549,15 @@ _xt_highint2:
.section .Level3InterruptVector.text, "ax"
.global _Level3Vector
.type _Level3Vector,@function
.global xt_highint3
.align 4
_Level3Vector:
wsr a0, EXCSAVE_3 /* preserve a0 */
call0 _xt_highint3 /* load interrupt handler */
call0 xt_highint3 /* load interrupt handler */
/* never returns here - call0 is used as a jump (see note at top) */
.end literal_prefix
.section .iram1,"ax"
.type _xt_highint3,@function
.align 4
_xt_highint3:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 3<<2
beqz a0, 1f
.Ln_xt_highint3_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xt_highint3_exit:
rsr a0, EXCSAVE_3 /* restore a0 */
rfi 3
#endif /* Level 3 */
#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
@ -1612,110 +1566,15 @@ _xt_highint3:
.section .Level4InterruptVector.text, "ax"
.global _Level4Vector
.type _Level4Vector,@function
.global xt_highint4
.align 4
_Level4Vector:
wsr a0, EXCSAVE_4 /* preserve a0 */
call0 _xt_highint4 /* load interrupt handler */
call0 xt_highint4 /* load interrupt handler */
/* never returns here - call0 is used as a jump (see note at top) */
.end literal_prefix
.section .iram1,"ax"
.type _xt_highint4,@function
.align 4
_xt_highint4:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 4<<2
beqz a0, 1f
.Ln_xt_highint4_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* On the ESP32, this level is used for panic events that are detected by hardware and should
also panic when interrupts are disabled. At the moment, these are the interrupt watchdog
as well as the cache invalid access interrupt. (24 and 25) */
/* Allocate exception frame and save minimal context. */
mov a0, sp
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_A1
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -12 /* for debug backtrace */
#endif
rsr a0, PS /* save interruptee's PS */
s32i a0, sp, XT_STK_PS
rsr a0, EPC_4 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -16 /* for debug backtrace */
#endif
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
call0 _xt_context_save
/* Save vaddr into exception frame */
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
/* Figure out reason, save into EXCCAUSE reg */
rsr a0, INTERRUPT
extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */
beqz a0, 1f
/* Kill this interrupt; we cannot reset it. */
rsr a0, INTENABLE
movi a4, ~(1<<ETS_CACHEERR_INUM)
and a0, a4, a0
wsr a0, INTENABLE
movi a0, PANIC_RSN_CACHEERR
j 9f
1:
#if CONFIG_INT_WDT_CHECK_CPU1
/* Check if the cause is the app cpu failing to tick.*/
movi a0, int_wdt_app_cpu_ticked
l32i a0, a0, 0
bnez a0, 2f
/* It is. Modify cause. */
movi a0,PANIC_RSN_INTWDT_CPU1
j 9f
2:
#endif
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
movi a0,PANIC_RSN_INTWDT_CPU0
9:
/* Found the reason, now save it. */
s32i a0, sp, XT_STK_EXCCAUSE
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_4 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
wsr a0, PS
//Call panic handler
mov a6,sp
call4 panicHandler
call0 _xt_context_restore
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
wsr a0, PS
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
wsr a0, EPC_4
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
l32i sp, sp, XT_STK_A1 /* remove exception frame */
rsync /* ensure PS and EPC written */
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
#endif /* Level 4 */
#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
@ -1724,95 +1583,15 @@ _xt_highint4:
.section .Level5InterruptVector.text, "ax"
.global _Level5Vector
.type _Level5Vector,@function
.global xt_highint5
.align 4
_Level5Vector:
wsr a0, EXCSAVE_5 /* preserve a0 */
call0 _xt_highint5 /* load interrupt handler */
call0 xt_highint5 /* load interrupt handler */
/* never returns here - call0 is used as a jump (see note at top) */
.end literal_prefix
#define L5_INTR_STACK_SIZE 8
#define L5_INTR_A2_OFFSET 0
#define L5_INTR_A3_OFFSET 4
.data
_l5_intr_stack:
.space L5_INTR_STACK_SIZE
.section .iram1,"ax"
.type _xt_highint5,@function
.align 4
_xt_highint5:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 5<<2
beqz a0, 1f
.Ln_xt_highint5_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* This section is for access dport register protection */
/* Allocate exception frame and save minimal context. */
/* Because the interrupt cause code have protection that only
allow one cpu enter in L5 interrupt at one time, so
there needn't have two _l5_intr_stack for each cpu */
movi a0, _l5_intr_stack
s32i a2, a0, L5_INTR_A2_OFFSET
s32i a3, a0, L5_INTR_A3_OFFSET
/* Check interrupt */
rsr a0, INTERRUPT
extui a0, a0, ETS_DPORT_INUM, 1 /* get dport int bit */
beqz a0, 1f
/* handle dport interrupt */
/* get CORE_ID */
getcoreid a0
beqz a0, 2f
/* current cpu is 1 */
movi a0, DPORT_CPU_INTR_FROM_CPU_3_REG
movi a2, 0
s32i a2, a0, 0 /* clear intr */
movi a0, 0 /* other cpu id */
j 3f
2:
/* current cpu is 0 */
movi a0, DPORT_CPU_INTR_FROM_CPU_2_REG
movi a2, 0
s32i a2, a0, 0 /* clear intr */
movi a0, 1 /* other cpu id */
3:
/* set and wait flag */
movi a2, dport_access_start
addx4 a2, a0, a2
movi a3, 1
s32i a3, a2, 0
memw
movi a2, dport_access_end
addx4 a2, a0, a2
.check_dport_access_end:
l32i a3, a2, 0
beqz a3, .check_dport_access_end
1:
movi a0, _l5_intr_stack
l32i a2, a0, L5_INTR_A2_OFFSET
l32i a3, a0, L5_INTR_A3_OFFSET
rsync /* ensure register restored */
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
.align 4
.L_xt_highint5_exit:
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#endif /* Level 5 */
@ -1822,38 +1601,15 @@ _xt_highint5:
.section .Level6InterruptVector.text, "ax"
.global _Level6Vector
.type _Level6Vector,@function
.global xt_highint6
.align 4
_Level6Vector:
wsr a0, EXCSAVE_6 /* preserve a0 */
call0 _xt_highint6 /* load interrupt handler */
call0 xt_highint6 /* load interrupt handler */
/* never returns here - call0 is used as a jump (see note at top) */
.end literal_prefix
.section .iram1,"ax"
.type _xt_highint6,@function
.align 4
_xt_highint6:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 6<<2
beqz a0, 1f
.Ln_xt_highint6_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xt_highint6_exit:
rsr a0, EXCSAVE_6 /* restore a0 */
rfi 6
#endif /* Level 6 */
#if XCHAL_HAVE_NMI
@ -1862,38 +1618,15 @@ _xt_highint6:
.section .NMIExceptionVector.text, "ax"
.global _NMIExceptionVector
.type _NMIExceptionVector,@function
.global xt_nmi
.align 4
_NMIExceptionVector:
wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */
call0 _xt_nmi /* load interrupt handler */
call0 xt_nmi /* load interrupt handler */
/* never returns here - call0 is used as a jump (see note at top) */
.end literal_prefix
.section .iram1,"ax"
.type _xt_nmi,@function
.align 4
_xt_nmi:
#ifdef XT_INTEXC_HOOKS
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, XCHAL_NMILEVEL<<2
beqz a0, 1f
.Ln_xt_nmi_call_hook:
callx0 a0 /* must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE.
*/
.align 4
.L_xt_nmi_exit:
rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */
rfi XCHAL_NMILEVEL
#endif /* NMI */