S3C2440 异常进入和退出
根据异常类型的不同,返回的方式也不同。异常造成下一条指令要从相应的向量表入口读取。
1 处理器对异常的反应
产生异常时,处理器采取如下动作:
1. 将 CPSR 复制到相应的 SPSR 中。 这会保存当前模式、中断屏蔽和条件标记。
2. 转至ARM状态。
3. 更改相应的 CPSR 模式位,以便:
- 更改为适当的模式,并在该模式的相应编组寄存器中进行映射。
- 禁用中断。发生任何异常时,都会禁用 IRQ。 在复位时发生 FIQ,会禁用 FIQ。
4. 将相应 LR 设置为返回地址。
5. 将 PC 设置为异常的向量地址。
2 从异常处理程序的返回
从异常中返回的方法取决于异常处理程序是否使用堆栈操作。 无论是否使用,要返回到异常发生处继续执行,异常处理程序必须:
- 从相应 SPSR 恢复 CPSR
- 使用相应 LR 中的返回地址恢复 PC。
对于不需要从堆栈中恢复目标模式寄存器的简单返回,异常处理程序可通过执行具有以下设置的数据处理指令来完成这些操作:
- 设置 S 标记
- PC 作为目标寄存器。
所需的返回指令取决于异常的类型。
注意,不必从复位处理程序返回,因为复位处理程序直接执行主代码。
处理异常时,如果异常处理程序入口代码使用了堆栈来存储必须保留的寄存器,则可通过使用带 ^ 限定符的加载多个指令来返回。 异常处理程序可使用一条指令返回,例如使用:
LDMFD sp!,{R0-R12,pc}^
为此,异常处理程序必须将以下内容保存到堆栈中:
- 调用处理程序时使用的所有工作寄存器
- 为产生与数据处理指令相同的效果而修改的链接寄存器。
^ 限定符指定从 SPSR 恢复 CPSR。
注意:不能使用任何 16 位 Thumb 指令从异常返回,因为这些指令无法恢复 CPSR。
3 返回地址和返回指令
产生异常时由程序计数器指向的实际位置取决于异常的类型。返回地址可能不必是程序计数器指向的下一条指令。如果异常发生在 ARM 状态,处理器则将 (PC+4) 存储在 lr_ mode。
下面较详细地说明了每一种异常类型如何从处理代码正确返回的指令。
3.1 从 SWI 和 未定义指令处理程序返回
SWI 和未定义指令异常是由指令本身造成的,因此,处理异常时,程序计数器保持不变(预取指就失败了)。处理器将 (PC+4) 存储在 lr_ mode 中。因而使 lr_mode 指向下一条要执行的指令。要从 lr 中恢复程序计数器,则使用:
MOVS pc, lr
从处理程序返回控制权。
将返回地址推入堆中并在返回时将其弹出的处理程序入口和出口代码为:
STMFD sp!,{reglist,lr}
;...
LDMFD sp!,{reglist,pc}^
3.2 从 FIQ 和 IRQ 处理程序返回
执行完每一条指令后,处理器检测中断管脚是否为 LOW(电平),以及 CPSR中断禁用位是否为清除。结果,仅在程序计数器被更新后才发生 IRQ 或 FIQ 异常。处理器将 (PC+4) 存储在 lr_mode 中。使 lr_mode 指向发生异常时尚未执行的指令的下一条指令。处理程序完成后,必须从 lr_mode 指向发生异常时尚未执行的指令处继续运行。该继续执行地址较 lr_mode 中的地址少一个字(四个字节),因此,其返回指令为:
SUBS pc, lr, #4
将返回地址推入堆中并在返回时将其弹出的处理程序入口和出口代码为:
SUB lr,lr,#4
STMFD sp!,{reglist,lr}
;...
LDMFD sp!,{reglist,pc}^
3.3 从预取中断处理程序返回
如果处理器试图在非法地址取指令,则该指令被标志为无效。继续执行已经在流水线中的指令至遇到产生“预取中断”处的无效指令为止。如有将虚拟存储器位置映射到该物理存储器的指令,异常处理程序将无映射关系的指令装入物理存储器并使用 MMU。然后,处理程序必须返回,再次使着运行产生异常的指令。现在装入并执行指令。
因为发出预取中断时程序计数器还没有被更新,所以 lr_abt 指向产生异常的下一条指令。处理程序必须返回至 lr_ABT-4 的指令,请使用下列指令:
SUBS pc,lr, #4
将返回地址推入堆中并在返回时将其弹出的处理程序入口和出口代码为:
SUB lr,lr,#4
STMFD sp!,{reglist,lr}
;...
LDMFD sp!,{reglist,pc}^
3.4 从数据中断处理程序返回
当装入或存储指令试图访问存储器时,程序计数器被更新。(PC+4) 的存储值指向产生异常地址处的第二条指令。MMU(如果有)将相应地址映射至物理存储器,处理程序必须返回到原来中断的指令,以便进行第二次执行尝试。因此,返回地址较 lr_abt 中少两个字(八个字节),使用如下返回指令:
SUBS pc, lr, #8
将返回地址推入堆中并在返回时将其弹出的处理程序入口和出口代码为:
SUB lr,lr,#8
STMFD sp!,{reglist,lr}
;...
LDMFD sp!,{reglist,pc}^