本帖最后由 XIVN1987 于 2024-4-15 12:43 编辑
- volatile int timer_n = 0;
- void timer_handler (void) {
- timer_n++;
- }
- timer_handler:
- lui a0, %hi(timer_n)
- lw a1, %lo(timer_n)(a0)
- addi a1, a1, 1
- sw a1, %lo(timer_n)(a0)
- ret
- __attribute__((interrupt))
- void timer_handler (void) {
- timer_n++;
- }
- timer_handler:
- addi sp, sp, -16
- sw a0, 12(sp) # 4-byte Folded Spill
- sw a1, 8(sp) # 4-byte Folded Spill
- lui a0, %hi(timer_n)
- lw a1, %lo(timer_n)(a0)
- addi a1, a1, 1
- sw a1, %lo(timer_n)(a0)
- lw a0, 12(sp) # 4-byte Folded Reload
- lw a1, 8(sp) # 4-byte Folded Reload
- addi sp, sp, 16
- mret
对比发现,添加 __attribute__((interrupt)) 修饰后,编译器给用到的寄存器添加保存、恢复代码,并将 ret 替换为 mret.
既然 ISR 对自己使用的寄存器都会提前保存、返回时恢复,,那么发生中断嵌套就不会破坏 ISR 的上下文环境,,可以允许中断嵌套的发生
但是在中断返回时 CPU 需要 mepc 和 mstatus 中的信息确定返回地址和返回特权级,,这些寄存器编译器没有给我们保存、恢复,,因此还需要手动添加代码处理 - __attribute__((interrupt))
- void timer_handler (void) {
- int mepc, mstatus;
- asm("csrr %0, mepc\n\t"
- "csrr %1, mstatus\n\t"
- "csrsi mstatus, 8" // mstatus.MIE = 1, interrupt enable
- : "=r" (mepc), "=r" (mstatus));
- // ISR code
- asm("csrci mstatus, 8\n\t" // mstatus.MIE = 0, interrupt disable
- "csrw mepc, %0\n\t"
- "csrw mstatus, %1"
- : : "r" (mepc), "r" (mstatus));
- }
实现中断嵌套的关键是在重新使能中断之前保存 mepc、mstatus,并在执行 mret 之前恢复它们
但在 CLINT 下实现中断嵌套没有意义,因为 CLINT 下没有中断优先级,中断嵌套只有配合可配置的中断优先级才有意义。所以一般 MCU 厂商会使用更高级的中断控制器替代 CLINT,而不会直接使用官方简陋的 CLINT,,比如沁恒 MCU 使用了自己设计的 PFIC 中断控制器,,添加了中断优先级等功能。。
|