中断处理 — Interrupt Handling

优先级排序与中断响应机制

📖 RISC-V中断类型

RISC-V定义了三种中断源,每个特权级各有一组:

中断mip位mie位cause来源
Machine Software IntMSIP(3)MSIE(3)2147483651软件中断(核间通信)
Machine Timer IntMTIP(7)MTIE(7)2147483655CLINT定时器
Machine External IntMEIP(11)MEIE(11)2147483659PLIC外部设备
Supervisor Software IntSSIP(1)SSIE(1)2147483649S-mode软件中断
Supervisor Timer IntSTIP(5)STIE(5)2147483653S-mode定时器
Supervisor External IntSEIP(9)SEIE(9)2147483657S-mode外部中断
中断优先级 (从高到低): ┌──────────────────────────────────────┐ │ MEI (外部中断) → 最高优先级 │ │ MSI (软件中断) → 次高 │ │ MTI (定时器中断) → 第三 │ │ SEI (S外部中断) → 第四 │ │ SSI (S软件中断) → 第五 │ │ STI (S定时器中断) → 最低 │ └──────────────────────────────────────┘ 中断使能条件: mie[x] = 1 AND mip[x] = 1 AND mstatus.MIE = 1 (或在更低特权级时,MIE可以为0)

🔬 中断响应时序

中断响应时序: 时钟: ──┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ mip: ──────────────╱────────────────── 中断源拉高 采样: ──────╱────────────── 上升沿采样 响应: ──╱──────────── PC←mtvec 关键延迟: 从mip拉高到PC跳转 = 2个时钟周期 (1周期采样 + 1周期跳转)
RISC-V的中断是电平触发的:mip由中断源保持,直到软件处理完毕并通知中断源撤销。这与ARM的边沿触发不同。

🖥️ Verilog实现:中断优先级选择器

// Lesson 06: Interrupt Handling — Priority-based selection
module interrupt_handler(
    input  wire        clk, rst_n,
    input  wire [11:0] mie_val, mip_val,
    input  wire        mstatus_mie,
    input  wire [1:0]  current_priv,
    output reg  [31:0] int_cause,
    output reg         int_taken,
    output reg  [3:0]  int_id
);
    localparam PRV_M = 2'b10;
    wire mie_mei = mie_val[11] & mip_val[11];
    wire mie_msi = mie_val[3]  & mip_val[3];
    wire mie_mti = mie_val[7]  & mip_val[7];
    wire mie_sei = mie_val[9]  & mip_val[9];
    wire mie_ssi = mie_val[1]  & mip_val[1];
    wire mie_sti = mie_val[5]  & mip_val[5];

    reg int_pending; reg [31:0] sel_cause; reg [3:0] sel_id;
    always @(*) begin
        int_pending = 0; sel_cause = 0; sel_id = 0;
        if (mstatus_mie || current_priv < PRV_M) begin
            if (mie_mei) begin int_pending=1; sel_cause=32'h8000000B; sel_id=6; end
            else if (mie_msi) begin int_pending=1; sel_cause=32'h80000003; sel_id=3; end
            else if (mie_mti) begin int_pending=1; sel_cause=32'h80000007; sel_id=7; end
            else if (mie_sei) begin int_pending=1; sel_cause=32'h80000009; sel_id=9; end
            else if (mie_ssi) begin int_pending=1; sel_cause=32'h80000001; sel_id=1; end
            else if (mie_sti) begin int_pending=1; sel_cause=32'h80000005; sel_id=5; end
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin int_cause <= 0; int_taken <= 0; int_id <= 0; end
        else begin
            int_taken <= int_pending;
            if (int_pending) begin int_cause <= sel_cause; int_id <= sel_id; end
        end
    end
endmodule
Verilator仿真验证通过 — 中断优先级排序正确

代码解析

🧪 实验练习

  1. 添加中断嵌套:在M-mode handler中重新使能MIE
  2. 实现S-mode中断:通过mideleg将中断委托给S-mode
  3. 添加中断优先级配置:可编程的优先级排序
  4. 实现中断抢占:高优先级中断可以抢占低优先级
中断优先级排序正确
思考题:如果MEI和MTI同时pending,处理器响应哪个?如果MTI先响应了,MEI还能被处理吗?
参考资料:RISC-V Privileged Spec §3.1.9 | CLINT中断时序 | PLIC与中断优先级

🔗 中断在实时系统中的应用

实时操作系统(RTOS)对中断延迟有严格要求:

指标定义典型值(RISC-V)
中断延迟从IRQ到第一条handler指令20-50 cycles
中断抖动延迟的变化范围5-20 cycles
上下文切换保存/恢复所有寄存器50-100 cycles
中断嵌套深度最大可嵌套层数通常4-8层

RISC-V中断嵌套

中断嵌套流程: M-mode (MIE=0, 刚进入handler): // 保存当前mstatus到栈 csrr t0, mstatus // 重新使能中断, 允许嵌套 csrs mstatus, (1<<3) // MIE = 1 // 现在可以被更高优先级中断抢占! // 处理当前中断... // 禁用中断, 准备返回 csrc mstatus, (1<<3) // MIE = 0 // 恢复mstatus csrw mstatus, t0 mret 关键: MPIE保存了之前的MIE 嵌套时必须用栈保存完整的mstatus

中断嵌套允许高优先级中断抢占低优先级中断的处理。在Linux中,中断处理分为上半部(top half,不可抢占)和下半部(bottom half,可抢占),以平衡实时性和吞吐量。

🎯 本课与整体课程的关系

中断知识图谱: 05 Trap → 06 中断 (本课) ↓ 07 PLIC — 多源中断的优先级路由 08 CLINT — 定时器中断的硬件源 ↓ 中断是异步事件处理的核心机制 与ecall的同步trap形成互补

📚 延伸阅读与参考资料

资料内容链接
RISC-V特权规范CSR、Trap、中断完整定义riscv.org/specifications
RISC-V手册中文版免费教材crva.ict.ac.cn
OpenSBI源码M-mode固件参考实现github.com/riscv/opensbi
Linux RISC-V内核移植与驱动kernel.org
BOOM处理器UC Berkeley开源OoO核心github.com/riscv-boom/riscv-boom
香山处理器中科院开源高性能核心github.com/OpenXiangShan

相关课程

课程范围课程号主题
特权架构01-06特权级→CSR→ecall→mret→trap→中断
内存系统07-12PLIC→CLINT→SV39→TLB→直接映射→组相联
算术单元13-14Booth乘法器→恢复余数除法
乱序执行15-19OoO→ROB→寄存器重命名→记分牌→Tomasulo
分支预测20-212位预测器→BTB
RISC-V扩展22-26RVC→RVM→RVA→RVF→RVD
系统集成27-30PMP→解码器→SoC→启动流程

实验环境搭建

建议使用以下环境进行实验:

📊 中断控制器演进

代际控制器特点代表
第一代简单优先级固定优先级,无嵌套RISC-V CLINT
第二代优先级+路由可配置优先级,多目标路由RISC-V PLIC
第三代高级PLIC(APLIC)支持MSI,更大中断源数RISC-V APLIC
第四代IMSIC每Hart独立中断文件,MSIRISC-V IMSIC

RISC-V最新的中断架构使用IMSC(Incoming Message-Signaled Interrupt Controller),支持MSI(Message-Signaled Interrupts)——设备直接写内存触发中断,无需专用的IRQ线。这与PCIe的MSI-X机制对应。

中断亲和性与负载均衡

在多核系统中,中断亲和性决定哪个核心处理哪个中断:

🔬 中断控制器的设计空间

中断控制器的设计涉及多个权衡:

中断控制器设计参数: ┌──────────────────────────────────────┐ │ 优先级策略: │ │ • 固定优先级: MEI>MSI>MTI │ │ • 可配置优先级: PLIC模式 │ │ • 动态优先级: 老化/优先级提升 │ │ │ │ 路由策略: │ │ • 广播: 所有Hart都收到 │ │ • 轮询: 依次分配给各Hart │ │ • 亲和性: 绑定到特定Hart │ │ • 最低负载: 选择最空闲的Hart │ │ │ │ 中断类型: │ │ • 电平触发: 持续到设备取消 │ │ • 边沿触发: 一次性脉冲 │ │ • MSI: 写内存触发(PCIe标准) │ └──────────────────────────────────────┘ RISC-V选择: PLIC使用电平触发 + 可配置优先级 这是嵌入式场景最安全的选择: • 电平触发不会丢失中断 • 可配置优先级支持不同设备需求