**标题: ColdFire与ARM处理器中断响应分析
**简介: 对于任何一种处理器,中断都是非常重要的,它的响应速度,直接关系着程序的性能。另外用户程序出现跑飞形象,也大多都是由中断引起,在中断的处理过程当中执行非法指针操作引起。因此分析、熟悉处理器的中断响应执行过程,无论对其性能的了解,还是解决由中断引起的程序跑飞的调试,都是必须的。
正文: 一. ARM处理器中断分析(以S3C2410的IRQ及timer0中断为例) 1. 中断初始化过程 1> 中断向量表起始地址定义 C文件中的宏定义: #define _ISR_STARTADDRESS 0x33ffff00 汇编文件中的定义: _ISR_STARTADDRESS EQU 0x33ffff00 2> IRQ中断及具体外设中断源地址定义 C文件中的宏定义: 。。。。。。 #define pISR_IRQ (*(unsigned *)(_ISR_STARTADDRESS+0x18)) 。。。。。。 #define pISR_TIMER0 (*(unsigned *)(_ISR_STARTADDRESS+0x48)) 。。。。。。。 汇编文件中的定义: 。。。。。。 pISR_IRQ EQU (_ISR_STARTADDRESS+0x18) 。。。。。。 pISR_TIMER0 EQU (_ISR_STARTADDRESS+0x48) 。。。。。。 AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS 。。。。。。 HandleIRQ # 4 //注:位于_ISR_STARTADDRESS+0x18处 。。。。。。 HandleTIMER0 # 4 。。。。。。 END 3> 相关的子程序段 内核中断都要用到的宏定义: MACRO $HandlerLabel HANDLER $HandleLabel
$HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does't push because it return to original address) ldr r0,=$HandleLabel;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND
IRQ中断处理程序断: IsrIRQ sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} 4> 系统启动时的初始化过程 ResetHandler //系统复位后,从这开始执行 。。。。。。 ldr r0,=HandleIRQ ldr r1,=IsrIRQ //将IRQ中断处理程序IsrIRQ入口地址保存在向量表HandleIRQ位置 str r1,[r0] 。。。。。。 pISR_TIMER0 = (int)Timer0Done;//该语句为C语言,在应用程序中初始化 //将定时器0的中断处理程序地址保存在向量表该中断源位置 2. 中断响应过程 当产生timer0中断请求时,PC指向IRQ中断入口(地址:0x00000018)处,执行跳转指令(b HandlerIRQ)到宏定义(HandlerIRQ HANDLER HandleIRQ)处,即相当于如下程序: HandlerLabel sub sp,sp,#4 stmfd sp!,{r0} ldr r0,=HandleIRQ ldr r0,[r0] str r0,[sp,#4] ldmfd sp!,{r0,pc} 执行这段程序后,PC将指向存放在中断向量表HandleIRQ处的IsrIRQ程序,如下: IsrIRQ sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} 上述的INTOFFSET为中断偏移寄存器,该值保存了请求挂起的中断源的偏移值(每个中断源都对应一个唯一值,参考S3C2410 datasheet的P14-16页表格,如timer0的偏移值为10),指示是哪个中断源产生请求处理,例如timer0产生中断请求,则该值就为10。由于EINT0的偏移值为0,而中断向量表是根据偏移值排列的,故上述的程序将向量表的HandlerEINT0再加上INTOFFSET值,查表得到pISR_TIMER0位置处的timer0中断处理程序Timer0Done的地址,所以执行这段程序后PC指向了Timer0Done,也就是用户最终的中断处理程序。 二. ColdFire中断分析(以MCF52235的EPORT0的IRQ4为例) 1. 中断向量表初始化 1> 中断函数定义 __interrupt__ void irq4_handler(void) { 。。。。。。 } 2> 向量表定义 /* * Exception Vector Table */ VECTOR_TABLE: _VECTOR_TABLE: INITSP: .long ___SP_INIT /* Initial SP */ INITPC: .long 0x00000400 /* Initial PC */ vector02: .long _asm_exception_handler /* Access Error */ 。。。。。。 vector44: .long _irq4_handler //64+4(IRQ4的中断源号)=0x44 。。。。。。 vectorFF: .long _irq_handler 3> 系统启动时的对中断向量表的初始化 /* Copy the vector table to RAM */ if (__VECTOR_RAM != VECTOR_TABLE) { for (n = 0; n < 256; n++) __VECTOR_RAM[n] = VECTOR_TABLE[n]; } mcf5xxx_wr_vbr((uint32)__VECTOR_RAM);//将向量表地址写入内核向量寄存器
2. 中断响应过程 当IRQ4中断源产生中断时,PC将直接指向中断向量表的IRQ4处的服务程序地址:irq_handler。注:由于接触ColdFire也不是很久,所以不一定正确,还请熟悉ColdFire的朋友指证。不过我在单步仿真的情况下,触发IRQ4时,观察PC值确时是如此的。 三. 总结 由上述分析,ColdFire处理器很像8位单片机(如:51系列等)那样,一个中断源占用一个中断入口,只是该中断入口是跟随内核的VBR值的不同,而可以不同。当产生某个中断源请求时,PC直接指向该中断源的处理程序。相比之下,ARM的中断响应处理要复杂些,无论是哪个中断源请求,都必须先进入IRQ(假设中断源被设成IRQ模式)的中断入口,再根据具体中断源的偏移寄存器INTOFFSET值,找到最终中断源的处理程序。
|