5、软件则需要完成的工作
软件则需要完成以下工作:
(1)为ARM核建立异常向量表。ARM体系结构中定义了各种异常的入口地址,例如复位异常的入口地址为0x0,发生复位时,ARM核自动跳转到0x0处开始执行。因此,需要在各入口地址处放一条跳转指令,跳转到相应的异常处理服务程序。因此,异常向量表就是从0x0地址开始的8个字(除了7条跳转到上述异常处理程序的跳转指令外,还有一个保留字)。
(2)为各种处理器模式设置堆栈:由于异常处理程序中需要用到通用寄存器,因此,进入异常时,应该保存要使用的寄存器,保存方法是将其压入本异常模式下的堆栈,异常处理完毕后返回时,从堆栈中恢复通用寄存器的值。
(3)编写异常处理服务程序。异常服务程序应首先保护中断现场(将相关寄存器压入堆栈),并判断中断源以执行相应的服务子程序,完成后恢复中断现场并返回。典型的异常处理例程框架如下(以IRQ和FIQ为例):
SUBS LR, LR, #4 ;事先修正返回地址
STMFD SP!, { reglist, LR } ;保护现场
; ... ;异常处理程序主体
LDMFD SP!, { reglist, PC }^ ;恢复现场,(^表示将SPSR恢复到CPSR),并将LR出栈送PC返回
注意,各种处理器异常对返回地址的修正是不一样的。可以参考相关资料[1][2][3]。
STMFD SP!, { reglist, LR } ;保护现场
; ... ;异常处理程序主体
LDMFD SP!, { reglist, LR } ;恢复现场
SUBS PC, LR, #4 ;修正返回地址并返回
因此,ARM处理器核心所能处理的就是异常向量表中的7种异常。而在一个具体的ARM芯片中,通常会有多个外部FIQ/IRQ中断源,还会提供一个中断控制器对这些中断源进行集中管理,因此,上面的IRQ/FIQ异常处理例程可以作为一个顶层服务程序,在程序主体中对中断源进行判决,跳转到相应的服务子程序。
注意,以上只阐述个人对ARM处理器的异常处理机制的理解,对于具体某一ARM处理器芯片的IRQ/FIQ中断处理,需要对具体芯片的中断控制系统有正确的认识和理解。
6、程序示例分析
下面结合Samsung公司基于ARM7TDMI内核的S3C44B0微控制器的启动代码详细说明关于异常处理中的Reset、IRQ和FIQ处理过程及实现方法,
以下代码均在Embest IDE 集成开发环境下能够编译运行并经过实际验证。
.text
#Embest IDE集成开发环境可以通过链接脚本文件将下面的语句定位在零起始地址,系统上
#加电后CPU从此处开始执行。
ENTRY:
b ResetHandler /*0x00000000; for debug*/
b HandlerUndef /*0x00000004; handlerUndef*/
b HandlerSWI /*0x00000008; SWI interrupt handler*/
b HandlerPabort /* 0x0000000C;handlerPAbort*/
b HandlerDabort /*0x00000010; handlerDAbort*/
b . /* handlerReserved */
b HandlerIRQ /* 0x00000018*/
b HandlerFIQ /*0x0000001C */
上面的代码用于在出现异常时,CPU根据不同情况利用标号自动跳转到对应的异常处理程序处,分别对应于处理器的7种不同工作模式。当复位后,由零地址的跳转指令使CPU转去执行启动代码,它是用于初始化CPU内部特殊功能寄存器和外围电路以及用来为高级语言写的软件做好运行前准备的一小段汇编语言,这部分汇编代码也可以被成为嵌入式系统的Bootloader。运行完ootloader代码后,会自动跳转至利用高级语言编写的系统应用程序或是开始运行操作系统内核。而对于中断的处理在系统启动代码中对于初学者是较难理解的。
当CPU接收到中断请求信号之后且允许CPU响应中断请求,则对于FIQ和非矢量IRQ中断CPU会根据中断控制器设定的工作模式去自动执行
0x0000001C 或0x00000018处的跳转指令。执行
b HandlerIRQ
#跳转到
HandlerIRQ HANDLER HandleIRQ
#这个宏定义的动作是要跳转到HandleIRQ中存放的地址去运行。
#然后在复位初始化代码(ResetHandler)中会看到有:
/* Setup IRQ handler*/
ldr r0,=HandleIRQ
ldr r1,=IsrIRQ
str r1,[r0]
这里是把IsrIRQ的地址放到了HandleIRQ中。因此程序会跳转到IsrIRQ去执行。
#ARM7TDMI内核只支持FIQ和IRQ两个中断请求,当有多个中断请求信号同时有效的时#候,是利用软件的方式来完成优先级判定,然后再跳转到相应的中断服务程序。在IsrIRQ中,CPU会读取中断挂起寄存器的数值来判定中断来源和优先级。而S3C44B0中集成的中断控制器提供了一种更为快速有效的中断响应方式:矢量中断利用中断控制器的硬件方式直接提供对中断服务的快速响应:当多重中断请求信号发生时,由硬件优先级判定逻辑确定哪个中断请求将被响应,同时硬件逻辑还利用向量表中的跳转指令使CPU直接跳转到相应的中断服务程序入口出。这样在很大程度上减小了中断响应的延迟。
那么在程序设计上,就需要我们在矢量中断表中对应的地址上放置各个中断请求对应的服务程序入口地址,如:
VECTOR_BRANCH:
ldr pc,=HandlerEINT0 /*0x00000020*/
ldr pc,=HandlerEINT1 /*0x00000024*/
ldr pc,=HandlerEINT2 /*0x00000028*/
ldr pc,=HandlerEINT3 /*0x0000002C*/
ldr pc,=HandlerEINT4567 /*0x00000030*/
ldr pc,=HandlerTICK /*0x00000034 */
b .
b .
ldr pc,=HandlerZDMA0 /*0x00000040*/
ldr pc,=HandlerZDMA1 /*0x00000044*/
……
|