bootloader启动代码init.s解析----IRQ中断处理函数

init.s源代码如下:

;/////////////////////////////////////////////
;option.inc
_ISR_STARTADDRESS EQU 0x33ffff00

;2440addr.inc
INTOFFSET EQU  0x4a000014    ;Interruot request source offset
;/////////////////////////////////////////////
;init.s
;/////////////////////宏
MACRO
$HandlerLabel HANDLER $HandleLabel $HandlerLabel
sub sp,sp,# ;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,#] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND ;////////////////////////;入口处定义中断跳转
ResetEntry
b ResetHandler
b HandlerUndef ;handler for Undefined mode
b HandlerSWI ;handler for SWI interrupt
b HandlerPabort ;handler for PAbort
b HandlerDabort ;handler for DAbort
b . ;reserved
b HandlerIRQ ;handler for IRQ interrupt
b HandlerFIQ ;handler for FIQ interrupt HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort IsrIRQ ;定义IsrIRQ函数
sub sp,sp,# ;reserved for PC
stmfd sp!,{r8-r9} ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl # ;r8=r8+(r9*4)
ldr r8,[r8]
str r8,[sp,#]
ldmfd sp!,{r8-r9,pc} ResetHandler
;....此处省略,其他操作如看门狗、sram初始化、堆栈初始化等 ....
   ;Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]          ;这样,在地址值为HandleIRQ(0x33FF_FF1C)处,装着IsrIRQ函数指针。
;....此处省略,拷贝程序、跳转main等....
;///////////////////////////////////////////////////////////////;定义中断地址
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # ;0x33FF_FF04
HandleUndef # ;0x33FF_FF08
HandleSWI # ;0x33FF_FF0c
HandlePabort # ;0x33FF_FF10
HandleDabort # ;0x33FF_FF14
HandleReserved # ;0x33FF_FF18
HandleIRQ # ;0x33FF_FF1C
HandleEINT0 # ;@0x33FF_FF20

HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleCAM # 4 ; Added for 2440.
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
;@0x33FF_FF60
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleNFCON # 4 ; Added for 2440.
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4

把异常处理的宏展开,以HandlerIRQ HANDLER HandleIRQ为例:

HandlerIRQ      HANDLER HandleIRQ
展开:
HandlerIRQ
sub sp,sp,# ;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,=HandleIRQ ;load the address of HandleIRQ to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleIRQ
;这里的contents是参照下面Setup IRQ handler ,为IsrIRQ函数指针
str r0,[sp,#] ;store the contents(ISR) of HandleIRQ to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND

中断发生时,b    HandlerIRQ

HandlerIRQ 展开后代码如上所示,流程如下图,最终跳转到了中断处理函数IsrIRQ【*HandleIRQ = IsrIRQ】:

在IsrIRQ里面,跳转到具体的中断处理函数。
IsrIRQ
sub sp,sp,# ;reserved for PC
stmfd sp!,{r8-r9} ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #
ldr r8,[r8] ;//r8 = HandleEINT0 + INTOFFSET寄存器的值*4 ;这里对应的是C代码中定义的中断响应函数的地址。怎么对应上的?见如下的代码:
str r8,[sp,#]
ldmfd sp!,{r8-r9,pc}
C代码中:
关联中断处理函数和启动代码中的中断地址。 //option.h
#define _ISR_STARTADDRESS 0x33ffff00

//addr.h
#define pISR_UART1 (*(unsigned *)(_ISR_STARTADDRESS+0x7c))
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20)) ;0x33FF_FF20
//IsrBind()  // isr_init.c 
pISR_UART1=(unsigned int)ProcomUart1IsrFunction; 在逻辑代码中,地址值是绝对的,因此C中的_ISR_STARTADDRESS正是启动代码中的_ISR_STARTADDRESS。 那pISR_UART1表示的就是*(HandleUART1)。pISR_EINT0就是*(HandleEINT0).
这里可以得出:我们的C代码中可以在pISR_EINT0里面分发外部中断,也可以直接绑定到具体中断源。这无非是一个中断地址表和中断处理函数的对应。

IsrIRQ跳转图解:

下面总结中断触发如何引发调用中断函数:
//先后关系:
硬件中断发生
--->
中断相关寄存器的值产生相应变化(INT_OFFSET反映了具体的外部中断源)
--->
b HandlerIRQ()

--->

HandleIRQ()

--->
IsrIRQ()

--->//如上图IsrIRQ的解析所示,根据INT_OFFSET和事先制定的地址对照表,跳转到C中初始化时绑定的中断函数

one of irq_funcs
 

扩展阅读:

1. 2440之中断管理 http://www.cnblogs.com/hnrainll/archive/2011/07/01/2095464.html

bootloader启动代码init.s解析----IRQ中断处理函数的更多相关文章

  1. Android init.rc解析【转】

    转自:http://www.linuxidc.com/Linux/2014-10/108438.htm 本文主要来自$Android_SOURCE/system/init/readme.txt的翻译. ...

  2. .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换

    .NET/C# 程序从 Main 函数开始执行,基本上各种书籍资料都是这么写的.不过,我们可以写多个 Main 函数,然后在项目文件中设置应该选择哪一个 Main 函数. 你可能会觉得这样没有什么用, ...

  3. S3C2440启动代码2440init.s彻底解析

    可以选择nand启动和nor启动,这两者之间的关系通过一个按键来选择 这个OM0有何玄机,在数据手册中有这么一段 位宽RAM启动了(当然,还得设置一些东西,下面就说), Nanaflash启动经历的过 ...

  4. init进程 && 解析Android启动脚本init.rc && 修改它使不启动android && init.rc中启动一个sh文件

    Android启动后,系统执行的第一个进程是一个名称为init 的可执行程序.提供了以下的功能:设备管理.解析启动脚本.执行基本的功能.启动各种服务.代码的路径:system/core/init,编译 ...

  5. Android系统init进程启动及init.rc全解析

    转:https://blog.csdn.net/zhonglunshun/article/details/78615980 服务启动机制system/core/init/init.c文件main函数中 ...

  6. 启动代码和Bootloader区别

    很多人都会把两者混淆,所以这里稍微说一下. 启动代码和Bootloader有点类似于类和结构体的关系,也就是说结构体只是一种很特殊很特殊的类,但不能说类是一种结构体. 也就是说可以说启动代码是Boot ...

  7. STM32 启动代码 bootloader

    什么是启动代码?     启动代码是系统上电或者复位后运行的第一段代码,是进入C 语言的main 函数之前需要执行的那段汇编代码.STM32的启动代码在startup_stm32f10x_hd.s 启 ...

  8. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  9. S3C6410的启动代码分析 一

    本文开始第一篇,启动代码的编写,注意,仅仅是启动代码,并不是bootloader,因为只有boot,没有loader. 第一要明确:CPU上电之后,会从某个固定地址执行指令.ARM结构的CPU从地址0 ...

随机推荐

  1. /export/App/zz/phantomjs-1.9.7-linux-x86_64/bin

    /export/App/zz/phantomjs-1.9.7-linux-x86_64/bin

  2. SharePoint将网站另存为模板

    1.将网站另存为模板 参考文章 http://blog.csdn.net/dyp330/article/details/23180843 http://blog.163.com/berlin1989@ ...

  3. 实现AJAX局部刷新以及PageMethod方法的使用

    <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> &l ...

  4. if和switch的区别,循环的for 和while的区别, 字符串常用的7种方法

    相同点: 都是用于多重选择 不同点: 多重IF没有switch选择结构的限制,特别适合变量处于某个连续区间的情况 switch只能处理等值条件判断的情况,而且条件必须是整型变量或者字符串变量 字符串的 ...

  5. 《JavaScript权威指南》拾遗(下)

    一.类和原型         1.在JavaScript中,类的实现是基于原型继承机制的,如果两个实例都是从同一个原型对象中继承了属性,则它们是同一个类的实例.         2.原型对象是类的唯一 ...

  6. php重定向页面的三种方式

    PHP页面跳转一.header()函数 header()函数是PHP中进行页面跳转的一种十分简单的方法.header()函数的主要功能是将HTTP协议标头(header)输出到浏览器. header( ...

  7. BZOJ 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头

    1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Description   今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏.     贝茜让N(1≤N≤10 ...

  8. android 修改背景色(转)

    修改为黑底白字 修改AndroidManifest.xml把android:theme="@style/AppTheme" 修改为android:theme="@andr ...

  9. 数据结构——AVL平衡树

    1.是二叉搜索树(Binary Search Tree) 2.树和所有左右子树高度之差为-1,0,1 平衡因子(balance factor) =右子树高度-左子树高度 平衡化旋转: 1.从插入位置向 ...

  10. poj 2245 Lotto(dfs)

    题目链接:http://poj.org/problem?id=2245 思路分析:无重复元素组合组合问题,使用暴力枚举法,注意剪枝条件. 代码如下: #include <iostream> ...