目录整理:RTL/上板/仿真分开存放,测试 ROM 镜像归入 testbench/rom
- rtl/:12 个可综合的处理器源文件(顶层 cpu21_riscv_redirect_int_bpb.v,其余为各功能单元)。 - board/:板级顶层 cpu21_board_top.v、引脚约束 cpu21_board_top.xdc、片内 ROM 初始化 cpu21_board_rom.vh 与短延时版本 cpu21_board_rom_fast.vh。 - testbench/:保留三个测试平台;ROM 镜像统一放到 testbench/rom/,测试程序源码与期望值 仍在 testbench/programs/(其中的 .hex 是 RARS 原始输出,与 rom/ 里改过显示方式的版本 内容不同,两者都保留)。 - 同步更新:两个测试平台的 ROM 探测路径改为 testbench/rom/(并在头注释里补充说明: PowerShell 会把 -generic_top/--testplusarg 参数里的 "=" 拆开、Verilog 字符串中的 路径要用正斜杠);tools/hex2vh.py 的用法示例指向 board/cpu21_board_top.v; 说明文档新增“目录结构”一节并同步所有路径引用;.gitignore 补充 .Xil/。 - 清理:删除 *.hex.lst 中间文件与空的 .Xil/ 目录。 - 验证:isa_test 24/24、lui_test 4/4、mmio_test 5/5 三项回归通过;两个基线(5560 / 6003 周期)与整理前一致;板级仿真(默认 ROM 首次写入 LED=0001、快速 ROM 跑马灯循环)正常; Vivado 工程源文件路径同步到 rtl/ 与 board/ 后综合通过(LUT 5276、23 个引脚,与整理前 完全一致),因此已有 bit 文件仍然有效。
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 中断控制器 + ustatus/uepc CSR + 嵌套返回栈。
|
||||
//
|
||||
// IRQ3 优先级最高,其次 IRQ2,最后 IRQ1;嵌套请求只有优先级高于当前级别
|
||||
// 才会被接纳。中断入口地址由优先级选出,返回地址保存在 epc_stack 中,
|
||||
// 当前上下文的活动返回 PC 放在 uepc_q(与课程讲义用 CSRRW 保存/恢复
|
||||
// uepc 的流程一致)。
|
||||
// -----------------------------------------------------------------------------
|
||||
module cpu21_riscv_irq_ctrl #(
|
||||
parameter [31:0] IRQ1_VECTOR = 32'h0000_30ac,
|
||||
parameter [31:0] IRQ2_VECTOR = 32'h0000_31e4,
|
||||
parameter [31:0] IRQ3_VECTOR = 32'h0000_3310,
|
||||
parameter IRQ_STACK_DEPTH = 4,
|
||||
// ustatus 复位值。bit0 为 MIE。课程的中断测试程序只会在中断处理
|
||||
// 程序中设置 MIE,若复位后不立即置位 MIE,主程序将永远无法响应
|
||||
// 第一次中断,因此这里默认打开 MIE。
|
||||
parameter [31:0] USTATUS_INIT = 32'h0000_0001
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
input wire [ 2:0] irq_i,
|
||||
input wire halted_i,
|
||||
// EX 级正在处理重定向/URET/停机,此时不允许响应中断
|
||||
input wire ex_block_i,
|
||||
// 中断发生时要保存的返回地址(由顶层根据流水线状态给出)
|
||||
input wire [31:0] save_pc_i,
|
||||
// EX 级的 URET
|
||||
input wire uret_i,
|
||||
// EX 级 CSR 指令(CSRRW/CSRRSI/CSRRCI)
|
||||
input wire csr_valid_i,
|
||||
input wire csr_set_i,
|
||||
input wire csr_clear_i,
|
||||
input wire csr_write_i,
|
||||
input wire [11:0] csr_addr_i,
|
||||
input wire [31:0] csr_imm_i,
|
||||
input wire [31:0] csr_wdata_i,
|
||||
// 控制结果
|
||||
output wire take_irq_o,
|
||||
output wire [31:0] vector_o,
|
||||
output wire [31:0] return_pc_o,
|
||||
output wire [ 2:0] pending_o,
|
||||
output wire [ 1:0] level_o,
|
||||
output wire [31:0] uepc_o,
|
||||
output wire [31:0] ustatus_o
|
||||
);
|
||||
reg [31:0] ustatus_q;
|
||||
reg [31:0] uepc_q;
|
||||
reg [ 1:0] irq_current_q;
|
||||
reg [ 2:0] irq_pending_q;
|
||||
reg [ 2:0] irq_sync1_q;
|
||||
reg [ 2:0] irq_sync2_q;
|
||||
reg [ 2:0] irq_prev_q;
|
||||
reg [31:0] epc_stack [0:IRQ_STACK_DEPTH-1];
|
||||
reg [31:0] status_stack [0:IRQ_STACK_DEPTH-1];
|
||||
reg [ 1:0] priority_stack [0:IRQ_STACK_DEPTH-1];
|
||||
reg [ 2:0] irq_depth_q;
|
||||
|
||||
reg irq_selected_valid;
|
||||
reg [ 1:0] irq_selected_level;
|
||||
reg [31:0] irq_vector;
|
||||
reg [ 2:0] irq_pending_d;
|
||||
reg [31:0] ustatus_d;
|
||||
reg [31:0] uepc_d;
|
||||
|
||||
integer s;
|
||||
|
||||
// 上升沿检测:只在 irq_i 由 0 变 1 的那一拍产生中断事件。
|
||||
wire [ 2:0] irq_event = irq_sync2_q & ~irq_prev_q;
|
||||
|
||||
// 优先级仲裁:在当前级别允许的条件下选出优先级最高的中断源。
|
||||
always @* begin
|
||||
irq_selected_valid = 1'b0;
|
||||
irq_selected_level = 2'd0;
|
||||
if (irq_pending_q[2] && (irq_current_q < 2'd3)) begin
|
||||
irq_selected_valid = 1'b1;
|
||||
irq_selected_level = 2'd3;
|
||||
end else if (irq_pending_q[1] && (irq_current_q < 2'd2)) begin
|
||||
irq_selected_valid = 1'b1;
|
||||
irq_selected_level = 2'd2;
|
||||
end else if (irq_pending_q[0] && (irq_current_q < 2'd1)) begin
|
||||
irq_selected_valid = 1'b1;
|
||||
irq_selected_level = 2'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// 依据被选中的优先级选择对应的中断入口地址。
|
||||
always @* begin
|
||||
case (irq_selected_level)
|
||||
2'd1: irq_vector = IRQ1_VECTOR;
|
||||
2'd2: irq_vector = IRQ2_VECTOR;
|
||||
2'd3: irq_vector = IRQ3_VECTOR;
|
||||
default: irq_vector = IRQ1_VECTOR;
|
||||
endcase
|
||||
end
|
||||
|
||||
// 响应中断的条件:有已选中中断、MIE 使能、栈未溢出、未停机,且没有
|
||||
// 正在处理的重定向/URET/停机事件。
|
||||
assign take_irq_o = irq_selected_valid && ustatus_q[0] &&
|
||||
(irq_depth_q < IRQ_STACK_DEPTH) && !halted_i &&
|
||||
!ex_block_i;
|
||||
|
||||
assign vector_o = irq_vector;
|
||||
assign return_pc_o = uepc_q;
|
||||
assign pending_o = irq_pending_q;
|
||||
assign level_o = irq_current_q;
|
||||
assign uepc_o = uepc_q;
|
||||
assign ustatus_o = ustatus_q;
|
||||
|
||||
// 组合逻辑计算下一拍的挂起位与 CSR(ustatus/uepc)取值。
|
||||
always @* begin
|
||||
irq_pending_d = irq_pending_q | irq_event;
|
||||
if (take_irq_o) begin
|
||||
case (irq_selected_level)
|
||||
2'd1: irq_pending_d[0] = 1'b0;
|
||||
2'd2: irq_pending_d[1] = 1'b0;
|
||||
2'd3: irq_pending_d[2] = 1'b0;
|
||||
default: irq_pending_d = irq_pending_d;
|
||||
endcase
|
||||
end
|
||||
|
||||
ustatus_d = ustatus_q;
|
||||
uepc_d = uepc_q;
|
||||
if (csr_valid_i && csr_set_i) begin
|
||||
if (csr_addr_i == 12'h004) ustatus_d = ustatus_q | csr_imm_i;
|
||||
else if (csr_addr_i == 12'h041) uepc_d = uepc_q | csr_imm_i;
|
||||
end else if (csr_valid_i && csr_clear_i) begin
|
||||
if (csr_addr_i == 12'h004) ustatus_d = ustatus_q & ~csr_imm_i;
|
||||
else if (csr_addr_i == 12'h041) uepc_d = uepc_q & ~csr_imm_i;
|
||||
end else if (csr_valid_i && csr_write_i) begin
|
||||
if (csr_addr_i == 12'h004) ustatus_d = csr_wdata_i;
|
||||
else if (csr_addr_i == 12'h041) uepc_d = csr_wdata_i;
|
||||
end
|
||||
|
||||
if (take_irq_o) ustatus_d[0] = 1'b0;
|
||||
else if (uret_i && (irq_depth_q != 0)) ustatus_d = status_stack[irq_depth_q-1'b1];
|
||||
|
||||
if (take_irq_o) uepc_d = save_pc_i;
|
||||
else if (uret_i && (irq_depth_q > 1)) uepc_d = epc_stack[irq_depth_q-2];
|
||||
else if (uret_i && (irq_depth_q == 1)) uepc_d = 32'b0;
|
||||
end
|
||||
|
||||
// 复位时清空中断状态与嵌套栈。
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
ustatus_q <= USTATUS_INIT;
|
||||
uepc_q <= 32'b0;
|
||||
irq_current_q <= 2'b0;
|
||||
irq_pending_q <= 3'b0;
|
||||
irq_sync1_q <= 3'b0;
|
||||
irq_sync2_q <= 3'b0;
|
||||
irq_prev_q <= 3'b0;
|
||||
irq_depth_q <= 3'b0;
|
||||
for (s = 0; s < IRQ_STACK_DEPTH; s = s + 1) begin
|
||||
epc_stack[s] <= 32'b0;
|
||||
status_stack[s] <= 32'b0;
|
||||
priority_stack[s] <= 2'b0;
|
||||
end
|
||||
end else begin
|
||||
// 中断输入打两拍同步,并锁存挂起状态与 CSR。
|
||||
irq_sync1_q <= irq_i;
|
||||
irq_sync2_q <= irq_sync1_q;
|
||||
irq_prev_q <= irq_sync2_q;
|
||||
irq_pending_q <= irq_pending_d;
|
||||
ustatus_q <= ustatus_d;
|
||||
uepc_q <= uepc_d;
|
||||
|
||||
if (take_irq_o) begin
|
||||
if (irq_depth_q < IRQ_STACK_DEPTH) begin
|
||||
epc_stack[irq_depth_q] <= save_pc_i;
|
||||
status_stack[irq_depth_q] <= ustatus_q;
|
||||
priority_stack[irq_depth_q] <= irq_current_q;
|
||||
irq_depth_q <= irq_depth_q + 3'd1;
|
||||
end
|
||||
irq_current_q <= irq_selected_level;
|
||||
end else if (uret_i) begin
|
||||
if (irq_depth_q != 0) begin
|
||||
irq_depth_q <= irq_depth_q - 3'd1;
|
||||
irq_current_q <= priority_stack[irq_depth_q-1'b1];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
Reference in New Issue
Block a user