430 lines
16 KiB
Diff
430 lines
16 KiB
Diff
From 8c8c4bd282ed5bf359ef1c0eaeace4c4fbe8ff52 Mon Sep 17 00:00:00 2001
|
||
From: supperthomas <78900636@qq.com>
|
||
Date: Mon, 18 Apr 2022 22:59:02 +0800
|
||
Subject: [PATCH] add fixed of rtthread
|
||
|
||
---
|
||
.../esp_system/ld/esp32c3/sections.ld.in | 19 ++
|
||
components/freertos/port/port_common.c | 11 +-
|
||
components/freertos/port/port_systick.c | 56 ++---
|
||
components/riscv/vectors.S | 236 +++++++++++++++---
|
||
4 files changed, 254 insertions(+), 68 deletions(-)
|
||
|
||
diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in
|
||
index 0ebeda06c1..10506d38a3 100644
|
||
--- a/components/esp_system/ld/esp32c3/sections.ld.in
|
||
+++ b/components/esp_system/ld/esp32c3/sections.ld.in
|
||
@@ -183,6 +183,25 @@ SECTIONS
|
||
_noinit_end = ABSOLUTE(.);
|
||
} > dram0_0_seg
|
||
|
||
+ .stack_dummy (COPY):
|
||
+ {
|
||
+ . = ALIGN(8);
|
||
+ __STACKSIZE__ = 40960;
|
||
+ __stack_start__ = .;
|
||
+ *(.stack*)
|
||
+ . += __STACKSIZE__;
|
||
+ __stack_cpu0 = .;
|
||
+ __stack_end__ = .;
|
||
+ } > dram0_0_seg
|
||
+
|
||
+ .stack_dummy (COPY):
|
||
+ {
|
||
+ . = ALIGN(8);
|
||
+ __HEAPSIZE__ = 40960;
|
||
+ __heap_start__ = .;
|
||
+ . += __STACKSIZE__;
|
||
+ __heap_end__ = .;
|
||
+ } > dram0_0_seg
|
||
/* Shared RAM */
|
||
.dram0.bss (NOLOAD) :
|
||
{
|
||
diff --git a/components/freertos/port/port_common.c b/components/freertos/port/port_common.c
|
||
index ffca3d5429..dd3cc46f16 100644
|
||
--- a/components/freertos/port/port_common.c
|
||
+++ b/components/freertos/port/port_common.c
|
||
@@ -74,11 +74,12 @@ void esp_startup_start_app_common(void)
|
||
esp_gdbstub_init();
|
||
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||
|
||
- portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
|
||
- ESP_TASK_MAIN_STACK, NULL,
|
||
- ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
|
||
- assert(res == pdTRUE);
|
||
- (void)res;
|
||
+ // portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
|
||
+ // ESP_TASK_MAIN_STACK, NULL,
|
||
+ // ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
|
||
+ ///assert(res == pdTRUE);
|
||
+ app_main();
|
||
+ //(void)res;
|
||
}
|
||
|
||
static void main_task(void* args)
|
||
diff --git a/components/freertos/port/port_systick.c b/components/freertos/port/port_systick.c
|
||
index 0c14a155a1..cf525f9383 100644
|
||
--- a/components/freertos/port/port_systick.c
|
||
+++ b/components/freertos/port/port_systick.c
|
||
@@ -116,34 +116,34 @@ void vPortSetupTimer(void)
|
||
*/
|
||
IRAM_ATTR void SysTickIsrHandler(void *arg)
|
||
{
|
||
- uint32_t cpuid = xPortGetCoreID();
|
||
- systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg;
|
||
-#ifdef CONFIG_PM_TRACE
|
||
- ESP_PM_TRACE_ENTER(TICK, cpuid);
|
||
-#endif
|
||
-
|
||
- uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
|
||
- do {
|
||
- systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id);
|
||
-
|
||
- uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid];
|
||
- if (diff > 0) {
|
||
- if (s_handled_systicks[cpuid] == 0) {
|
||
- s_handled_systicks[cpuid] = diff;
|
||
- diff = 1;
|
||
- } else {
|
||
- s_handled_systicks[cpuid] += diff;
|
||
- }
|
||
-
|
||
- do {
|
||
- xPortSysTickHandler();
|
||
- } while (--diff);
|
||
- }
|
||
- } while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id));
|
||
-
|
||
-#ifdef CONFIG_PM_TRACE
|
||
- ESP_PM_TRACE_EXIT(TICK, cpuid);
|
||
-#endif
|
||
+// uint32_t cpuid = xPortGetCoreID();
|
||
+// systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg;
|
||
+// #ifdef CONFIG_PM_TRACE
|
||
+// ESP_PM_TRACE_ENTER(TICK, cpuid);
|
||
+// #endif
|
||
+
|
||
+// uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
|
||
+// do {
|
||
+// systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id);
|
||
+
|
||
+// uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid];
|
||
+// if (diff > 0) {
|
||
+// if (s_handled_systicks[cpuid] == 0) {
|
||
+// s_handled_systicks[cpuid] = diff;
|
||
+// diff = 1;
|
||
+// } else {
|
||
+// s_handled_systicks[cpuid] += diff;
|
||
+// }
|
||
+
|
||
+// do {
|
||
+// xPortSysTickHandler();
|
||
+// } while (--diff);
|
||
+// }
|
||
+// } while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id));
|
||
+
|
||
+// #ifdef CONFIG_PM_TRACE
|
||
+// ESP_PM_TRACE_EXIT(TICK, cpuid);
|
||
+// #endif
|
||
}
|
||
|
||
#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
|
||
diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S
|
||
index 1006d5bea5..91bb4aa39e 100644
|
||
--- a/components/riscv/vectors.S
|
||
+++ b/components/riscv/vectors.S
|
||
@@ -17,6 +17,9 @@
|
||
#include "soc/soc_caps.h"
|
||
#include "sdkconfig.h"
|
||
|
||
+#define STORE sw
|
||
+#define LOAD lw
|
||
+#define REGBYTES 4
|
||
|
||
.equ SAVE_REGS, 32
|
||
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||
@@ -218,25 +221,25 @@ _call_panic_handler:
|
||
*/
|
||
.global _interrupt_handler
|
||
.type _interrupt_handler, @function
|
||
-_interrupt_handler:
|
||
+_interrupt_handler1:
|
||
/* entry */
|
||
- save_regs
|
||
- save_mepc
|
||
+ save_regs /* 保存寄存器 */
|
||
+ save_mepc /* 保存MEPC */
|
||
|
||
/* Before doing anythig preserve the stack pointer */
|
||
/* It will be saved in current TCB, if needed */
|
||
- mv a0, sp
|
||
+ mv a0, sp /* 保存SP a0 = sp */
|
||
call rtos_int_enter
|
||
|
||
/* Before dispatch c handler, restore interrupt to enable nested intr */
|
||
- csrr s1, mcause
|
||
- csrr s2, mstatus
|
||
+ csrr s1, mcause /* 保存mcause s1 = mcause */
|
||
+ csrr s2, mstatus /* 保存mstatus s2 = mstatus */
|
||
|
||
- /* Save the interrupt threshold level */
|
||
- la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||
- lw s3, 0(t0)
|
||
+ /* Save the interrupt threshold level 保存中断嵌套层数? */
|
||
+ la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG /* 保存mstatus t0 = &INTERRUPT_CORE0_CPU_INT_THRESH_REG */
|
||
+ lw s3, 0(t0) /* s3 = mstatus */
|
||
|
||
- /* Increase interrupt threshold level */
|
||
+ /* Increase interrupt threshold level 增加中断嵌套层数*/
|
||
li t2, 0x7fffffff
|
||
and t1, s1, t2 /* t1 = mcause & mask */
|
||
slli t1, t1, 2 /* t1 = mcause * 4 */
|
||
@@ -247,56 +250,219 @@ _interrupt_handler:
|
||
sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */
|
||
fence
|
||
|
||
- li t0, 0x8
|
||
- csrrs t0, mstatus, t0
|
||
-
|
||
- #ifdef CONFIG_PM_TRACE
|
||
- li a0, 0 /* = ESP_PM_TRACE_IDLE */
|
||
- #if SOC_CPU_CORES_NUM == 1
|
||
- li a1, 0 /* No need to check core ID on single core hardware */
|
||
- #else
|
||
- csrr a1, mhartid
|
||
- #endif
|
||
- la t0, esp_pm_trace_exit
|
||
- jalr t0 /* absolute jump, avoid the 1 MiB range constraint */
|
||
- #endif
|
||
+ li t0, 0x8 /* t0 = 8 */
|
||
+ csrrs t0, mstatus, t0 /*设置状态MIE寄存器,开总中断*/
|
||
|
||
- #ifdef CONFIG_PM_ENABLE
|
||
- la t0, esp_pm_impl_isr_hook
|
||
- jalr t0 /* absolute jump, avoid the 1 MiB range constraint */
|
||
- #endif
|
||
|
||
/* call the C dispatcher */
|
||
mv a0, sp /* argument 1, stack pointer */
|
||
mv a1, s1 /* argument 2, interrupt number (mcause) */
|
||
- /* mask off the interrupt flag of mcause */
|
||
+ /* mask off the interrupt flag of mcause 屏幕异常中断*/
|
||
li t0, 0x7fffffff
|
||
and a1, a1, t0
|
||
jal _global_interrupt_handler
|
||
|
||
- /* After dispatch c handler, disable interrupt to make freertos make context switch */
|
||
+ /* After dispatch c handler, disable interrupt to make freertos make context switch
|
||
+ 在调用c函数之后,disable 中断让freertos能够做内容切换
|
||
+ */
|
||
|
||
li t0, 0x8
|
||
- csrrc t0, mstatus, t0
|
||
+ csrrc t0, mstatus, t0 /*清状态MIE寄存器 关总中断*/
|
||
|
||
- /* restore the interrupt threshold level */
|
||
+
|
||
+ /* restore the interrupt threshold level 中断嵌套 */
|
||
la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||
sw s3, 0(t0)
|
||
fence
|
||
|
||
/* Yield to the next task is needed: */
|
||
- mv a0, sp
|
||
+ mv a0, sp /* a0 = sp*/
|
||
call rtos_int_exit
|
||
|
||
/* The next (or current) stack pointer is returned in a0 */
|
||
- mv sp, a0
|
||
+ mv sp, a0 /* sp = a0*/
|
||
|
||
/* restore the rest of the registers */
|
||
- csrw mcause, s1
|
||
- csrw mstatus, s2
|
||
+ csrw mcause, s1 /* mcause = s1 */
|
||
+ csrw mstatus, s2 /* mstatus = s2 */
|
||
restore_mepc
|
||
restore_regs
|
||
|
||
/* exit, this will also re-enable the interrupts */
|
||
mret
|
||
+ .size _interrupt_handler1, .-_interrupt_handler1
|
||
+
|
||
+
|
||
+
|
||
+_interrupt_handler:
|
||
+ /* 此时CPU的sp = from_thread->sp */
|
||
+ /* 注意: 在这里,并没有将mepc的值赋值为from_thread栈中的epc,但后面会赋值 */
|
||
+ addi sp, sp, -32 * REGBYTES /* sp = sp - 32 * 4 栈指针向下偏移32个寄存器长度,用来将CPU的寄存器保存到from_thread的栈中*/
|
||
+ STORE x1, 1 * REGBYTES(sp) /* 将CPU的x1寄存器,即ra寄存器,保存到from_thread->栈中 */
|
||
+
|
||
+ li t0, 0x80 /* t0 = 0x80 */
|
||
+ STORE t0, 2 * REGBYTES(sp) /* mstatus = t0, 即关闭全局中断 */
|
||
+
|
||
+ /* 将 CPU 的其他寄存器的值,保存到from_thread的任务栈中 */
|
||
+ STORE x4, 4 * REGBYTES(sp)
|
||
+ STORE x5, 5 * REGBYTES(sp)
|
||
+ STORE x6, 6 * REGBYTES(sp)
|
||
+ STORE x7, 7 * REGBYTES(sp)
|
||
+ STORE x8, 8 * REGBYTES(sp)
|
||
+ STORE x9, 9 * REGBYTES(sp)
|
||
+ STORE x10, 10 * REGBYTES(sp)
|
||
+ STORE x11, 11 * REGBYTES(sp)
|
||
+ STORE x12, 12 * REGBYTES(sp)
|
||
+ STORE x13, 13 * REGBYTES(sp)
|
||
+ STORE x14, 14 * REGBYTES(sp)
|
||
+ STORE x15, 15 * REGBYTES(sp)
|
||
+ STORE x16, 16 * REGBYTES(sp)
|
||
+ STORE x17, 17 * REGBYTES(sp)
|
||
+ STORE x18, 18 * REGBYTES(sp)
|
||
+ STORE x19, 19 * REGBYTES(sp)
|
||
+ STORE x20, 20 * REGBYTES(sp)
|
||
+ STORE x21, 21 * REGBYTES(sp)
|
||
+ STORE x22, 22 * REGBYTES(sp)
|
||
+ STORE x23, 23 * REGBYTES(sp)
|
||
+ STORE x24, 24 * REGBYTES(sp)
|
||
+ STORE x25, 25 * REGBYTES(sp)
|
||
+ STORE x26, 26 * REGBYTES(sp)
|
||
+ STORE x27, 27 * REGBYTES(sp)
|
||
+ STORE x28, 28 * REGBYTES(sp)
|
||
+ STORE x29, 29 * REGBYTES(sp)
|
||
+ STORE x30, 30 * REGBYTES(sp)
|
||
+ STORE x31, 31 * REGBYTES(sp)
|
||
+
|
||
+ /* 备份 CPU 的 sp (这时,CPU的sp其实就是from thread的sp指针) 寄存器的值到 s0 寄存器中,下面会使用s0,恢复 CPU 的寄存器 */
|
||
+ move s0, sp /* s0 = sp */
|
||
+
|
||
+ /* 在中断函数中,中断函数中调用的C函数,需要使用 sp, 这里,在中断函数中,使用的 sp 为,系统的栈资源 */
|
||
+ /* switch to interrupt stack */
|
||
+ la sp, __stack_end__ /* sp = _sp */
|
||
+
|
||
+ /* interrupt handle */
|
||
+ /* 注意: 在调用C函数之前,比如sp的值为0x30001000, 在执行完C函数后,sp的值还是会变成 0x30001000 */
|
||
+ call rt_interrupt_enter /* 执行所有的中断函数前,调用该函数 */
|
||
+
|
||
+ csrr s1, mcause
|
||
+ csrr s2, mstatus
|
||
+
|
||
+ /* Save the interrupt threshold level */
|
||
+ la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||
+ lw s3, 0(t0)
|
||
+
|
||
+ li t2, 0x7fffffff
|
||
+ and t1, s1, t2 /* t1 = mcause & mask */
|
||
+ slli t1, t1, 2 /* t1 = mcause * 4 */
|
||
+ la t2, INTC_INT_PRIO_REG(0)
|
||
+ add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */
|
||
+ lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */
|
||
+ addi t2, t2, 1 /* t2 = t2 +1 */
|
||
+ sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */
|
||
+ fence
|
||
+
|
||
+ li t0, 0x8
|
||
+ csrrs t0, mstatus, t0
|
||
+
|
||
+ /* call the C dispatcher */
|
||
+ mv a0, sp /* argument 1, stack pointer */
|
||
+ mv a1, s1 /* argument 2, interrupt number (mcause) */
|
||
+ /* mask off the interrupt flag of mcause */
|
||
+ li t0, 0x7fffffff
|
||
+ and a1, a1, t0
|
||
+ jal _global_interrupt_handler
|
||
+
|
||
+ li t0, 0x8
|
||
+ csrrc t0, mstatus, t0
|
||
+
|
||
+ /* restore the interrupt threshold level */
|
||
+ la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||
+ sw s3, 0(t0)
|
||
+ fence
|
||
+
|
||
+ call rt_interrupt_leave /* 执行所有的中断函数后,调用该函数 */
|
||
+
|
||
+ /* 上面,将保存执行中断服务函数之前的CPU的sp寄存器到了s0所指向的位置处,当执行完中断服务函数,需要将之前的CPU寄存器,恢复一下,此时sp又变成了from thread的sp了 */
|
||
+ move sp, s0 /* sp = s0 */
|
||
+
|
||
+ /* 下面两句话,相当于将 rt_thread_switch_interrupt_flag 值,赋值给了s2 */
|
||
+ /* 将 rt_thread_switch_interrupt_flag 的地址值,赋值给 s0 寄存器*/
|
||
+ la s0, rt_thread_switch_interrupt_flag /* s0 = &rt_thread_switch_interrupt_flag */
|
||
+ /* 将 s0 所指向的地址处的内容,取出来,赋值给 s2 寄存器,其实就是将 rt_thread_switch_interrupt_flag 的值,赋值给了 s2 寄存器*/
|
||
+ lw s2, 0(s0) /* s2 = *s0 = rt_thread_switch_interrupt_flag */
|
||
+
|
||
+ /* 如果 s2的值,即 rt_thread_switch_interrupt_flag 值,如果不为0,则需要继续执行下一条指令,如果为0,则需要跳转到 spurious_interrupt 标号处 执行 */
|
||
+ /* 如果 s2的值等于0,rt_thread_switch_interrupt_flag等于0, 则不需要在中断处理函数中,进行上下文切换,反之则需要 */
|
||
+ /* 如果不需要上下文切换, */
|
||
+
|
||
+ /* 在这里,跳转到 spurious_interrupt的话,是不会进行上下文切换的,因为,此时CPU的sp指针还是from线程的*/
|
||
+ beqz s2, spurious_interrupt /* if (s2 == 0) goto spurious_interrupt; else 执行下一条语句*/
|
||
+
|
||
+ /* 需要上下文切换: 主要目的是将CPU的sp指针,赋值为to_thread的sp */
|
||
+
|
||
+ /* 将 s0 所执向的地址的内容设置为0, 也就是,将变量 rt_thread_switch_interrupt_flag 赋值为了 0 */
|
||
+ /* s0存放的值是 rt_thread_switch_interrupt_flag 变量的地址*/
|
||
+ sw zero, 0(s0) /* *s0 = 0; 也就是 rt_thread_switch_interrupt_flag = 0 */
|
||
+ /* 将 mepc 的值,赋值给 a0 寄存器,mepc 的值是,跳转到中断函数执行之前的 PC 指针 */
|
||
+ /* 这时的mpec其实,还是from线程,在跳转到中断执行前的一个PC地址 */
|
||
+ csrr a0, mepc /* a0 = mepc */
|
||
+
|
||
+ /* 将 mpec 的值写回到freom thread任务栈中的 epc 中,待后续,恢复from线程时,使用 */
|
||
+ STORE a0, 0 * REGBYTES(sp) /* from_thread->sp->epc = a0 ,中断入口处*/
|
||
+
|
||
+ /* 将from_thread的sp指针,赋值为CPU的sp指针 */
|
||
+ la s0, rt_interrupt_from_thread /* s0 = &rt_interrupt_from_thread 注意: rt_interrupt_from_thread = &(from_thread->sp) */
|
||
+ LOAD s1, 0(s0) /* s1 = rt_interrupt_from_thread,也就是s1 = &(from_thread->sp) */
|
||
+ STORE sp, 0(s1) /* from_thread->sp = sp*/
|
||
+
|
||
+ /* 接下来,需要开始恢复CPU的sp为to_thread的sp了 */
|
||
+ la s0, rt_interrupt_to_thread /* s0 = &rt_interrupt_to_thread 注意: rt_interrupt_to_thread = &(to_thred->sp)*/
|
||
+ LOAD s1, 0(s0) /* s1 = rt_interrupt_to_thread, 也就是s1 = &(to_thred->sp) */
|
||
+ LOAD sp, 0(s1) /* sp = (to_thred->sp)*/
|
||
+
|
||
+ /* 将CPU的 mepc设置为to_thred的mepc,待中断退出,执行mret指令后,将从该地址开始执行 */
|
||
+ LOAD a0, 0 * REGBYTES(sp) /* a0 = to_thread的mepc的值*/
|
||
+ csrw mepc, a0 /* mepc = a0 */
|
||
+
|
||
+
|
||
+spurious_interrupt:
|
||
+ LOAD x1, 1 * REGBYTES(sp)
|
||
+
|
||
+ /* Remain in M-mode after mret */
|
||
+ li t0, 0x00001800
|
||
+ csrs mstatus, t0
|
||
+ LOAD t0, 2 * REGBYTES(sp)
|
||
+ csrs mstatus, t0
|
||
+
|
||
+ LOAD x4, 4 * REGBYTES(sp)
|
||
+ LOAD x5, 5 * REGBYTES(sp)
|
||
+ LOAD x6, 6 * REGBYTES(sp)
|
||
+ LOAD x7, 7 * REGBYTES(sp)
|
||
+ LOAD x8, 8 * REGBYTES(sp)
|
||
+ LOAD x9, 9 * REGBYTES(sp)
|
||
+ LOAD x10, 10 * REGBYTES(sp)
|
||
+ LOAD x11, 11 * REGBYTES(sp)
|
||
+ LOAD x12, 12 * REGBYTES(sp)
|
||
+ LOAD x13, 13 * REGBYTES(sp)
|
||
+ LOAD x14, 14 * REGBYTES(sp)
|
||
+ LOAD x15, 15 * REGBYTES(sp)
|
||
+ LOAD x16, 16 * REGBYTES(sp)
|
||
+ LOAD x17, 17 * REGBYTES(sp)
|
||
+ LOAD x18, 18 * REGBYTES(sp)
|
||
+ LOAD x19, 19 * REGBYTES(sp)
|
||
+ LOAD x20, 20 * REGBYTES(sp)
|
||
+ LOAD x21, 21 * REGBYTES(sp)
|
||
+ LOAD x22, 22 * REGBYTES(sp)
|
||
+ LOAD x23, 23 * REGBYTES(sp)
|
||
+ LOAD x24, 24 * REGBYTES(sp)
|
||
+ LOAD x25, 25 * REGBYTES(sp)
|
||
+ LOAD x26, 26 * REGBYTES(sp)
|
||
+ LOAD x27, 27 * REGBYTES(sp)
|
||
+ LOAD x28, 28 * REGBYTES(sp)
|
||
+ LOAD x29, 29 * REGBYTES(sp)
|
||
+ LOAD x30, 30 * REGBYTES(sp)
|
||
+ LOAD x31, 31 * REGBYTES(sp)
|
||
+
|
||
+ addi sp, sp, 32 * REGBYTES
|
||
+ mret
|
||
.size _interrupt_handler, .-_interrupt_handler
|
||
--
|
||
2.35.1.windows.2
|
||
|