精确异常:流水线中异常的严格语义保证
精确异常(Precise Exception)是处理器设计的硬性要求:当异常发生时,异常指令之前的所有指令完整执行,异常指令及之后的所有指令仿佛从未执行。
| 异常类型 | RISC-V mcause | 产生阶段 | 检测难度 |
|---|---|---|---|
| 非法指令 | 2 | ID | 易 |
| 断点 | 3 | ID | 易 |
| ecall | 8-11 | EX | 易 |
| 地址不对齐 | 4/6 | MEM | 中 |
| 访问故障 | 5/7 | MEM | 中 |
| 外部中断 | 0x8000000x | 任意 | 难 |
流水线中多个阶段可能同时产生异常,必须按程序序处理——最早的指令异常优先:
// Lesson 35: Pipeline Exception Handling (Precise Exceptions)
module exception_pipeline #(
parameter DATA_W = 32
)(
input wire clk, rst_n,
input wire [DATA_W-1:0] pc_id_i, pc_ex_i, pc_mem_i,
input wire valid_id_i, valid_ex_i, valid_mem_i,
input wire is_store_id_i,
input wire [6:0] opcode_id_i, [2:0] funct3_id_i,
input wire exc_undef_i, // 非法指令
input wire exc_ecall_i, // ecall
input wire exc_misalign_i, // 地址不对齐
input wire exc_load_fault_i, // Load故障
input wire exc_store_fault_i, // Store故障
input wire irq_ext_i, // 外部中断
input wire [DATA_W-1:0] mtvec_i,
output reg [DATA_W-1:0] mepc_o,
output reg [DATA_W-1:0] mcause_o,
output reg trap_o,
output reg flush_all_o,
output reg [DATA_W-1:0] trap_pc_o
);
// 优先级: MEM > EX > ID > 中断
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
mepc_o <= 0; mcause_o <= 0;
trap_o <= 0; flush_all_o <= 0;
end else begin
trap_o <= 0; flush_all_o <= 0;
// MEM阶段异常 (最高优先级)
if (valid_mem_i && exc_store_fault_i) begin
mepc_o <= pc_mem_i; mcause_o <= 32'd7;
trap_o <= 1; flush_all_o <= 1;
trap_pc_o <= mtvec_i;
end else if (valid_mem_i && exc_load_fault_i) begin
mepc_o <= pc_mem_i; mcause_o <= 32'd5;
trap_o <= 1; flush_all_o <= 1;
trap_pc_o <= mtvec_i;
end
// EX阶段异常
else if (valid_ex_i && exc_ecall_i) begin
mepc_o <= pc_ex_i; mcause_o <= 32'd11;
trap_o <= 1; flush_all_o <= 1;
trap_pc_o <= mtvec_i;
end
// ID阶段异常
else if (valid_id_i && exc_undef_i) begin
mepc_o <= pc_id_i; mcause_o <= 32'd2;
trap_o <= 1; flush_all_o <= 1;
trap_pc_o <= mtvec_i;
end
// 外部中断
else if (irq_ext_i) begin
mepc_o <= pc_id_i;
mcause_o <= 32'h8000000B;
trap_o <= 1; flush_all_o <= 1;
trap_pc_o <= mtvec_i;
end
end
end
endmodule
在顺序流水线中,精确异常相对容易实现(冲刷流水线即可)。但在乱序处理器中,指令可能已经执行但还没提交:
| 架构 | 精确异常方案 | 复杂度 |
|---|---|---|
| 顺序流水线 | 冲刷流水线 | 低 |
| 顺序+重排缓冲 | ROB按序提交,异常时清空ROB | 中 |
| 乱序+ROB | 异常指令到ROB头时才触发,之前指令已提交 | 高 |
| 乱序+Checkpoint | 每条指令保存检查点,异常时回滚 | 很高 |