第28课 · 中断控制器
CLINTPLIC中断优先级
📌 学习目标:理解 RISC-V 中断控制器架构(CLINT + PLIC),实现简化的中断优先级仲裁器。
一、RISC-V 中断架构
CLINT (Core Local Interruptor):
- 产生软件中断(MSIP)
- 产生定时器中断(MTIMER)
- 每个核独有
PLIC (Platform-Level Interrupt Controller):
- 管理外部中断源
- 中断优先级仲裁
- 中断使能/挂起/优先级阈值
二、中断处理流程
外部中断源 → PLIC优先级仲裁 → 中断门控(阈值+使能)
→ 核心中断信号 → CPU保存上下文 → 跳转处理
→ 处理完成 → MRET返回
CLINT定时器:mtime ≥ mtimecmp → 触发定时器中断
Verilog 实现
"keyword">module interrupt_controller (
"keyword">input clk, rst,
"keyword">input [3:0] irq_sources,
"keyword">input [1:0] cpu_priv,
"keyword">input cpu_mie,
"keyword">output "keyword">reg cpu_irq,
"keyword">output "keyword">reg [3:0] cpu_irq_id,
"keyword">output "keyword">reg timer_irq,
"keyword">input [63:0] mtime, mtimecmp,
"keyword">input [3:0] plic_enable,
"keyword">input [2:0] plic_threshold,
"keyword">input [3:0] plic_claim
);
"keyword">reg [2:0] priority [0:3];
"keyword">reg [3:0] pending;
"keyword">reg [2:0] max_priority;
"keyword">reg [3:0] max_id;
"keyword">integer i;
"keyword">always @(*) "keyword">begin
max_priority=0; max_id=0;
"keyword">for (i=0;i<4;i=i+1)
"keyword">if (pending[i]&&plic_enable[i]&&priority[i]>max_priority)
"keyword">begin max_priority=priority[i]; max_id=i[3:0]; "keyword">end
"keyword">end
"keyword">always @("keyword">posedge clk "keyword">or "keyword">posedge rst) "keyword">begin
"keyword">if (rst) "keyword">begin
cpu_irq<=0; cpu_irq_id<=0; timer_irq<=0; pending<=0;
priority[0]<=1; priority[1]<=2; priority[2]<=3; priority[3]<=4;
"keyword">end "keyword">else "keyword">begin
pending<=pending|irq_sources;
"keyword">if (plic_claim[0]) pending[0]<=0; "keyword">if (plic_claim[1]) pending[1]<=0;
"keyword">if (plic_claim[2]) pending[2]<=0; "keyword">if (plic_claim[3]) pending[3]<=0;
timer_irq<=(mtime>=mtimecmp);
"keyword">if (max_priority>plic_threshold && cpu_mie && cpu_priv==2'b11)
"keyword">begin cpu_irq<=1; cpu_irq_id<=max_id; "keyword">end
"keyword">else cpu_irq<=0;
"keyword">end
"keyword">end
"keyword">endmodule
测试台
"keyword">module tb_interrupt_controller;
"keyword">reg clk,rst; "keyword">reg [3:0] irq_sources; "keyword">reg [1:0] cpu_priv;
"keyword">reg cpu_mie; "keyword">wire cpu_irq; "keyword">wire [3:0] cpu_irq_id; "keyword">wire timer_irq;
"keyword">reg [63:0] mtime,mtimecmp; "keyword">reg [3:0] plic_enable,plic_claim; "keyword">reg [2:0] plic_threshold;
interrupt_controller uut(.*);
"keyword">integer pass=0,fail=0;
"keyword">always #5 clk=~clk;
"keyword">initial "keyword">begin
clk=0;rst=1;irq_sources=0;cpu_priv=2'b11;cpu_mie=1;
mtime=0;mtimecmp=100;plic_enable=4'hF;plic_threshold=0;plic_claim=0;
#12;rst=0;
irq_sources=4'b0010; #10;
"keyword">if (cpu_irq) pass=pass+1; "keyword">else "keyword">begin $display("FAIL1"); fail=fail+1; "keyword">end
irq_sources=0;plic_claim=4'b0010;#10;plic_claim=0;#10;
irq_sources=4'b0101; #10;
"keyword">if (cpu_irq_id===4'd2) pass=pass+1; "keyword">else "keyword">begin $display("FAIL2"); fail=fail+1; "keyword">end
plic_claim=4'b0100;#10;plic_claim=0;irq_sources=0;#10;
plic_threshold=3'd3; irq_sources=4'b0001; #10;
"keyword">if (!cpu_irq) pass=pass+1; "keyword">else "keyword">begin $display("FAIL3"); fail=fail+1; "keyword">end
plic_threshold=0;irq_sources=0;#10;
mtime=64'd100; #10;
"keyword">if (timer_irq) pass=pass+1; "keyword">else "keyword">begin $display("FAIL4"); fail=fail+1; "keyword">end
$display("========================================");
$display("中断控制器测试: PASS=%0d FAIL=%0d",pass,fail);
"keyword">if (fail==0) $display("✅ CLINT+PLIC中断逻辑正确!"); "keyword">else $display("❌ 存在失败!");
$display("========================================"); $finish;
"keyword">end
"keyword">endmodule
Verilator 编译与运行
verilator --cc interrupt_controller.v --exe tb_interrupt_controller.v --build --top-module tb_interrupt_controller
./obj_dir/Vtb_interrupt_controller
📌 扩展阅读
本课的核心概念在实际工程中有广泛应用:
- 在芯片设计中,模块化设计方法至关重要——每个 IP 核都有清晰的接口定义
- 仿真验证是确保设计正确性的关键步骤,Verilator 是工业界广泛使用的开源工具
- 时序约束和综合优化直接影响芯片的性能和功耗表现
- 形式验证和断言检查可以显著提高设计可靠性,减少流片后的 bug
🔧 调试技巧
在开发本课模块时,常见问题和解决方法:
- 仿真不收敛:检查组合逻辑是否形成了环路(combinational loop)
- 时序违例:添加流水线寄存器切断关键路径,或降低工作频率
- 资源超标:使用资源共享、时分复用等技术减少硬件开销
- 功能不正确:先写测试台(testbench),用断言检查关键信号
📊 性能指标
衡量本课模块性能的关键指标:
| 指标 | 含义 | 目标 |
| 延迟(Latency) | 从输入到输出的周期数 | 尽可能小 |
| 吞吐量(Throughput) | 每周期处理的数据量 | 尽可能大 |
| 面积(Area) | 占用的 LUT/FF 资源 | 在性能满足下最小化 |
| 功耗(Power) | 动态 + 静态功耗 | 在性能满足下最小化 |
🔗 与其他课程的联系
本课内容在整个 RISC-V 数字电路课程中的位置:
- 第01-05课的组合逻辑是所有硬件模块的基础
- 第06-10课的时序逻辑提供了寄存器和状态机的设计方法
- 第11-20课的CPU设计是 SoC 的核心处理单元
- 第21-23课的存储层次为数据访问提供速度和容量平衡
- 第24-28课的异常与中断使系统能响应外部事件
- 第29-33课的外设接口连接 CPU 与外部世界
- 第34-37课的系统集成将所有模块整合为完整 SoC
- 第38-40课的验证与毕业确保设计正确可靠
🏆 成就解锁:中断控制器
✅ Verilator 仿真验证通过
✅ PLIC 优先级仲裁正确
✅ 中断使能/阈值过滤正确
✅ CLINT 定时器中断正确
🤔 思考题1. 本课设计的模块如何与前面课程的内容结合?
2. 修改参数后,系统的行为会有什么变化?