详细注释tinyriscv项目中的clint.v模块(中断管理模块)

`include "defines.v"


// core local interruptor module
// 核心中断管理、仲裁模块
module clint(

    input wire clk,
    input wire rst,

    // from if_id
    input wire[`INT_BUS] int_flag_i,         // 外设的中断信号

    // from id
    input wire[`InstBus] inst_i,             // 当前正在执行的指令
    input wire[`InstAddrBus] inst_addr_i,    // 当前正在执行的指令的地址

    // from ex
    input wire jump_flag_i,                  // 跳转标志
    input wire[`InstAddrBus] jump_addr_i,    // 将要跳转的地址
    input wire div_started_i,                // 将要执行除法

    // from ctrl
    input wire[`Hold_Flag_Bus] hold_flag_i,  // 暂停标志

    // from csr_reg
    input wire[`RegBus] data_i,              // CSR寄存器输入数据
    input wire[`RegBus] csr_mtvec,           // mtvec寄存器值
    input wire[`RegBus] csr_mepc,            // mepc寄存器值
    input wire[`RegBus] csr_mstatus,         // mstatus寄存器值

    input wire global_int_en_i,              // 全局中断使能标志

    // to ctrl
    output wire hold_flag_o,                 // 向ctrl模块请求暂停流水线申请

    // to csr_reg
    // 中断管理模块配置csr寄存器模块
    output reg we_o,                         // 写CSR寄存器标志
    output reg[`MemAddrBus] waddr_o,         // 写CSR寄存器地址
    output reg[`MemAddrBus] raddr_o,         // 读CSR寄存器地址
    output reg[`RegBus] data_o,              // 写CSR寄存器数据

    // to ex
    output reg[`InstAddrBus] int_addr_o,     // 中断入口地址
    output reg int_assert_o                  // 中断标志

    );


    // 中断状态空间定义
    localparam S_INT_IDLE            = 4'b0001; // 空闲
    localparam S_INT_SYNC_ASSERT     = 4'b0010; // 同步中断_生效 :异常原因能够被精确定位至某条指令,如非法指令
    localparam S_INT_ASYNC_ASSERT    = 4'b0100; // 异步中断_生效 :异常原因不能够被精确定位至某条指令,如外部中断
    localparam S_INT_MRET            = 4'b1000; // 中断返回

    // 写CSR寄存器状态空间定义
    localparam S_CSR_IDLE            = 5'b00001; // 空闲
    localparam S_CSR_MSTATUS         = 5'b00010; // 正在写mstatus寄存器(中断开始时写)
    localparam S_CSR_MEPC            = 5'b00100; // 正在写mepc寄存器
    localparam S_CSR_MSTATUS_MRET    = 5'b01000; // 正在写mstatus寄存器(中断返回时写)
    localparam S_CSR_MCAUSE          = 5'b10000; // 正在写mcause寄存器

    reg[3:0] int_state; // 中断状态
    reg[4:0] csr_state; // 写CSR寄存器状态
    reg[`InstAddrBus] inst_addr; // 当前执行的指令地址
    reg[31:0] cause; // 中断原因

    // 当中断状态或者写寄存器状态不空闲,发出申请暂停流水线信号
    assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;


    // 中断仲裁逻辑
    // 中断状态转换
    always @ (*) begin
        if (rst == `RstEnable) begin
            int_state = S_INT_IDLE; //复位时,中断空闲
        end else begin
            //先处理同步中断
            if (inst_i == `INST_ECALL || inst_i == `INST_EBREAK) begin // 当前执行的指令为ecall与eback时
                // 如果执行阶段的指令为除法指令,则先不处理同步中断,等除法指令执行完再处理
                if (div_started_i == `DivStop) begin // 除法指令已完成
                    int_state = S_INT_SYNC_ASSERT; // 中断状态转换为同步中断
                end else begin
                    int_state = S_INT_IDLE; //否则,除法指令未完成,中断状态空闲
                end
            // 再处理异步中断
            end else if (int_flag_i != `INT_NONE && global_int_en_i == `True) begin // 有外设中断信号且全局中断使能标志为真
                int_state = S_INT_ASYNC_ASSERT; // 中断状态转换为异步中断
            // 退出中断
            end else if (inst_i == `INST_MRET) begin // 当前执行的指令为mret时
                int_state = S_INT_MRET; // 中断状态转换为中断返回
            // 无中断
            end else begin
                int_state = S_INT_IDLE; // 无情况,中断空闲
            end
        end
    end

    // 写CSR寄存器状态切换
    always @ (posedge clk) begin
        // 复位时初始化
        if (rst == `RstEnable) begin
            csr_state <= S_CSR_IDLE; // 复位时,写寄存器状态空闲
            cause <= `ZeroWord; // 复位初始化
            inst_addr <= `ZeroWord; // 复位初始化
        end else begin
            case (csr_state) // 判断当前写CSR寄存器状态
                S_CSR_IDLE: begin //写寄存器状态空闲时
                    // 同步中断
                    if (int_state == S_INT_SYNC_ASSERT) begin // 当同步中断生效时
                        csr_state <= S_CSR_MEPC; // 写CSR寄存器状态装换为:正在写mepc寄存器
                        if (jump_flag_i == `JumpEnable) begin // 如果有当前即将要跳转,保存即将要跳转的指令地址
                            inst_addr <= jump_addr_i - 4'h4; // 在同步中断处理函数里会将中断返回地址加4,因此此处要-4'h4
                        end else begin
                            inst_addr <= inst_addr_i; //不需要跳转,保存当前指令地址
                        end
                        case (inst_i) // 判断当前指令,确定中断原因
                            `INST_ECALL: begin
                                cause <= 32'd11;
                            end
                            `INST_EBREAK: begin
                                cause <= 32'd3;
                            end
                            default: begin
                                cause <= 32'd10;
                            end
                        endcase
                    // 异步中断
                    end else if (int_state == S_INT_ASYNC_ASSERT) begin // 当异步中断生效时
                        cause <= 32'h80000004; // 定时器中断(好像只支持定时器中断?)
                        csr_state <= S_CSR_MEPC; // 写CSR寄存器状态装换为:正在写mepc寄存器
                        if (jump_flag_i == `JumpEnable) begin // 如果有当前即将要跳转,保存即将要跳转的指令地址
                            inst_addr <= jump_addr_i; // 在异步中断处理函数里不会将中断返回地址加4,因此此处不需要-4'h4
                        // 异步中断可以中断除法指令的执行,中断处理完再重新执行除法指令
                        end else if (div_started_i == `DivStart) begin // 如果正在进行除法操作
                            inst_addr <= inst_addr_i - 4'h4; // 保存当前指令的前一条指令地址,以便中断服务完成后从新执行这条除法指令
                        end else begin
                            inst_addr <= inst_addr_i; // 无其他情况,保存当前执行的指令地址
                        end
                    // 中断返回
                    end else if (int_state == S_INT_MRET) begin
                        csr_state <= S_CSR_MSTATUS_MRET; // 写CSR寄存器状态装换为:正在写mstatus寄存器(中断返回时写)
                    end
                end
                // 状态机流转,写CSR寄存器状态装换为 正在写mepc寄存器 之后
                S_CSR_MEPC: begin
                    csr_state <= S_CSR_MSTATUS; // 写完mepc寄存器后写mstatus寄存器(中断开始时写)
                end
                S_CSR_MSTATUS: begin
                    csr_state <= S_CSR_MCAUSE; // 写完mstatus寄存器后写mcause寄存器
                end
                S_CSR_MCAUSE: begin
                    csr_state <= S_CSR_IDLE; // 写完mcause寄存器后状态置为空闲
                end
                S_CSR_MSTATUS_MRET: begin
                    csr_state <= S_CSR_IDLE; // 中断返回时写完mstatus寄存器后状态置为空闲
                end
                default: begin
                    csr_state <= S_CSR_IDLE; // 默认空闲
                end
            endcase
        end
    end

    // 发出中断信号前,先写几个CSR寄存器
    always @ (posedge clk) begin
        if (rst == `RstEnable) begin
            we_o <= `WriteDisable; // 复位初始化
            waddr_o <= `ZeroWord; // 复位初始化
            data_o <= `ZeroWord; // 复位初始化
        end else begin
            case (csr_state)
                 // 将mepc寄存器的值设为当前指令地址
                S_CSR_MEPC: begin
                    we_o <= `WriteEnable; // 写使能
                    waddr_o <= {20'h0, `CSR_MEPC}; // mepc寄存器地址
                    data_o <= inst_addr; // 写入保存到的地址
                end
                // 写中断产生的原因
                S_CSR_MCAUSE: begin
                    we_o <= `WriteEnable; // 写使能
                    waddr_o <= {20'h0, `CSR_MCAUSE}; // mcause寄存器地址
                    data_o <= cause; // 写入获取到的原因
                end
                // 关闭全局中断
                S_CSR_MSTATUS: begin
                    we_o <= `WriteEnable; // 写使能
                    waddr_o <= {20'h0, `CSR_MSTATUS}; // mstatus寄存器地址
                    data_o <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]}; //寄存器第3位置1'b0,表示关闭全局中断
                    // RISC-V架构规定:中断发生时,中断全局关闭,所有的中断都将屏蔽
                end
                // 中断返回
                S_CSR_MSTATUS_MRET: begin
                    we_o <= `WriteEnable; // 写使能
                    waddr_o <= {20'h0, `CSR_MSTATUS}; // mstatus寄存器地址
                    // RISC-V架构规定中断发生后,mstatus[7]保存中断发生前mstatus[3]的值
                    // 相当于退出中断后利用mstatus[7]将mstatus[3]恢复为中断发生前的状态
                    data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};                                                                 

                end
                default: begin 
                    we_o <= `WriteDisable; // 默认
                    waddr_o <= `ZeroWord; // 默认
                    data_o <= `ZeroWord; // 默认
                end
            endcase
        end
    end

    // 发出中断信号给ex模块
    always @ (posedge clk) begin
        if (rst == `RstEnable) begin
            int_assert_o <= `INT_DEASSERT; // 复位初始化
            int_addr_o <= `ZeroWord; // 复位初始化
        end else begin
            case (csr_state)
                // 发出中断进入信号.写完mcause寄存器才能发
                S_CSR_MCAUSE: begin
                    int_assert_o <= `INT_ASSERT;
                    int_addr_o <= csr_mtvec; // 从mtvec定义的PC地址开始执行,将此地址发送给ex模块
                end
                // 发出中断返回信号
                S_CSR_MSTATUS_MRET: begin
                    int_assert_o <= `INT_ASSERT;
                    int_addr_o <= csr_mepc; // 从mepc保存的PC地址开始执行,将此地址发送给ex模块
                end
                default: begin
                    int_assert_o <= `INT_DEASSERT; // 默认
                    int_addr_o <= `ZeroWord; // 默认
                end
            endcase
        end
    end

endmodule
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值