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