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. linux 多线程编程笔记

    一, 线程基础知识 1,线程的概念 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行 中必不可少的资源(如程序计 ...

  2. UIPickView之自定义生日键盘和城市键盘

    ////  ViewController.m//  04-键盘处理// // #import "ViewController.h"#import "XMGProvince ...

  3. CSS3媒体查询(Media Queries)

    媒体类型: all 所有设备 screen 电脑显示器 handheld 便携设备 tv 电视类型设备 print 打印用纸打印预览视图 关键字 and not(排除某种设备) only(限定某种设备 ...

  4. c++ 输出虚函数表内容

    class Base{ public: virtual void f(){cout<<"Base::f"<<endl;} virtual void g(){ ...

  5. SharePoint Secure Store Service(SSSS)的使用(一)

    SSS在案例中的应用: SSS介绍 SSS部署 SSS应用 http://www.cnblogs.com/renzh/archive/2013/03/31/2990280.html 创建.部署.应用S ...

  6. Java map取value最大值和最小值

    /** * 求Map<K,V>中Value(值)的最小值 * * @param map * @return */ public static Object getMinValue(Map& ...

  7. ajax.js

    /**通用ajax服务的定义对象 * services可以是单个服务对象,也可以是service服务数组 * 具体服务的定义请参考appendServices成员函数 */ function Serv ...

  8. ThinkPHP第九天(在Admin分组中配置__PUBLIC__,$POST异步传输,import使用方法,验证码点击刷新方法,Create方法作用)

    1.项目分组之后,后台模板的公用文件一般放置在Tpl/Admin/Public中,这样子在替换模板路径时候如果还用__PUBLIC__时为了不与前台冲突,应该在Admin/config.php中配置一 ...

  9. python--data type

    1.Python中常见的数据类型有: 数据类型    内建函数 整型    int(),long() 浮点型    float() 字符串型    str() 列表    list() 元组    t ...

  10. Using WMIC For Gathering System Info

    WMIC is a command line interface to WMI (Windows Management Instrumentation). While it has many uses ...