mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-21 00:56:38 +08:00
feat(freertos): Simplify xtensa platform code
All normal ISRs are called by "_xt_isr_handler".
This commit is contained in:
@ -20,6 +20,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ETS_INT_MASK 0x00003FFF
|
||||
#define ESP_TICKS_MAX UINT32_MAX
|
||||
|
||||
typedef uint32_t esp_tick_t;
|
||||
@ -63,6 +64,70 @@ static inline void soc_restore_local_irq(esp_irqflag_t flag)
|
||||
);
|
||||
}
|
||||
|
||||
static inline void soc_set_ccompare(uint32_t ticks)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"wsr %0, ccompare0\n"
|
||||
:
|
||||
: "a"(ticks)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline uint32_t soc_get_ccompare(void)
|
||||
{
|
||||
uint32_t ticks;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rsr %0, ccompare0\n"
|
||||
: "=a"(ticks)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
static inline uint32_t soc_get_ccount(void)
|
||||
{
|
||||
uint32_t ticks;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rsr %0, ccount\n"
|
||||
: "=a"(ticks)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
static inline void soc_clear_int_mask(uint32_t mask)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"wsr %0, intclear\n"
|
||||
:
|
||||
: "a"(mask)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline uint32_t soc_get_int_mask(void)
|
||||
{
|
||||
uint32_t mask, enable;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rsr %0, interrupt\n"
|
||||
"rsr %1, intenable\n"
|
||||
"rsync\n"
|
||||
: "=a"(mask), "=a"(enable)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return mask & enable & ETS_INT_MASK;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define _EAGLE_SOC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/soc.h"
|
||||
|
||||
/* IO definitions (access restrictions to peripheral registers) */
|
||||
|
||||
|
@ -42,6 +42,7 @@ extern "C" {
|
||||
#define ETS_SOFT_INUM 7
|
||||
#define ETS_WDT_INUM 8
|
||||
#define ETS_FRC_TIMER1_INUM 9
|
||||
#define ETS_INT_MAX 14
|
||||
|
||||
extern char NMIIrqIsOn;
|
||||
extern uint32_t WDEV_INTEREST_EVENT;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#include "portmacro.h"
|
||||
#include "esp8266/eagle_soc.h"
|
||||
#include "driver/soc.h"
|
||||
|
||||
static const char *TAG = "wdt";
|
||||
|
||||
@ -46,7 +47,7 @@ esp_err_t esp_task_wdt_init(void)
|
||||
const uint32_t panic_time_param = 11;
|
||||
|
||||
// Just for soft restart
|
||||
_xt_clear_ints(1 << ETS_WDT_INUM);
|
||||
soc_clear_int_mask(1 << ETS_WDT_INUM);
|
||||
|
||||
_xt_isr_attach(ETS_WDT_INUM, esp_task_wdt_isr, NULL);
|
||||
_xt_isr_unmask(1 << ETS_WDT_INUM);
|
||||
|
@ -158,8 +158,6 @@ void _xt_user_exit (void);
|
||||
void _xt_tick_timer_init (void);
|
||||
void _xt_isr_unmask (uint32_t unmask);
|
||||
void _xt_isr_mask (uint32_t mask);
|
||||
uint32_t _xt_read_ints (void);
|
||||
void _xt_clear_ints(uint32_t mask);
|
||||
|
||||
/* interrupt related */
|
||||
typedef void (* _xt_isr)(void *arg);
|
||||
|
@ -140,7 +140,6 @@ Derviation of clock divisor for timer tick and interrupt (one per tick).
|
||||
#else
|
||||
#ifndef __ASSEMBLER__
|
||||
extern unsigned _xt_tick_divisor;
|
||||
extern void _xt_tick_divisor_init(void);
|
||||
#endif
|
||||
#define XT_TICK_DIVISOR _xt_tick_divisor
|
||||
#endif
|
||||
|
@ -117,119 +117,6 @@ _xt_int_exit:
|
||||
l32i a0, sp, XT_STK_EXIT
|
||||
ret
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
* _xt_timer_int
|
||||
* void _xt_timer_int(void)
|
||||
*
|
||||
* Implements the Xtensa RTOS porting layer's XT_RTOS_TIMER_INT function for uC/OS-II.
|
||||
* Called every timer interrupt.
|
||||
* Manages the tick timer and calls OSTimeTick() every tick, and calls OSTmrSignal() when required.
|
||||
* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
|
||||
*
|
||||
* Callable from C (obeys ABI conventions). Implemented in assmebly code for performance.
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
/* Define local variable offsets in stack frame for Call0 ABI. */
|
||||
#define __xt_timer_int_a0 0 /* ENTRY()/RET() saves/restores */
|
||||
#define __xt_timer_int_a2 4 /* preserve a2 */
|
||||
#define __xt_timer_int_a3 8 /* preserve a3 */
|
||||
|
||||
.globl _xt_timer_int
|
||||
.type _xt_timer_int,@function
|
||||
.align 4
|
||||
_xt_timer_int:
|
||||
|
||||
/*
|
||||
Xtensa timers work by comparing a cycle counter with a preset value. Once the match occurs
|
||||
an interrupt is generated, and the handler has to set a new cycle count into the comparator.
|
||||
To avoid clock drift due to interrupt latency, the new cycle count is computed from the old,
|
||||
not the time the interrupt was serviced. However if a timer interrupt is ever serviced more
|
||||
than one tick late, it is necessary to process multiple ticks until the new cycle count is
|
||||
in the future, otherwise the next timer interrupt would not occur until after the cycle
|
||||
counter had wrapped (2^32 cycles later).
|
||||
|
||||
do {
|
||||
ticks++;
|
||||
old_ccompare = read_ccompare_i();
|
||||
write_ccompare_i( old_ccompare + divisor );
|
||||
service one tick;
|
||||
diff = read_ccount() - old_ccompare;
|
||||
} while ( diff > divisor );
|
||||
*/
|
||||
|
||||
ENTRY(16)
|
||||
|
||||
.L_xt_timer_int_catchup:
|
||||
|
||||
/* Update the timer comparator for the next tick. */
|
||||
#ifdef XT_CLOCK_FREQ
|
||||
movi a2, XT_TICK_DIVISOR /* a2 = comparator increment */
|
||||
#else
|
||||
movi a3, _xt_tick_divisor
|
||||
l32i a2, a3, 0 /* a2 = comparator increment */
|
||||
#endif
|
||||
rsr a3, XT_CCOMPARE /* a3 = old comparator value */
|
||||
add a4, a3, a2 /* a4 = new comparator value */
|
||||
wsr a4, XT_CCOMPARE /* update comp. and clear interrupt */
|
||||
esync
|
||||
|
||||
/* Preserve a2 and a3 across C calls. */
|
||||
s32i a2, sp, __xt_timer_int_a2
|
||||
s32i a3, sp, __xt_timer_int_a3
|
||||
|
||||
#ifndef CONFIG_TASK_SWITCH_FASTER
|
||||
movi a0, xPortSysTickHandle
|
||||
callx0 a0
|
||||
#else
|
||||
call0 xPortSysTickHandle
|
||||
#endif
|
||||
|
||||
/* Restore a2 and a3. */
|
||||
l32i a2, sp, __xt_timer_int_a2
|
||||
l32i a3, sp, __xt_timer_int_a3
|
||||
|
||||
/* Check if we need to process more ticks to catch up. */
|
||||
esync /* ensure comparator update complete */
|
||||
rsr a4, CCOUNT /* a4 = cycle count */
|
||||
sub a4, a4, a3 /* diff = ccount - old comparator */
|
||||
blt a2, a4, .L_xt_timer_int_catchup /* repeat while diff > divisor */
|
||||
|
||||
RET(16)
|
||||
|
||||
|
||||
|
||||
#define __xt_timer_int1_a0 0 /* ENTRY()/RET() saves/restores */
|
||||
#define __xt_timer_int1_a2 4 /* preserve a2 */
|
||||
#define __xt_timer_int1_a3 8 /* preserve a3 */
|
||||
|
||||
.globl _xt_timer_int1
|
||||
.type _xt_timer_int1,@function
|
||||
.align 4
|
||||
_xt_timer_int1:
|
||||
|
||||
ENTRY(16)
|
||||
|
||||
/* Preserve a2 and a3 across C calls. */
|
||||
s32i a2, sp, __xt_timer_int1_a2
|
||||
s32i a3, sp, __xt_timer_int1_a3
|
||||
|
||||
/* Call the uCOS-II tick handler. */
|
||||
#ifndef CONFIG_TASK_SWITCH_FASTER
|
||||
movi a0, vTaskSwitchContext
|
||||
callx0 a0
|
||||
#else
|
||||
call0 vTaskSwitchContext
|
||||
#endif
|
||||
|
||||
/* Restore a2 and a3. */
|
||||
l32i a2, sp, __xt_timer_int1_a2
|
||||
l32i a3, sp, __xt_timer_int1_a3
|
||||
|
||||
RET(16)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
@ -241,9 +128,10 @@ _xt_timer_int1:
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
.globl _xt_tick_timer_init
|
||||
.type _xt_tick_timer_init,@function
|
||||
.align 4
|
||||
.section .text._xt_tick_timer_init, "ax"
|
||||
.globl _xt_tick_timer_init
|
||||
.type _xt_tick_timer_init,@function
|
||||
.align 4
|
||||
_xt_tick_timer_init:
|
||||
|
||||
ENTRY(16)
|
||||
@ -268,10 +156,10 @@ _xt_tick_timer_init:
|
||||
|
||||
RET(16)
|
||||
|
||||
|
||||
.globl _xt_set_xt_ccompare_val
|
||||
.type _xt_set_xt_ccompare_val,@function
|
||||
.align 4
|
||||
.section .text._xt_set_xt_ccompare_val, "ax"
|
||||
.globl _xt_set_xt_ccompare_val
|
||||
.type _xt_set_xt_ccompare_val,@function
|
||||
.align 4
|
||||
_xt_set_xt_ccompare_val:
|
||||
ENTRY(16)
|
||||
|
||||
@ -282,9 +170,10 @@ _xt_set_xt_ccompare_val:
|
||||
esync
|
||||
RET(16)
|
||||
|
||||
.globl ResetCcountVal
|
||||
.type ResetCcountVal,@function
|
||||
.align 4
|
||||
.section .text.ResetCcountVal, "ax"
|
||||
.globl ResetCcountVal
|
||||
.type ResetCcountVal,@function
|
||||
.align 4
|
||||
ResetCcountVal:
|
||||
ENTRY(16)
|
||||
wsr a2, ccount
|
||||
@ -296,10 +185,10 @@ ResetCcountVal:
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
.globl _xt_isr_unmask
|
||||
.type _xt_isr_unmask,@function
|
||||
.align 4
|
||||
.section .text._xt_isr_unmask, "ax"
|
||||
.globl _xt_isr_unmask
|
||||
.type _xt_isr_unmask,@function
|
||||
.align 4
|
||||
_xt_isr_unmask:
|
||||
ENTRY(16)
|
||||
|
||||
@ -313,9 +202,10 @@ _xt_isr_unmask:
|
||||
RET(16)
|
||||
|
||||
|
||||
.globl _xt_isr_mask
|
||||
.type _xt_isr_mask,@function
|
||||
.align 4
|
||||
.section .text._xt_isr_mask, "ax"
|
||||
.globl _xt_isr_mask
|
||||
.type _xt_isr_mask,@function
|
||||
.align 4
|
||||
_xt_isr_mask:
|
||||
ENTRY(16)
|
||||
|
||||
@ -330,23 +220,6 @@ _xt_isr_mask:
|
||||
RET(16)
|
||||
|
||||
|
||||
.global _xt_read_ints
|
||||
.type _xt_read_ints,@function
|
||||
.align 4
|
||||
_xt_read_ints:
|
||||
ENTRY(16)
|
||||
rsr a2, INTERRUPT
|
||||
RET(16)
|
||||
|
||||
.global _xt_clear_ints
|
||||
.type _xt_clear_ints,@function
|
||||
.align 4
|
||||
_xt_clear_ints:
|
||||
ENTRY(16)
|
||||
wsr a2, INTCLEAR
|
||||
RET(16)
|
||||
|
||||
|
||||
.section .text._xt_enter_first_task, "ax"
|
||||
.globl _xt_enter_first_task
|
||||
.type _xt_enter_first_task, @function
|
||||
|
@ -53,7 +53,9 @@
|
||||
extern char NMIIrqIsOn;
|
||||
static int SWReq = 0;
|
||||
|
||||
unsigned cpu_sr;
|
||||
uint32_t cpu_sr;
|
||||
|
||||
uint32_t _xt_tick_divisor;
|
||||
|
||||
/* Each task maintains its own interrupt status in the critical nesting
|
||||
variable. */
|
||||
@ -65,8 +67,6 @@ uint64_t g_os_ticks = 0;
|
||||
void vPortEnterCritical(void);
|
||||
void vPortExitCritical(void);
|
||||
|
||||
void _xt_timer_int1(void);
|
||||
|
||||
|
||||
uint8_t *__cpu_init_stk(uint8_t *stack_top, void (*_entry)(void *), void *param, void (*_exit)(void))
|
||||
{
|
||||
@ -121,7 +121,7 @@ void TASK_SW_ATTR SoftIsrHdl(void* arg)
|
||||
extern int MacIsrSigPostDefHdl(void);
|
||||
|
||||
if (MacIsrSigPostDefHdl() || (SWReq == 1)) {
|
||||
_xt_timer_int1();
|
||||
vTaskSwitchContext();
|
||||
SWReq = 0;
|
||||
}
|
||||
}
|
||||
@ -138,8 +138,12 @@ void esp_increase_tick_cnt(const TickType_t ticks)
|
||||
soc_restore_local_irq(flag);
|
||||
}
|
||||
|
||||
void TASK_SW_ATTR xPortSysTickHandle(void)
|
||||
void TASK_SW_ATTR xPortSysTickHandle(void *p)
|
||||
{
|
||||
const uint32_t cpu_clk_cnt = soc_get_ccount() + _xt_tick_divisor;
|
||||
|
||||
soc_set_ccompare(cpu_clk_cnt);
|
||||
|
||||
g_cpu_ticks = soc_get_ticks();
|
||||
g_os_ticks++;
|
||||
|
||||
@ -167,8 +171,11 @@ portBASE_TYPE xPortStartScheduler(void)
|
||||
_xt_isr_attach(ETS_SOFT_INUM, SoftIsrHdl, NULL);
|
||||
_xt_isr_unmask(1 << ETS_SOFT_INUM);
|
||||
|
||||
_xt_isr_attach(ETS_MAX_INUM, xPortSysTickHandle, NULL);
|
||||
|
||||
/* Initialize system tick timer interrupt and schedule the first tick. */
|
||||
_xt_tick_divisor_init();
|
||||
_xt_tick_divisor = xtbsp_clock_freq_hz() / XT_TICK_PER_SEC;
|
||||
|
||||
_xt_tick_timer_init();
|
||||
|
||||
vTaskSwitchContext();
|
||||
@ -255,44 +262,40 @@ bool interrupt_is_disable(void)
|
||||
return tmp & 0xFUL ? true : false;
|
||||
}
|
||||
|
||||
_xt_isr_entry isr[16];
|
||||
char _xt_isr_status = 0;
|
||||
static _xt_isr_entry s_isr[16];
|
||||
static uint8_t s_xt_isr_status = 0;
|
||||
|
||||
void _xt_isr_attach(uint8_t i, _xt_isr func, void* arg)
|
||||
{
|
||||
isr[i].handler = func;
|
||||
isr[i].arg = arg;
|
||||
s_isr[i].handler = func;
|
||||
s_isr[i].arg = arg;
|
||||
}
|
||||
|
||||
uint16_t TASK_SW_ATTR _xt_isr_handler(uint16_t i)
|
||||
void IRAM_ATTR _xt_isr_handler(void)
|
||||
{
|
||||
uint8_t index;
|
||||
do {
|
||||
uint32_t mask = soc_get_int_mask();
|
||||
|
||||
if (i & (1 << ETS_WDT_INUM)) {
|
||||
index = ETS_WDT_INUM;
|
||||
} else if (i & (1 << ETS_GPIO_INUM)) {
|
||||
index = ETS_GPIO_INUM;
|
||||
} else {
|
||||
index = __builtin_ffs(i) - 1;
|
||||
for (int i = 0; i < ETS_INT_MAX && mask; i++) {
|
||||
int bit = 1 << i;
|
||||
|
||||
if (index == ETS_MAX_INUM) {
|
||||
i &= ~(1 << ETS_MAX_INUM);
|
||||
index = __builtin_ffs(i) - 1;
|
||||
if (!(bit & mask) || !s_isr[i].handler)
|
||||
continue;
|
||||
|
||||
soc_clear_int_mask(bit);
|
||||
|
||||
s_xt_isr_status = 1;
|
||||
s_isr[i].handler(s_isr[i].arg);
|
||||
s_xt_isr_status = 0;
|
||||
|
||||
mask &= ~bit;
|
||||
}
|
||||
}
|
||||
|
||||
_xt_clear_ints(1 << index);
|
||||
|
||||
_xt_isr_status = 1;
|
||||
isr[index].handler(isr[index].arg);
|
||||
_xt_isr_status = 0;
|
||||
|
||||
return i & ~(1 << index);
|
||||
} while (soc_get_int_mask());
|
||||
}
|
||||
|
||||
int xPortInIsrContext(void)
|
||||
{
|
||||
return _xt_isr_status != 0;
|
||||
return s_xt_isr_status != 0;
|
||||
}
|
||||
|
||||
void __attribute__((weak, noreturn)) vApplicationStackOverflowHook(xTaskHandle xTask, const char *pcTaskName)
|
||||
|
@ -1,54 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2006-2009 by Tensilica Inc. ALL RIGHTS RESERVED.
|
||||
These coded instructions, statements, and computer programs are the
|
||||
copyrighted works and confidential proprietary information of Tensilica Inc.
|
||||
They may not be modified, copied, reproduced, distributed, or disclosed to
|
||||
third parties in any manner, medium, or form, in whole or in part, without
|
||||
the prior written consent of Tensilica Inc.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
XTENSA INITIALIZATION ROUTINES CODED IN C
|
||||
|
||||
This header is a place to put miscellaneous Xtensa RTOS-generic initialization
|
||||
functions that are implemented in C.
|
||||
|
||||
This header contains definitions and macros for use primarily by Xtensa
|
||||
RTOS assembly coded source files. It includes and uses the Xtensa hardware
|
||||
abstraction layer (HAL) to deal with config specifics. It may also be
|
||||
included in C source files.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XTENSA_INIT_H
|
||||
#define XTENSA_INIT_H
|
||||
|
||||
#ifdef XT_BOARD
|
||||
#include <xtensa/xtbsp.h>
|
||||
#endif
|
||||
|
||||
#include "freertos/xtensa_rtos.h"
|
||||
|
||||
|
||||
#ifdef XT_RTOS_TIMER_INT
|
||||
#ifndef XT_CLOCK_FREQ
|
||||
|
||||
unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */
|
||||
|
||||
/*
|
||||
Compute and initialize at run-time the tick divisor (the number of
|
||||
processor clock cycles in an RTOS tick, used to set the tick timer).
|
||||
Called when the processor clock frequency is not known at compile-time.
|
||||
*/
|
||||
void _xt_tick_divisor_init(void)
|
||||
{
|
||||
#ifdef XT_BOARD
|
||||
_xt_tick_divisor = xtbsp_clock_freq_hz() / XT_TICK_PER_SEC;
|
||||
#else
|
||||
#error "No way to obtain processor clock frequency"
|
||||
#endif /* XT_BOARD */
|
||||
}
|
||||
|
||||
#endif /* XT_CLOCK_FREQ */
|
||||
#endif /* XT_RTOS_TIMER_INT */
|
||||
|
||||
#endif /* XTENSA_INIT_H */
|
@ -675,16 +675,6 @@ _xt_user_entry1:
|
||||
|
||||
/* Handle level 1 interrupts. No need to enable med-pri interrupts now. */
|
||||
.L_xt_user_int:
|
||||
/*
|
||||
Get mask of pending, enabled interrupts at this level into a2.
|
||||
Comment this out if there is only one interrupt at this level.
|
||||
*/
|
||||
rsr a2, INTENABLE
|
||||
rsr a3, INTERRUPT
|
||||
movi a4, XCHAL_INTLEVEL1_MASK
|
||||
and a2, a2, a3
|
||||
and a2, a2, a4
|
||||
|
||||
|
||||
/* USER_EDIT:
|
||||
ADD LOW PRIORITY LEVEL 1 INTERRUPT HANDLER CODE HERE, OR CALL C HANDLER.
|
||||
@ -695,16 +685,6 @@ _xt_user_entry1:
|
||||
When done, ensure a2 contains a mask of unhandled (still pending)
|
||||
enabled ints at this level, and fall through.
|
||||
*/
|
||||
.Ln_xt_user_int_timer:
|
||||
movi a3, 0xFFBF
|
||||
and a3, a2, a3
|
||||
bnez a3, 3f
|
||||
/* Interrupt handler for the RTOS tick timer if at this level. */
|
||||
movi a3, XT_TIMER_INTEN /* timer interrupt bit */
|
||||
sub a12, a2, a3 /* clear timer int and save mask */
|
||||
call0 XT_RTOS_TIMER_INT
|
||||
mov a2, a12 /* recover mask of remaining ints */
|
||||
beqz a2, 4f
|
||||
3:
|
||||
movi a0, _chip_interrupt_tmp
|
||||
s32i a1, a0, 0
|
||||
@ -720,13 +700,6 @@ _xt_user_entry1:
|
||||
movi a0, _chip_interrupt_tmp
|
||||
l32i a1, a0, 0
|
||||
|
||||
bnez a2, .Ln_xt_user_int_timer
|
||||
4:
|
||||
/* All interrupts at this level should have been handled now. */
|
||||
beqz a2, .L_xt_user_done
|
||||
|
||||
call0 _xt_ext_panic
|
||||
|
||||
/* Done handling after XT_RTOS_INT_ENTER. Give control to RTOS. */
|
||||
.L_xt_user_done:
|
||||
call0 XT_RTOS_INT_EXIT /* does not return directly here */
|
||||
@ -797,7 +770,7 @@ nmi_common:
|
||||
s32i a1, a0, HESF_AR(1)
|
||||
l32i a2, a2, 0 // get dispatcher address
|
||||
s32i a3, a0, HESF_AR(3)
|
||||
xsr a2, EXCSAVE_LEVEL // get saved a0, restore dispatcher address
|
||||
xsr a2, EXCSAVE_LEVEL // get saved a0, restore dispatcher address
|
||||
|
||||
s32i a4, a0, HESF_AR(4)
|
||||
s32i a2, a0, HESF_AR(0)
|
||||
@ -819,7 +792,7 @@ nmi_common:
|
||||
rsr a4, EXCCAUSE
|
||||
s32i a3, a0, HESF_EPC1
|
||||
s32i a4, a0, HESF_EXCCAUSE
|
||||
rsr a3, EXCVADDR
|
||||
rsr a3, EXCVADDR
|
||||
s32i a3, a0, HESF_EXCVADDR
|
||||
rsr a4, EXCSAVE1
|
||||
s32i a4, a0, HESF_EXCSAVE1
|
||||
|
Reference in New Issue
Block a user