第25课 · 特权架构

M/S/U模式特权级切换ecall/mret

📌 学习目标:理解 RISC-V 三级特权架构(M/S/U),实现特权级切换和 ecall/mret 指令处理。

一、RISC-V 特权级

级别缩写编码典型用途
机器模式M11最高权限,直接访问所有资源
监管者模式S01操作系统内核
用户模式U00用户应用程序

二、特权级切换机制

特权级提升(低→高):
  U → S : ecall(系统调用)
  S → M : ecall(请求机器服务)
  任何 → M : 异常/中断

特权级降低(高→低):
  M → S : mret(MPP=S)
  S → U : sret(SPP=U)

三、mstatus 关键字段

[12:11] MPP  - 之前的特权级
[7]     MPIE - 之前的中断使能
[3]     MIE  - 机器模式中断使能

进入异常:MPP ← 当前特权级, MPIE ← MIE, MIE ← 0
MRET返回:特权级 ← MPP, MIE ← MPIE

Verilog 实现

// privilege_controller.v — 特权级控制器 "keyword">module privilege_controller ( "keyword">input clk, rst, "keyword">input [1:0] current_priv, "keyword">input ecall, mret, sret, exception_occurs, "keyword">output "keyword">reg [1:0] next_priv, "keyword">output "keyword">reg [31:0] mstatus_out, "keyword">output "keyword">reg priv_changed ); "keyword">reg [1:0] mpp; "keyword">reg mpie, mie; "keyword">reg spp, spie, sie; "keyword">always @("keyword">posedge clk "keyword">or "keyword">posedge rst) "keyword">begin "keyword">if (rst) "keyword">begin mpp<=0; mpie<=0; mie<=0; spp<=0; spie<=0; sie<=0; next_priv<=2'b11; priv_changed<=0; mstatus_out<=0; "keyword">end "keyword">else "keyword">begin priv_changed<=0; "keyword">if (ecall) "keyword">begin "keyword">case (current_priv) 2'b00: next_priv<=2'b01; 2'b01: next_priv<=2'b11; 2'b11: next_priv<=2'b11; "keyword">endcase "keyword">if (next_priv==2'b11) "keyword">begin mpp<=current_priv; mpie<=mie; mie<=0; "keyword">end "keyword">else "keyword">begin spp<=current_priv[0]; spie<=sie; sie<=0; "keyword">end priv_changed<=1; "keyword">end "keyword">if (mret) "keyword">begin next_priv<=mpp; mie<=mpie; mpie<=1; mpp<=0; priv_changed<=1; "keyword">end "keyword">if (sret) "keyword">begin next_priv<={1'b0,spp}; sie<=spie; spie<=1; spp<=0; priv_changed<=1; "keyword">end "keyword">if (exception_occurs && !ecall) "keyword">begin next_priv<=2'b11; mpp<=current_priv; mpie<=mie; mie<=0; priv_changed<=1; "keyword">end mstatus_out<={12'b0,mpp,4'b0,mpie,3'b0,mie,3'b0}; "keyword">end "keyword">end "keyword">endmodule

测试台

// tb_privilege_controller.v "keyword">module tb_privilege_controller; "keyword">reg clk,rst; "keyword">reg [1:0] current_priv; "keyword">reg ecall,mret,sret,exception_occurs; "keyword">wire [1:0] next_priv; "keyword">wire [31:0] mstatus_out; "keyword">wire priv_changed; privilege_controller uut(.*); "keyword">integer pass=0,fail=0; "keyword">always #5 clk=~clk; "keyword">initial "keyword">begin clk=0;rst=1;current_priv=0;ecall=0;mret=0;sret=0;exception_occurs=0; #12;rst=0; current_priv=2'b00; ecall=1; #10; "keyword">if (next_priv===2'b01 && priv_changed) pass=pass+1; "keyword">else "keyword">begin $display("FAIL1"); fail=fail+1; "keyword">end ecall=0; #10; current_priv=2'b01; ecall=1; #10; "keyword">if (next_priv===2'b11) pass=pass+1; "keyword">else "keyword">begin $display("FAIL2"); fail=fail+1; "keyword">end ecall=0; #10; mret=1; #10; "keyword">if (next_priv===2'b01) pass=pass+1; "keyword">else "keyword">begin $display("FAIL3"); fail=fail+1; "keyword">end mret=0; #10; current_priv=2'b00; exception_occurs=1; #10; "keyword">if (next_priv===2'b11) pass=pass+1; "keyword">else "keyword">begin $display("FAIL4"); fail=fail+1; "keyword">end exception_occurs=0; #10; $display("========================================"); $display("特权级切换测试: PASS=%0d FAIL=%0d",pass,fail); "keyword">if (fail==0) $display("✅ 特权级切换全部正确!"); "keyword">else $display("❌ 存在失败!"); $display("========================================"); $finish; "keyword">end "keyword">endmodule

Verilator 编译与运行

verilator --cc privilege_controller.v --exe tb_privilege_controller.v --build --top-module tb_privilege_controller ./obj_dir/Vtb_privilege_controller

📌 扩展阅读

本课的核心概念在实际工程中有广泛应用:

🔧 调试技巧

在开发本课模块时,常见问题和解决方法:

📊 性能指标

衡量本课模块性能的关键指标:

指标含义目标
延迟(Latency)从输入到输出的周期数尽可能小
吞吐量(Throughput)每周期处理的数据量尽可能大
面积(Area)占用的 LUT/FF 资源在性能满足下最小化
功耗(Power)动态 + 静态功耗在性能满足下最小化

🔗 与其他课程的联系

本课内容在整个 RISC-V 数字电路课程中的位置:

🏆 成就解锁:特权架构

✅ Verilator 仿真验证通过

✅ M/S/U 三级特权切换正确

✅ ECALL 特权提升正确

✅ MRET/SRET 特权降低正确

🤔 思考题

1. 本课设计的模块如何与前面课程的内容结合?

2. 修改参数后,系统的行为会有什么变化?