44B0中断分析(转帖)
首先 ARM芯片要中断设置要是能中断向量,然后当有 IRQ 中断来之后,CPU自动的到0x18地址处取指。0x18处的指令呢是CPU 根据中断源算好的(比如:中断 EINT4567 来了,那么 0x18 处的指令就是跳转到地址 0x30 处)。然后就执行“ldr pc,=HandlerEINT4567”这条指令。这条指令的执行结果就是跳转到 “HandlerEINT4567 HANDLER HandleEINT4567”处执行。这条是宏指令,你可以看一下宏定义。执行结果就是跳转到HandleEINT4567 处执行。
那么 HandleEINT4567 处又是什么指令呢?这就要联系 44b.h 文件的#define pISR_EINT4567 (*(unsigned *)
(_ISR_STARTADDRESS+0x74)) 定 义 看 了。
HandleEINT4567 处的地址就是“_ISR_STARTADDRESS+0x74”。到此还不知道这个地址对应的指令是什么。 这时候就要去看Target.c文件的中断初始化了,其中pISR_EINT4567= (unsigned) OSEINT4567ISR;这条语句就解释了中断去向何处。 OSEINT4567ISR 就是在OS_CPU_A.s 里面定义的中断处理程序了。
一、 关于44B0中断系统
44B0 中断系统中有两张中断转移表,经过二重转移才跳到中断处理程序。第一张中断向量表由硬件决定,所在区域为ROM(flash),地址空间从0X00开始,其中0X00-0X1C为异常向量入口地址,0X20-0XC0为中断向量入口地址。另一张中断向量表在RAM 中,可以随便改,其位置在程序连接后才定。
二、 如何从第一张中断向量表跳到第二张中断向量表
由于 RAM 放在地址空间的高端(距离中断向量超过了 32M),故在第一张中断向量表对应位置上写上 ldr PC,# interrupt_service 如:ldr PC,=HandlerEINT4567
三、如何在启动程序中设置异常向量,中断向量表
如何把C语言中的一个中断函数对应到汇编的中断向量表中,示意图及举例如下:
把C语言中的一个中断函数对应到汇编的中断向量表中:pISR_EINT4567 = (int)Eint4567Isr;其实异常向量就是中断向量,ARM7的内核实际上只有8个(1个保留)异常向量,对于众多的中断源,ARM7 的内核是通过 IRQ、FRQ 的软件查询中断状态寄存器的位来获得ISR的起始地址。而44B0为了克服这种方式所带来的中断延迟,就加入了更多的中断向量表(0x20到0xc0),要使用这种方式,必须在中断控制寄存器中设置每个中断源的方式为IRQ 方式,且使用向量中断。
S3C44B0X 的中断控制器有30 个中断源。S3C44B0X 支持新的中断处理模式称为(vectored interrupt mode),在多个中段请求发生时,由硬件优先级逻辑确定应该有哪个中断得到服务,同时硬件逻辑使中断相量表的跳转指令加载到(0X18或0X1C)位置,在该位置执行跳转指令使程序跳到相应的中断服务线程,因此相对与传统的ARM 的软件方法能够大大减少中断进入延时。有两种类型的中断模式,FIQ (快速中断)和IRQ.所有的中断源在中断请求时应该确定使用的中断模式。在网络上广为流传的44b0开发板例程中,大部分使用的都是IRQ 中断模式(请查阅寄存器rINTCON)。
一般来讲,使用 44b0 开 发板进行调试时, 无需更改44b.h,44blib.h,def.h,option.h,44binit.s,44blib.c,44blib_a.s,memcfg.s,option.s 等程序,甚至无需看懂,即可编程使用 44b0 开发板。如前所述,硬件逻辑使中断向量表的跳转指令加载到(0X18 或 0X1C)位置,在该位置执行跳转指令使程序跳到相应的中断服务线程,用户只需定义相应的中断服务程序即可。中断向量表的定义如下:
/* ISR */
#define pISR_RES
ET (*(unsigned *)(_ISR_STARTADDRESS+0x0))
#define pISR_UNDEF (*(unsigned *)(_ISR_STARTADDRESS+0x4))
#define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x8))
#define pISR_PABORT (*(unsigned *)(_ISR_STARTADDRESS+0xc))
#define pISR_DABORT (*(unsigned *)(_ISR_STARTADDRESS+0x10))
#define pISR_RESERVED (*(unsigned *)(_ISR_STARTADDRESS+0x14))
#define pISR_IRQ (*(unsigned *)(_ISR_STARTADDRESS+0x18))
#define pISR_FIQ (*(unsigned *)(_ISR_STARTADDRESS+0x1c))
void __irq Mycat(void);;;
显然,至此可以基本理解 44b0 的中断,是如何与程序中的中断服务子程序联系起来的了。中断的硬件逻辑,将检测到的中断,以某种方式指向中断服务程序的地址,该地址在头文件中以宏定义的形式出现。用户在自己的程序中,将中断服务子程序的地址付给该指针,从而将其联系起来。
ARM7TDMI 在矢量模式下,当从 0X18 地址处取指令时候,中断控制器会在数据总线上加载分支指令,这些分支指令使程序计数器能够对应到每一个中断源的向量地址。这些跳转到每一个中断源向量地址的分支指令由中断控制器产生。
例如:假设 EINT0 是 IRQ 中断,EINT0 的向量地址为:0X20(见向量表),那么中断控制器必须产生0X18---0X20的分支指令。
中断控制器产生的机器码为: 0XEA000000。在各个中断源对应的中断向量地址中,存放着跳转到相应中断服务程序的程序代码。在相应向量地址处分支指令的机器代码如下计算: 矢量中断模式的机器指令代码=0XEA000000+((<目标地址>-<向量地址>-0X8)>>2) ,机器代码一般由反汇编后自动产生。
结合这些,再看看程序中的代码。在无矢量中断模式,通过分析IISPR/FISPR 寄存器,IRQ/FIQ 处理器将移动PC到相应的ISR。HandleXXX 地址包含每个响应的ISR程序的起始地址。(见 44binit.S 文件) 编译器它自动有设置的(初始化的伪编译宏), |Image$$RO$$Limit|:表示RO 区末地址后面的地址,即RW数据源的起始地址|Image$$RW$$Base|:RW 区在 RAM 里的执行区起始地址,也就是编译器选项RW_Base指定的地址 |Image$$ZI$$Base|:ZI 区在RAM 里面的起始地址 |Image$$ZI$$Limit|:ZI 区在RAM 里面的结束地址后面的一个地址 程序先把 ROM 里|Image$$RO$$Limt|开始的 RW 初始数据拷贝到 RAM 里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit|。
1.文件描述和准备
本文将试图讲述44B0X处理器处理中断的具体过程,如果读者的中断执行不正常,请确保 FLASH 中烧录了立宇泰 ARMSys's BootLoader for Linux V1.2,同时ADS开发环境中的RO Base为0x0c0008000,RW Base为0xc5f0000。 本文采用的44BINIT.s的自叙为:
本程序以系统的Timer0中断为例,中断初始化程序如下:
2.调试程序装载后
AXD装载AXF调试文件后,暂时不运行,PC指针指示在bResetHandler处,用右键菜单中的Disassembly,可以看出初始地址实际上指示在0x0c008000,即ADS中设置的RO Base,表示程序即将从0x0c008000开始运行。
3.非矢量模式下的执行过程
经过以上准备工作,单击【运行】两次后 Timer0 中断发生,通过事先设置好的断点捕捉中断,所有图中的红点即为运行前设置的断点:
⑴PC->0x0c008000 转到 PC->0x00000018 处,即转到 Flash 中执行Bootloader的代码。
⑵ PC->0x00000018 转到 PC->0x0c000018处,即又跳回到SDRAM中。
⑶ PC->0x0c000080处执行的是IsrIRQ中断识别程序。
⑷ 识别程序段执行完后,转到用户的中断服务程序Timer_ISR( )入口。
4.矢量模式下的执行过程
OPTION.s中有_IRQ_BASEADDRESS EQU 0xc000000;
在44BINIT中有如下定义:
^ (_IRQ_BASEADDRESS+0x100) ……
HandleTIMER0 # 4
……
猜测地址HandleTIMER0=_IRQ_BASEADDRESS+0x134=0x0c000134,下面来看看猜想对不对。 改rINTCON=0x1进行矢量中断过程的观察,重新装载程序,再单击【运行】两次后,Time0中断产生:
⑴ Timer0 中断产生,跳转到中断矢量地址 0x00000060,而不是跳转到 IRQ中断入口0x00000018,这就是非矢量中断和矢量中断的本质区别。
⑵ 再跳转到0x00000334,注意还是在Flash中,因此还得归功于Bootloader 黑体所选程序是类似宏调用HandlerTIMER0 HANDLER HandleTIMER0 产生的代码,由于这是在 Flash 中,所以不可能是调试时下载进去的。(不相信可以把44BINIT.s中的宏HandlerTIMER0 HANDLER HandleTIMER0注释掉试试。) 执行完0x00000348处的指令后,执行步骤⑶。
⑶ 好,Bootloader完成使命后,跳转到用户的Timer_ISR( ),入口地址为0x0c0087d4 ,在44B.h中有定义:#define pISR_TIMER0 (*(unsigned *)(_IRQ_BASEADDRESS+0x134))//0x54),可看出pISR_TIMER0和44B0INIT.h中定义的HandleTIMER0指向地址是一样的,都指向0x0c000134。 下图即pISR_TIMER0=(int)Timer_ISR;已经生效的明证。
【心得】不管是何种中断模式,如果中断总是没有执行,则可以在FLASH中的中断分支表的相应项目上设置断点,再然后灵活运用STEPIN、STEPOUT、STEP等控制程序流程,以观察问题的根源。 在汇编级代码中设置断点,需要用到右键菜单中的【Set PC】,设置完后,不要忘记改回初始的PC值。
阅读(2443) | 评论(1) | 转发(0) |