您尚未登录。

楼主 # 2024-04-15 09:43:37

XIVN1987
会员
注册时间: 2019-08-30
已发帖子: 250
积分: 311.5

RISC-V CLINT 中断处理与中断嵌套

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 中断控制器,,添加了中断优先级等功能。。

最近编辑记录 XIVN1987 (2024-04-15 12:40:43)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn