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. Hat’s Words(字典树)

    Hat’s Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  2. [置顶] JDK-Future 模式和实现

    最近的项目用到了多线程,发现java.util.concurrent.Future蛮好用的. 像平时,写多线程一般使用Thread/Runnable,直接扔给线程池执行就好了.但是遇到了一些需要获取线 ...

  3. google chrome字体最小12px的问题

    解决Google浏览器不支持12px以下的字体大小的问题,有时设定了12PX,可在浏览器看时确不起作用 网络出现内核的浏览器有微软的Internet Explorer, Mozilla的Firefox ...

  4. gridview的高级使用

      后台数据 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Sy ...

  5. STL之map和multimap(关联容器)

    map是一类关联式容器.它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响.自动建立Key - value的对应,对于迭代器来说,可以修改实值,而不能修改key. ...

  6. seajs + easyui [转]

    * *content seajs+easyui使用 */ /** * 首先来看看在seajs中jquery和jquery插件如何使用 */ 1.jquery.js define(function(re ...

  7. XIV

    http://publib.boulder.ibm.com/infocenter/ibmxiv/r2/index.jsp

  8. Windows Phone 8初学者开发—第11部分:设置SounBoard应用程序

    原文 Windows Phone 8初学者开发—第11部分:设置SounBoard应用程序 原文地址: http://channel9.msdn.com/Series/Windows-Phone-8- ...

  9. Maven 版 JPA 最佳实践

    项目结构图 数据库环境 数据库:MySQL 版本:5.x 数据库名:jpa-demo 用户名密码:root/1234 代码清单 1:数据库脚本: /* Navicat MySQL Data Trans ...

  10. 羊和汽车问题(或s三门问题(Monty Hall problem)亦称为蒙提霍尔问题)

    三门问题(Monty Hall problem)亦称为蒙提霍尔问题.蒙特霍问题或蒙提霍尔悖论,大致出自美国的电视游戏节目Let's Make a Deal.问题名字来自该节目的主持人蒙提·霍尔(Mon ...