狭义的异常和中断是根据引起异常的原因来区分的,狭义的异常一般是由内因引起的,例如程序故障或者执行特殊的指令,狭义的中断一般是由外因引起的,例如外部中断。广义的异常包括狭义的异常和中断。下面的讨论的异常无特殊说明,都指的是广义的异常。RISC-V有四种工作模式,下面只讨论机器模式(RISC-V处理器核必备的模式)下的异常处理机制。
一、RISC-V架构规定的异常处理机制
1.1 进入异常
在进入异常时,RISC-V架构定义的行为如下:
1.从mtvec定义的PC地址开始执行
RISC-V 架构规定,在处理器的程序执行过程中,一旦遇到异常发生,则终止当前的程序流处理器被强行跳转到一个新的 PC 地址。该过程在 RISC-V 的架构中定义为“陷阱(trap)”,字面含义为“跳入陷阱”,更加准确的意译为“进入异常”。
RISC-V 处理器 trap 后跳入的 PC 地址由一个叫做机器模式异常入口基地址寄存器 mtvec(Machine Trap-Vector Base-Address Register)的 CSR 寄存器指定,其要点如下。
(1)mtvec 寄存器是一个可读可写的 CSR 寄存器,因此软件可以编程更改其中的值。
(2)mtvec 寄存器的详细格式如图 13-1 所示,其中的最低 2 位是 MODE 域,高 30 是BASE 域
• 假设 MODE 的值为 0,则所有的异常响应时处理器均跳转到 BASE 值指示的 PC 地址。
• 假设 MODE 的值为 1,则狭义的异常发生时,处理器跳转到 BASE 值指示的 PC 地址;狭义的中断发生时,处理器跳转到 BASE+4*CAUSE 值指示的 PC 地址。CAUSE的值表示中断对应的异常编号(Exception Code),如图 13-3 所示。譬如机器计时器中断(Machine Timer Interrupt)的异常编号为 7,则其跳转的地址为 BASE+4×7=BASE+28= BASE+0x1c。
2.更新CSR寄存器mcause
RISC-V 架构规定,在进入异常时,机器模式异常原因寄存器 mcause(Machine Cause Register)被同时更新,以反映当前的异常种类,软件可以通过读此寄存器查询造成异常的具体原因。
mcause 寄存器最高 1 位为 Interrupt 域,低 31 位为异常编号域。此两个域的组合表示值如图 13-3 所示,用于指示 RISC-V 架构定义的 12 种中断类型和 16 种异常类型。
3.更新CSR寄存器mepc
RISC-V 架构定义异常的返回地址由机器模式 异常 PC 寄存器 mepc(Machine Exception Program Counter)保存。在进入异常时,硬件将自动更新 mepc 寄存器的值为当前遇到异常的指令 PC 值(即当前程序的停止执行点)。该寄存器将作为异常的返回地址,在异常结束之后,能够使用它保存的PC 值回到之前被停止执行的程序点。
4.更新CSR寄存器mrval
RISC-V 架构规定,在进入异常时,硬件将自动更新机器模式异常值寄存器 mtval(Machine Trap Value Register ),以反映引起当前异常的存储器访问地址或者指令编码。
• 如果是由存储器访问造成的异常,譬如遭遇硬件断点、取指令、存储器读写造成的异常,则将存储器访问的地址更新到 mtval 寄存器中。
• 如果是由非法指令造成的异常,则将该指令的指令编码更新到 mtval 寄存器中。
5.更新CSR寄存器mstatus
RISC-V架构文档规定,当进入异常时,需要更新mstatus(Machine Status Register)中的某些位,mstatus寄存器的格式如下:
• 当该 MIE 域的值为 1 时,表示 Machine Mode 下所有中断的全局打开。
• 当该 MIE 域的值为 0 时,表示 Machine Mode 下所有中断的全局关闭。
RISC-V 架构规定,异常发生时有如下情况。
• MPIE 域的值被更新为异常发生前 MIE 域的值。MPIE 域的作用是在异常结束之后,能够使用 MPIE 的值恢复出异常发生之前的 MIE 值。
• MIE 的值则被更新成为 0(意味着进入异常服务程序后中断被全局关闭,所有的中断都将被屏蔽不响应)。
• MPP 的值被更新为异常发生前的模式。MPP 域的作用是在异常结束之后,能够使用MPP 的值恢复出异常发生之前的工作模式。对于只支持机器模式(Machine Mode Only)的处理器核(譬如蜂鸟 E200),则 MPP 的值永远为二进制值 11。
1.2 退出异常
当程序完成异常处理之后,最终需要从异常服务程序中退出,并返回主程序。RISC-V架构定义了一组专门的退出异常指令(Trap-Return Instructions),包括 MRET、SRET、和URET。其中 MRET 指令是必备的,而 SRET 和 URET 指令仅在支持监督模式和用户模式的处理器中使用。
在机器模式下退出异常时,软件必须使用 MRET 指令。RISC-V 架构规定,处理器执行MRET 指令后的硬件行为如下。
• 停止执行当前程序流,转而从 CSR 寄存器 mepc 定义的 PC 地址开始执行。
• 执行 MRET 指令不仅会让处理器跳转到上述的 PC 地址开始执行,还会让硬件同时更新 CSR 寄存器机器模式状态寄存器 mstatus(Machine Status Register)。
下文将分别予以详述。
1.从 mepc 定义的 PC 地址开始执行。
2.更新 CSR 寄存器 mstatus
mstatus 寄存器的详细格式如图 13-4 所示。RISC-V 架构规定,在执行 MRET 指令后,硬件将自动更新机器模式状态寄存器 mstatus(Machine Status Register)的某些域。
RISC-V 架构规定,执行 MRET 指令退出异常时有如下情况。
• mstatus 寄存器 MIE 域的值被更新为当前 MPIE 的值。
• mstatus 寄存器 MPIE 域的值则被更新为 1。
在进入异常时,MPIE 的值曾经被更新为异常发生前的 MIE 值。而 MRET 指令执行后,再次将 MIE 域的值更新为 MPIE 的值。通过这个机制,则意味着 MRET指令执行后,处理器的 MIE 值被恢复成异常发生之前的值(假设之前的 MIE 值为 1,则意味着中断被重新全局打开)。
1.3 中断类型
RISC-V架构定义了四种中断类型-外部中断、计时器中断、软件中断、调试中断。
外部中断:外部中断是来自处理器核外部的中断,例如由GPIO或者UART串口产生的中断,外部中断的仲裁和派发又PLIC实现。
计时器中断:RISC-V 架构定义了系统平台中必须有一个计时器,并给该计时器定义了两个 64 位宽的寄存器 mtime和 mtimecmp。mtime 寄存器用于反映当前计时器的计数值,mtimecmp 用于设置计时器的比较值。当 mtime 中的计数值大于或者等于mtimecmp 中设置的比较值时,计时器便会产生计时器中断。计时器中断会一直拉高,直到软件重新写 mtimecmp 寄存器的值,使得其比较值大于 mtime 中的值,从而将计时器中断清除。
软件中断:RISC-V 架构定义的机器模式软件中断可以通过软件写 1 至 msip 寄存器来触发。
中断的优先级:外部中断>软件中断>计时器中断,在多个外部中断源之前,可以通过PLIC来为每个外部中断源设置优先级。
1.4 中断寄存器
1.中断使能寄存器
RISC-V 架构的狭义上的异常是不可以被屏蔽的,也就是说一旦发生狭义上的异常,处理器一定会停止当前操作转而处理异常。但是狭义上的中断则可以被屏蔽掉,RISC-V 架构定义了 CSR 寄存器机器模式中断使能寄存器 mie(Machine Interrupt Enable Registers)可以用于控制中断的屏蔽。
(1)mie 寄存器的详细格式如图 13-8 所示,其中每一个比特域用于控制每个单独的中断使能。
• MEIE 域控制机器模式(Machine Mode)下外部中断(External Interrupt)的屏蔽。
• MTIE 域控制机器模式(Machine Mode)下计时器中断(Timer Interrupt)的屏蔽。
• MSIE 域控制机器模式(Machine Mode)下软件中断(Software Interrupt)的屏蔽。
(2)软件可以通过写 mie 寄存器中的值达到屏蔽某些中断的效果。假设 MTIE 域为被设置成 0,则意味着将计时器中断屏蔽,处理器将无法响应计时器中断。
需要注意区别的是,mie寄存器中的相关位(MEIE,MTIC,MSIE)只是负责某一种类型中断的使能,而mstatus寄存器的mie位是负责全局中断的使能。
2.中断等待寄存器
RISC-V 架构定义了 CSR 寄存器机器模式中断等待寄存器 mip(Machine Interrupt Pending Registers)可以用于查询中断的等待状态。
mip 寄存器的详细格式如图 13-9 所示,其中的每一个域用于反映每个单独的中断等待状态(Pending)。
• MEIP 域反映机器模式(Machine Mode)下的外部中断的等待(Pending)状态。
• MTIP 域反映机器模式(Machine Mode)下的计时器中断的等待(Pending)状态。
• MSIP 域反映机器模式(Machine Mode)下的软件中断的等待(Pending)状态。
有关中断和异常的寄存器总结如下: