9.4 流水线与异常处理
这里简要介绍一下如何在流水线处理器中支持异常处理。在第3章曾介绍过,异常产生的来源包括:外部事件、指令执行中的错误、数据完整性问题、地址转换异常、系统调用和陷入以及需要软件修正的运算等。在流水线处理器中,这些不同类型的异常可能在流水线的不同阶段产生。例如访存地址错异常可以在取指阶段和访存阶段产生,保留指令异常和系统调用异常在译码阶段产生,整数溢出异常在执行阶段产生,而中断则可以在任何时候发生。
异常可以分为可恢复异常和不可恢复异常。不可恢复的异常通常发生在系统硬件出现了严重故障的时候,此时异常处理后系统通常面临重启,所以处理器响应不可恢复异常的机制很简单,只要立即终止当前的执行,记录软件所需的信息然后跳转到异常处理入口即可。但是,可恢复异常的处理就比较难,要求做得非常精确,这也就是常常提到的精确异常概念。精确异常要求处理完异常之后,回到产生异常的地方接着执行,还能执行正确,就好像没有发生过异常一样。要达成这个效果,要求在处理异常时,发生异常的指令前面的所有指令都执行完(修改了机器状态),而发生异常的指令及其后面的指令都没有执行(没有修改机器状态)。
在流水线处理器中,同时会有多条指令处于不同阶段,不同阶段都有发生异常的可能,那么如何实现精确异常呢?这里给出一种可行的设计方案。为什么说是可行的以及结构设计该如何修改,作为课后作业留给同学们思考。
1)任何一级流水发生异常时,在流水线中记录下发生异常的事件,直到写回阶段再处理。
2)如果在执行阶段要修改机器状态(如状态寄存器),保存下来直到写回阶段再修改。
3)指令的PC值随指令流水前进到写回阶段为异常处理专用。
4)将外部中断作为取指的异常处理。
5)指定一个通用寄存器(或一个专用寄存器)为异常处理时保存PC值专用。
6)当发生异常的指令处在写回阶段时,保存该指令的PC及必需的其他状态,置取指的PC值为异常处理程序入口地址。
在前面3节的介绍中,由简至繁地搭建出一个可以正常执行各种指令的流水线处理器。回顾设计过程,其中的设计要点有两个:第一是通过加入大量触发器,实现了流水线功能;第二是通过加入大量控制逻辑,解决了指令相关问题。