微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM微处理器的编程模型之:异常中断处理

ARM微处理器的编程模型之:异常中断处理

时间:09-13 来源:互联网 点击:

0x8000+8=0x8008,即等于指令C的地址。假设指令A是BL指令,则当执行时,会把PC值(0x8008)保存到LR寄存器。但是,接下来处理器会对LR进行一次自动调整,使LR=LR-0x4。所以,最终保存在LR里面的是图3.5中所示的B指令地址。所以当从BL返回时,LR里面正好是正确的返回地址。

同样的跳转机制在所有的LR自动保存操作中都存在。当进入中断响应时,处理器对保存的LR也进行一次自动调整,并且跳转动作也是LR=LR-0x04。由此,就可以对不同异常类型的返回地址依次比较。

假设在指令B处(地址0x8004)发生了异常,进入异常相应后,LR经过跳转保存的地址值应该是C的地址0x8008。

(1)软中断异常

如果发生软中断异常,即指令B为SWI指令,从SWI中断返回后下一条执行指令就是C,正好是LR寄存器保存的地址,所以只有直接把LR恢复给PC即可。

(2)IRQ或FIQ异常

如果发生的是IRQ或FIQ异常,因为外部中断请求中断了正在执行的指令B,当中断返回后,需要重新回到B指令执行,也就是说,返回地址应该是B(0x8004),需要把LR减4送PC。

(3)Data Abort数据中止异常

在指令B处进入数据异常的相应,但导致数据异常的原因却应该是上一条指令A。当中断处理程序恢复数据异常后,要回到A重新执行导致数据异常的指令,因此返回地址应该是LR加8。

为方便起见,表3.7总结了各异常和返回地址的关系

表3.7 异常和返回地址

异 常

地 址

用 途

复位

复位没有定义LR

数据中止

LR-8

指向导致数据中止异常的指令

FIQ

LR-4

指向发生异常时正在执行的指令

IRQ

LR-4

指向发生异常时正在执行的指令

预取指令中止

LR-4

指向导致预取指令异常的那条指令

SWI

LR

执行SWI指令的下一条指令

未定义指令

LR

指向未定义指令的下一条指令

3.4.6 在应用程序中安装异常处理程序

1.使用汇编语言安装异常处理程序

如果系统启动不依赖于Debug或Debug monitor软件,可以使用汇编语言在系统启动时直接安装异常处理程序。

下面的例子显示了系统从0x0地址启动,直接安装异常处理程序的方法。

Vector_Init_Block

LDR PC, Reset_Addr

LDR PC, Undefined_Addr

LDR PC, SWI_Addr

LDR PC, Prefetch_Addr

LDR PC, Abort_Addr

NOP ;保留向量

LDR PC, IRQ_Addr

LDR PC, FIQ_Addr

Reset_Addr DCD Start_Boot

Undefined_Addr DCD Undefined_Handler

SWI_Addr DCD SWI_Handler

Prefetch_Addr DCD Prefetch_Handler

Abort_Addr DCD Abort_Handler

DCD 0 ;保留向量

IRQ_Addr DCD IRQ_Handler

FIQ_Addr DCD FIQ_Handler

有些情况下,系统0x0地址不一定是ROM。如果0x0地址为RAM,那么就系统将中断向量表从ROM复制RAM,下面的例子显示了这样一个过程。

MOV R8, #0

ADR R9, Vector_Init_Block

LDMIA R9!,{r0-r7} ;复制中断向量表 (8 words)

STMIA R8!,{r0-r7}

LDMIA R9!,{r0-r7} ;复制由伪操作 DCD定义的地址

STMIA R8!,{r0-r7}

注意

可以使用Scatter文件定义加载向量表的地址,这样上述代码的拷贝工作由C库函数完成。

2.使用C语言安装异常处理程序

程序中有时需要在main()函数中使用C语言安装中断向量表。这就要求指令经编译后的解码能安装在内存的正确位置。

(1)向量表中使用跳转指令的情况

如果在向量表中使用跳转指令,使用下面的步骤完成向量表的安装。

① 读取异常处理程序的地址。

② 从异常处理程序地址中减去向量表中的偏移。

③ 为适应指令流水线,将上一步得到的地址减8。

④ 将得到的结果右移2位,得到以字为单位的地址偏移量。

⑤ 将结果的高8位清零,得到跳转指令的24位偏移量。

⑥ 将上一步得到的结果和0xea000000(无条件跳转指令编码)做逻辑与操作,从而得到要写到向量表中的跳转指令的正确编码。

下面的例子显示了这样一个标准过程。

unsigned Install_Handler (unsigned routine, unsigned *vector)

{ unsigned vec, oldvec;

vec = ((routine - (unsigned)vector - 0x8)>>2);

if ((vec 0xFF000000))

{

/* diagnose the fault */

prinf (Installation of Handler failed);

exit (1);

}

vec = 0xEA000000 | vec;

oldvec = *vector;

*vector = vec;

return (oldvec);

}

(2)在向量表中使用加载PC指令

在向量表中使用加载PC指令,按照下面的步骤完成。

① 读取异常处理程序地址。

② 从异常处理程序地址中减去向量表中的偏移。

③ 为适应指令流水线,将上一步得到的地址减8。

④ 保留结果的后12位。

⑤ 将结果与0xe59ff000(LDR PC, [PC,#offset])做逻辑或操作,从而得到要写到向量表中的跳转指令的正确编码。

⑥ 将异常处理程序的地址放到相应的存储单元。

下面的例子显示了一个标准的C语言过程。

unsign

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top