首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM 的异常处理

ARM 的异常处理

当异常中断发生时,系统执行完当前指令后,将跳转到相应的异常中断处理程序处执行。当异常中断处理程序执行完成后,程序返回到发生中断指令的下条指令处执行。在进入异常中断处理程序时,要保存被中断程序的执行现场,从异常中断处理程序退出时,要恢复被中断程序的执
行现场。
1
、引起异常的原因
      
对于ARM核,可以且只能识别7种处理器异常,每种异常都对应一种ARM处理器模式,当发生异常时,ARM处理器就切换到相应的异常模式,并调用异常处理程序进行处理。
    (1)
、指令执行引起的异常
    软件中断、未定义指令(包括所要求的协处理器不存在是的协处理器指令)、预取址中止(存储器故障)、数据中止。
    (2)
、外部产生的中断
    复位、FIQIRQ
2
ARM中异常中断的种类
    (1)
、复位(RESET)
    a
、当处理器复位引脚有效时,系统产生复位异常中断,程序跳转到复位异常中断处理程序处执行,包括系统加电和系统复位。

    b
、通过设置PC跳转到复位中断向量处执行称为软复位。
    (2)
、未定义的指令
   
ARM处理器或者是系统中的协处理器认为当前指令未定义时,产生未定义的指令异常中断,可以通过改异常中断机制仿真浮点向量运算。
   (3)
、软件中断
   
这是一个由用户定义的中断指令(SWI)。可用于用户模式下的程序调用特权操作指令。在实时操作系统中可以通过该机制实现系统功能调用。
    (4)
、指令与取终止(Prefech Abort)
   
如果处理器预取的指令的地址不存在,或者该地址不允许当前指令访问,当被预取的指令执行时,处理器产生指令预取终止异常中断。
    (5)
、数据访问终止(DATAABORT
    如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问终止异常中断。
    (6)
、外部中断请求(IRQ)

当处理器的外部中断请求引脚有效,而且CPSR的寄存器的I控制位被清除时,处理器产生外部中断请求异常中断。系统中个外设通过该异常中断请求处理服务。

    (7)
、快速中断请求(FIQ
   
当处理器的外部快速中断请求引脚有效,而且CPSRF控制位被清除时,处理器产生外部中断请求异常中断。
   
3
、异常的响应过程
   
除了复位异常外,当异常发生时,ARM处理器尽可能完成当前指令(除了复位异常)后,再去处理异常。并执行如下动作:
    (1)
、将引起异常指令的下一条指令的地址保存到新模式的R14,若异常是从ARM状态进入,LR寄存器中保存的是下一条指令的地址(当前PC4PC8,与异常的类型有关);若异常是从Thumb状态进入,则在LR寄存器中保存当前PC的偏移量,这样,异常处理程序就不需要确定异常是从何种状态进入的。例如:在软件中断异常SWI,指令MOV PCR14_svc总是返回到下一条指令,不管SWI是在ARM状态执行,还是在Thumb
态执行。
    (2)
、将CPSR的内容保存到要执行异常中断模式的SPSR中。

    (3)
、设置CPSR相应的位进入相应的中断模式。
    (4)
、通过设置CPSR的第7位来禁止IRQ。如果异常为快速中断和复位。则还要设置CPSR的第6位来禁止快速中断。
    (5)
、给PC强制赋向量地址值。
   
上面的异常处理操作都是由ARM核硬件逻辑自动完成的,程序计数器PC总是跳转到相应的固定地址。
   
如果异常发生时,处理器处于Thumb状态,则当异常向量地址加载入PC时,处理器自动切换到ARM状态,则异常处理返回时,自动切换到Thumb状态。

4
、异常中断处理返回
   
异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回:

    (1)
、将所有修改过的用户寄存器从处理程序的保护栈中恢复。

    (2)
、将SPSR复制回CPSR中,将连接寄存器LR的值减去相应的偏移量后送到PC中。

    (3)
、若在进入异常处理时设置了中断禁止位,要在此清除。

   
复位异常处理程序不需要返回。


5
、软件则需要完成的工作

        
软件则需要完成以下工作:


      
1)为ARM核建立异常向量表。ARM体系结构中定义了各种异常的入口地址,例如复位异常的入口地址为0x0,发生复位时,ARM核自动跳转到0x0处开始执行。因此,需要在各入口地址处放一条跳转指令,跳转到相应的异常处理服务程序。因此,异常向量表就是从0x0地址开始的8个字(除了7条跳转到上述异常处理程序的跳转指令外,还有一个保留字)。

      
2)为各种处理器模式设置堆栈:由于异常处理程序中需要用到通用寄存器,因此,进入异常时,应该保存要使用的寄存器,保存方法是将其压入本异常模式下的堆栈,异常处理完毕后返回时,从堆栈中恢复通用寄存器的值。

      
3)编写异常处理服务程序。异常服务程序应首先保护中断现场(将相关寄存器压入堆栈),并判断中断源以执行相应的服务子程序,完成后恢复中断现场并返回。典型的异常处理例程框架如下(以IRQFIQ为例):

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微控制器的启动代码详细说明关于异常处理中的ResetIRQFIQ处理过程及实现方法,

以下代码均在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*/
        ……
7、中断向量表
    a、中断向量表指定了个异常中断及其处理程序的对应关系。他通常存放在存储地址的低端。在ARM体系中,异常中断向量表的大小为32字节,其中每个异常中断占据4个字节大小,保留了4个字节空间。
    b、每个异常中断对应的中断向量表中的4个字节的空间中存放了一个跳转指令或者一个向PC寄存器中赋值的数据访问指令。通过这两种指令,程序将跳转到相应的异常中断处理程序处执行。
    c、当几个异常中断同时发生时,系统并不能按照一定的次序来处理这些异常中断,例如:当FIQ、IRQ和第三个其他中断同时发生,FIQ比IRQ优先级高,IRQ会忽略,直到FIQ返回到用户代码为止。

各个异常中断的中断向量地址以及中断的处理优先级
————————————————————————————————————
  中断向量地址 |  异常中断类型   |   异常中断模式   |  优先级(6最低)  |
———————|———————|————————|—————————|
      0x00          |   复位                |     特权模式        |       1           |
      0x04          |   未定义的指令   |     UND终止模式  |         6         |
      0x08          |   软件中断         |     特权模式       |          6        |
      0x0C          |   指令预取终止   |     终止模式       |         5         |
      0x10          |   数据访问终止   |     终止模式       |         2         |
      0x14          |   保留                 |       未使用       |       未使用    |
      0x18          |   外部中断请求   |     IRQ模式        |          4        |
      0x1C          |   快速中断请求   |     FIQ模式        |          3        |
——————————————————————————————————————

8、总结
        S3C44B0利用两个向量表高效而可靠的实现了对异常的处理,掌握了S3C44B0微处理器的异常模式以及对异常处理中复位、FIQ和IRQ响应的过程,可以在很大程度上帮助我们理解ARM7TDMI内核对异常处理的工作原理,有利于理解S3C44B0的启动代码(或Bootloader),还可以更有效的利用芯片的硬件资源编写出精简而由高效的嵌入式程序代码。对嵌入式系统整体设计会起到很大的帮助,是进行嵌入式系统开发的基础。


What is the vector table on earth?

       中断向量表到底是什么呢?《ADS Developer Guide》中的定义如下:“中断向量表是一块32字节保留区域,通常在内存映像的底部。每种异常被分配一个字的空间。”这实际上指的是0x0地址开始的跳转到7种异常处理入口的7条跳转指令外加一个保留入口(8个字共32字节)。

       在《ARM嵌入式系统开发——软件设计与优化》中定义如下:“向量表的入口(entry)是一些跳转指令,跳转到专门处理某个异常或中断的子程序。每个入口包含一条跳转指令。”

       对于具体的ARM芯片,通常可以有多个IRQ/FIQ异常中断源,例如PXA270一共有34个外设级中断源可以发出IRQ/FIQ中断请求。如果要使用多个IRQ/FIQ中断,同样的,需要建立IRQ/FIQ中断向量表,这个表的条目(或入口,即entry):

(1)可以是跳转到对应ISR的指令机器码(使用“LDR PC, =ISR_Addr”伪指令跳转到对应入口以执行跳转指令,其中ISR_Addr是条目的地址标号);

(2)也可以是对应ISR的入口地址(在IRQ/FIQ异常处理程序中使用“LDR PC, [Rn, #ISR_OFFSET]”进行散转,Rn中事先保存IRQ_Table的基址,注意ISR_OFFSET相对于该LDR指令的地址(PC值)的偏移量不可超过4KB,亦即1K个字
返回列表