ARM 外部中断的过程

发布于 2022-02-15  1987 次阅读


前言

ARM的中断和51单片机的中断有不少不同的地方,这里梳理一下ARM外部中断的实现过程。

环境

  • ARM单片机:公司设计的EM537单片机
  • ARM指令集型号:V7-A

正文

一、ARM中断类型

首先参考《ARM体系结构与编程》第九章异常中断处理章节中的内容。
ARM中断可以分为以下几种类型:
ARM体系中的异常中断
ARM体系中的异常中断-续表

ARM中断向量的地址和优先级表格

ARM共有8种类型的中断,中断的数目可以扩展
EM537中通过TZIC模块,将IRQ中断数目扩展至128。

FIQ的中断,优先级高,延迟低。常用于DMA类型的中断。
我们平时使用最多的还是IRQ外部中断。

二、中断触发-处理中断的过程(以外部中断为例)

2.1 中断的配置

不同平台配置寄存器不同

  1. 打开想使用的中断允许位
  2. 配置中断优先级
  3. 打开总中断

2.2 中断的触发

满足中断触发条件后,由硬件进行触发。
作为开发者不需要关心硬件触发过程。

2.3 中断的执行

首先参考一下EM537的中断向量表:

@vectable.s
@--------------------------------
@ vector table
@--------------------------------

.global _start
.global UNDEF_HLDR
.global SWI_HLDR
.global PREFETCH_HLDR
.global ABORT_HLDR
.global IRQ_HLDR
.global FIQ_HLDR
.global JUMP_CS0
.global JUMP_COMMON
.arm

VECTORS:
.ifdef BOOT_DENALI
  ldr   pc, =JUMP_COMMON
.else
  .ifdef ARM_EMBEDDED_MODE
    ldr pc, =_start
  .else      
    ldr pc, =JUMP_CS0
  .endif
.endif
  ldr   pc, =UNDEF_HLDR
  ldr   pc, =SWI_HLDR
  ldr   pc, =PREFETCH_HLDR
  ldr   pc, =ABORT_HLDR
  nop
  ldr   pc, =IRQ_HLDR
  ldr   pc, =FIQ_HLDR
  nop
  nop

首先定义的是复位异常中断,此中断跳转地址是正常程序的起始地址_start

然后按顺序定义其他的中断跳转地址。
硬件触发外部中断后,ARM会跳转到IRQ_HLDR。
然后来看看 IRQ_HLDR的汇编。

@crt0.s的部分内容
IRQ_HLDR:
  stmfd   sp!, {r0-r12,lr}

  ldr  r0,= TZIC_BASE_ADDR+0xD80 @; HIPND0 interrupt pending register
  ldr  r0,[r0]
  mov r2, #0x0
  cmp r0, #0
  bne FIND_NUMBER

    ldr  r0,= TZIC_BASE_ADDR+0xD84 @; HIPND1 interrupt pending register
  ldr  r0,[r0]
  mov r2, #32
  cmp r0, #0
  bne FIND_NUMBER

  ldr  r0,=  TZIC_BASE_ADDR+0xD88 @; HIPND2 interrupt pending register
  ldr  r0,[r0]
  mov r2, #64
  cmp r0, #0
  bne FIND_NUMBER

  ldr  r0,=  TZIC_BASE_ADDR+0xD8C @; HIPND3 interrupt pending register
  ldr  r0,[r0]
  mov r2, #96
  cmp r0, #0
  bne FIND_NUMBER

FIND_NUMBER:
  mov r0, r0, lsr #1
  cmp r0, #0
  beq FOUND_NUMBER
  add r2, r2, #0x1
  b FIND_NUMBER

FOUND_NUMBER:
  mov r2, r2, lsl #2
  mov r0, r2

  ldr  lr,=INTERRUPT_0
  ldr  r0,[lr,r0]
  mov     lr,pc
  bx      r0
    mrs  r0, cpsr
    bic  r1, r0, #0x100
    msr  cpsr_cxsf, r1
    ldmfd   sp!, {r0-r12,lr}
  subs    pc,lr,#4

首先stmfd 压栈, 保护CPU状态。
接下来是4段比较相似的程序,用于查询触发的外部中断号

TZIC 实现了128个外部中断,使用前需要先对TZIC进行配置。
设置相应中断的中断号。如果此中断触发,就可以在HIPND(0-3) interrupt pending register这四个寄存器中查到。

然后解析一下其中一段程序的内容:

@将中断挂起寄存器0的地址,保存到r0
 ldr  r0,= TZIC_BASE_ADDR+0xD80 @; HIPND0 interrupt pending register

@寄存器间接寻址,将r0寄存器的值看作地址,然后将地址对应的值传给r0
  ldr  r0,[r0]

@r2 = 0
  mov r2, #0x0

@比较r0和0的大小,如果r0!=0,则跳转FIND_NUMBER
  cmp r0, #0
  bne FIND_NUMBER

@回顾这段代码,功能是检查中断挂起寄存器的值,如果全零就检查下一个,否则跳转FIND_NUMBER计算相应的中断号

FIND_NUMBER通过移位找出中断号,然后保存在r2中。
FOUND_NUMBER首先左移2,相当于*4,是为了计算相应的偏移地址。然后保存在r0中。

ldr  lr,=INTERRUPT_0
ldr  r0,[lr,r0]

这两句是相对寻址,最后r0=INTERRUPT_0的地址+r0。

结合下面的汇编代码,更容易理解

然后就可以跳转到对应的外部中断处理程序。

@int_table.s的部分
.global INTERRUPT_0
    .global ESDHC1_INT_ROUTINE
    .global ESDHC2_INT_ROUTINE
    .global ESDHC3_INT_ROUTINE
    .global ESDHC4_INT_ROUTINE
    .global DAP_INT_ROUTINE
    .global SDMA_INT_ROUTINE
    .global IOMUX_INT_ROUTINE
    .global EMI1_INT_ROUTINE
    .global VPU1_INT_ROUTINE
    .global IPU_ERR_INT_ROUTINE
    .global IPU_FUNC_INT_ROUTINE
    .global GPU1_INT_ROUTINE
    .global UART4_ANDED_INT_ROUTINE
    .global USB_UH1_INT_ROUTINE
    .global EMI2_INT_ROUTINE
    .global USB_UH2_INT_ROUTINE
    .global USB_UH3_INT_ROUTINE
    .global USB_UOTG_INT_ROUTINE
    .global SAHARA_INT1_ROUTINE
    .global SAHARA_INT2_ROUTINE
    .global SCC_SMON_INT_ROUTINE
    .global SCC_SCTL_INT_ROUTINE
    .global SCC_SCTL_NS_INT_ROUTINE
    .global SRTC_INT_ROUTINE
    .global SRTC_SEC_INT_ROUTINE
    .global RTIC_INT_ROUTINE
    .global CSU_INT_ROUTINE
    .global SATA_INT_ROUTINE
    .global SSI1_INT_ROUTINE
    .global SSI2_INT_ROUTINE
    .global UART1_ANDED_INT_ROUTINE
    .global UART2_ANDED_INT_ROUTINE
    .global UART3_ANDED_INT_ROUTINE

2.4 代码中调用中断(动态设置中断函数)

首先引用一下,参考文献1,2关于global的说明

.global 修饰标号为全局的,用法 .global xxx 这个符号可以被当前源文件以外的其他文件使用也可以被连接脚本(连接器)使用,xxx仅仅是一个标号对应一个地址并不是C中的一个变量。
无法对他取地址,因为他本身代表一个地址,仅仅是一个对应到一个编译过程中的值的别名,类似C代码中的define 定义的一样,只是在链接时他的值是由连接器自动处理的。
汇编代码使用仅能使用ldr,Rx,=xxx;而不能使用ldr,Rx,xxx

.global关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用。
.global _start 让_start符号成为可见的标示符,这样链接器就知道跳转到程序中的什么地方并开始执行。linux寻找这个 _start标签作为程序的默认进入点。
在汇编和C混合编程中,在GNU ARM编译环境下,汇编程序中要使用.global伪操作声明汇编程序为全局的函数,意即可被外部函数调用,同时C程序中要使用extern声明要调用的汇编语言程序。

所以ini_table.s中的.global UART1_ANDED_INT_ROUTINE只是声明了一个符号,并没有相应的程序。
在interrupt.h文件中extern void ( *UART1_ANDED_INT_ROUTINE )(void);使用extern关键字声明,以便在c里面进行调用。
这里声明的UART1_ANDED_INT_ROUTINE是一个函数指针。
这里引用参考文献4中的介绍:
Snipaste_2022-02-15_10-54-01.png

因此可以通过更改UART1_ANDED_INT_ROUTINE中断函数指针指向的函数,实现动态更改中断函数。
EM537中使用下面里例子进行设置:

#define CAPTURE_INTERRUPT(handle,routine) handle = (void (*)(void)) routine
__irq(intr_routin1)
#pragma interrupt intr_routin1 
void intr_routin1(void);

void intr_routin1(void){
//用户自定义函数内容
}

void main(){
CAPTURE INTERRUPT(UART1_ANDED_INT_ROUTINE, intr_routin1);
}

三、ARM初始化配置

想要正确的执行中断,还需要对ARM寄存器进行上电初始化。
初始化的主要功能是:

  1. 初始化Rn等常用寄存器的值为0;(理论上要使用的内存区域都要初始化,避免硬件初始化值不同造成错误。)
  2. 初始化各种处理器模式下的堆栈指针,否则堆栈指针可能会覆盖内存中的值,造成程序错误。
  3. 进入SPVR 模式 打开程序状态寄存器(CPSR)中的IRQ和FIQ中断标志位。

    附件2 crt0.s是初始化相关的汇编代码。

附件

1. interrupt.h


// These interrupts MUST be defined in the correct order.

// IRQ INTERRUPT
extern void ( *INTERRUPT_0 )(void);                //RESERVED
extern void ( *ESDHC1_INT_ROUTINE )(void);
extern void ( *ESDHC2_INT_ROUTINE )(void);
extern void ( *ESDHC3_INT_ROUTINE )(void);
extern void ( *ESDHC4_INT_ROUTINE )(void);
extern void ( *DAP_INT_ROUTINE )(void);
extern void ( *SDMA_INT_ROUTINE )(void);
extern void ( *IOMUX_INT_ROUTINE )(void);
extern void ( *EMI1_INT_ROUTINE )(void);
extern void ( *VPU1_INT_ROUTINE )(void);
extern void ( *IPU_ERR_INT_ROUTINE )(void);
extern void ( *IPU_FUNC_INT_ROUTINE )(void);
extern void ( *GPU1_INT_ROUTINE )(void);
extern void ( *UART4_ANDED_INT_ROUTINE )(void);  
extern void ( *USB_UH1_INT_ROUTINE )(void);
extern void ( *EMI2_INT_ROUTINE )(void);
extern void ( *USB_UH2_INT_ROUTINE )(void);
extern void ( *USB_UH3_INT_ROUTINE )(void);
extern void ( *USB_UOTG_INT_ROUTINE )(void);
extern void ( *SAHARA_INT1_ROUTINE )(void);
extern void ( *SAHARA_INT2_ROUTINE )(void);
extern void ( *SCC_SMON_INT_ROUTINE )(void);
extern void ( *SCC_SCTL_INT_ROUTINE )(void);
extern void ( *SCC_SCTL_NS_INT_ROUTINE )(void);
extern void ( *SRTC_INT_ROUTINE )(void);
extern void ( *SRTC_SEC_INT_ROUTINE )(void);
extern void ( *RTIC_INT_ROUTINE )(void);
extern void ( *CSU_INT_ROUTINE )(void);
extern void ( *SATA_INT_ROUTINE )(void);
extern void ( *SSI1_INT_ROUTINE )(void);
extern void ( *SSI2_INT_ROUTINE )(void);
extern void ( *UART1_ANDED_INT_ROUTINE )(void);
extern void ( *UART2_ANDED_INT_ROUTINE )(void);
extern void ( *UART3_ANDED_INT_ROUTINE )(void);
extern void ( *RTC_INT_ROUTINE )(void);
extern void ( *PTP_INT_ROUTINE )(void);
extern void ( *ECSPI1_INT_ROUTINE )(void);
extern void ( *ECSPI2_INT_ROUTINE )(void);
extern void ( *CSPI_INT_ROUTINE )(void);
extern void ( *GPT_INT_ROUTINE )(void);
extern void ( *EPIT1_INT_ROUTINE )(void);
extern void ( *EPIT2_INT_ROUTINE )(void);
extern void ( *GPIO1_INT7_ROUTINE )(void);
extern void ( *GPIO1_INT6_ROUTINE )(void);
extern void ( *GPIO1_INT5_ROUTINE )(void);
extern void ( *GPIO1_INT4_ROUTINE )(void);
extern void ( *GPIO1_INT3_ROUTINE )(void);
extern void ( *GPIO1_INT2_ROUTINE )(void);
extern void ( *GPIO1_INT1_ROUTINE )(void);
extern void ( *GPIO1_INT0_ROUTINE )(void);
extern void ( *GPIO1_INT15_0_ROUTINE )(void);
extern void ( *GPIO1_INT31_16_ROUTINE )(void);
extern void ( *GPIO2_INT15_0_ROUTINE )(void);
extern void ( *GPIO2_INT31_16_ROUTINE )(void);
extern void ( *GPIO3_INT15_0_ROUTINE )(void);
extern void ( *GPIO3_INT31_16_ROUTINE )(void);
extern void ( *GPIO4_INT15_0_ROUTINE )(void);
extern void ( *GPIO4_INT31_16_ROUTINE )(void);
extern void ( *WDOG1_INT_ROUTINE )(void);
extern void ( *WDOG2_INT_ROUTINE )(void);
extern void ( *KPP_INT_ROUTINE )(void);
extern void ( *PWM1_INT_ROUTINE )(void);
extern void ( *I2C1_INT_ROUTINE )(void);
extern void ( *I2C2_INT_ROUTINE )(void);
extern void ( *I2C3_INT_ROUTINE )(void);
extern void ( *MLB_INT_ROUTINE )(void);
extern void ( *ASRC_INT_ROUTINE )(void);
extern void ( *SPDIF_INT_ROUTINE )(void);
extern void ( *INTERRUPT_68 )(void);               //RESERVED
extern void ( *IIM_INT_ROUTINE )(void);
extern void ( *PATA_INT_ROUTINE )(void);
extern void ( *CCM_INT1_ROUTINE )(void);
extern void ( *CCM_INT2_ROUTINE )(void);
extern void ( *GPC_INT1_ROUTINE )(void);
extern void ( *GPC_INT2_ROUTINE )(void);
extern void ( *SRC_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K_NM_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K_PMU_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K_CTI_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K1_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K2_INT_ROUTINE )(void);
extern void ( *ESAI1_INT_ROUTINE )(void);
extern void ( *CAN1_INT_ROUTINE )(void);
extern void ( *CAN2_INT_ROUTINE )(void);
extern void ( *GPU2D_IRQ_INT_ROUTINE )(void);
extern void ( *GPU2D_BUSY_INT_ROUTINE )(void);
extern void ( *UART5_ANDED_INT_ROUTINE )(void);   
extern void ( *FEC_INT_ROUTINE )(void);
extern void ( *OWIRE_INT_ROUTINE )(void);
extern void ( *TIGERP_PLATFORM_NE_32K_256K3_INT_ROUTINE )(void);
extern void ( *SJC_INT_ROUTINE )(void);
extern void ( *INTERRUPT_91 )(void);               //RESERVED
extern void ( *TVOUT_INT_ROUTINE )(void);
extern void ( *FIRI_INT_ROUTINE )(void);
extern void ( *PWM2_INT_ROUTINE )(void);
extern void ( *INTERRUPT_95 )(void);               //RESERVED
extern void ( *SSI3_INT_ROUTINE )(void);
extern void ( *INTERRUPT_97 )(void);               //RESERVED
extern void ( *TIGERP_PLATFORM_NE_32K_256K4_INT_ROUTINE )(void);
extern void ( *INTERRUPT_99 )(void);               //RESERVED
extern void ( *VPU2_INT_ROUTINE )(void);
extern void ( *EMI_PROG_INT_ROUTINE )(void);
extern void ( *GPU2_INT_ROUTINE )(void);
extern void ( *GPIO5_INT15_0_ROUTINE )(void);
extern void ( *GPIO5_INT31_16_ROUTINE )(void);
extern void ( *GPIO6_INT15_0_ROUTINE )(void);
extern void ( *GPIO6_INT31_16_ROUTINE )(void);
extern void ( *GPIO7_INT15_0_ROUTINE )(void);
extern void ( *GPIO7_INT31_16_ROUTINE )(void);
extern void ( *INTERRUPT_109_128 )(void);          //RESERVED

// IRQ TZIC INTERRUPT NUMBER
#define INTERRUPT_0_NUM                            0         //RESERVED
#define ESDHC1_INT_NUM                             1
#define ESDHC2_INT_NUM                             2
#define ESDHC3_INT_NUM                             3
#define ESDHC4_INT_NUM                             4
#define DAP_INT_NUM                                5
#define SDMA_INT_NUM                               6
#define IOMUX_INT_NUM                              7
#define EMI1_INT_NUM                               8
#define VPU1_INT_NUM                               9
#define IPU_ERR_INT_NUM                            10
#define IPU_FUNC_INT_NUM                           11
#define GPU1_INT_NUM                               12
#define UART4_ANDED_INT_NUM                        13
#define USB_UH1_INT_NUM                            14
#define EMI2_INT_NUM                               15
#define USB_UH2_INT_NUM                            16
#define USB_UH3_INT_NUM                            17
#define USB_UOTG_INT_NUM                           18
#define SAHARA_INT1_NUM                            19
#define SAHARA_INT2_NUM                            20
#define SCC_SMON_INT_NUM                           21
#define SCC_SCTL_INT_NUM                           22
#define SCC_SCTL_NS_INT_NUM                        23
#define SRTC_INT_NUM                               24
#define SRTC_SEC_INT_NUM                           25
#define RTIC_INT_NUM                               26
#define CSU_INT_NUM                                27
#define SATA_INT_NUM                               28
#define SSI1_INT_NUM                               29
#define SSI2_INT_NUM                               30
#define UART1_ANDED_INT_NUM                        31
#define UART2_ANDED_INT_NUM                        32
#define UART3_ANDED_INT_NUM                        33
#define RTC_INT_NUM                                34
#define PTP_INT_NUM                                35
#define ECSPI1_INT_NUM                             36
#define ECSPI2_INT_NUM                             37
#define CSPI_INT_NUM                               38
#define GPT_INT_NUM                                39
#define EPIT1_INT_NUM                              40
#define EPIT2_INT_NUM                              41
#define GPIO1_INT7_NUM                             42
#define GPIO1_INT6_NUM                             43
#define GPIO1_INT5_NUM                             44
#define GPIO1_INT4_NUM                             45
#define GPIO1_INT3_NUM                             46
#define GPIO1_INT2_NUM                             47
#define GPIO1_INT1_NUM                             48
#define GPIO1_INT0_NUM                             49
#define GPIO1_INT15_0_NUM                          50
#define GPIO1_INT31_16_NUM                         51
#define GPIO2_INT15_0_NUM                          52
#define GPIO2_INT31_16_NUM                         53
#define GPIO3_INT15_0_NUM                          54
#define GPIO3_INT31_16_NUM                         55
#define GPIO4_INT15_0_NUM                          56
#define GPIO4_INT31_16_NUM                         57
#define WDOG1_INT_NUM                              58
#define WDOG2_INT_NUM                              59
#define KPP_INT_NUM                                60
#define PWM1_INT_NUM                               61
#define I2C1_INT_NUM                               62
#define I2C2_INT_NUM                               63
#define I2C3_INT_NUM                               64
#define MLB_INT_NUM                                65
#define ASRC_INT_NUM                               66
#define SPDIF_INT_NUM                              67
#define INTERRUPT_68_NUM                           68       //RESERVED
#define IIM_INT_NUM                                69
#define PATA_INT_NUM                               70
#define CCM_INT1_NUM                               71
#define CCM_INT2_NUM                               72
#define GPC_INT1_NUM                               73
#define GPC_INT2_NUM                               74
#define SRC_INT_NUM                                75
#define TIGERP_PLATFORM_NE_32K_256K_NM_INT_NUM     76
#define TIGERP_PLATFORM_NE_32K_256K_PMU_INT_NUM    77
#define TIGERP_PLATFORM_NE_32K_256K_CTI_INT_NUM    78
#define TIGERP_PLATFORM_NE_32K_256K1_INT_NUM       79
#define TIGERP_PLATFORM_NE_32K_256K2_INT_NUM       80
#define ESAI1_INT_NUM                              81
#define CAN1_INT_NUM                               82
#define CAN2_INT_NUM                               83
#define GPU2D_IRQ_INT_NUM                          84
#define GPU2D_BUSY_INT_NUM                         85
#define UART5_ANDED_INT_NUM                        86 
#define FEC_INT_NUM                                87
#define OWIRE_INT_NUM                              88
#define TIGERP_PLATFORM_NE_32K_256K3_INT_NUM       89
#define SJC_INT_NUM                                90
#define INTERRUPT_91_NUM                           91        //RESERVED
#define TVOUT_INT_NUM                              92
#define FIRI_INT_NUM                               93
#define PWM2_INT_NUM                               94
#define INTERRUPT_95_NUM                           95        //RESERVED
#define SSI3_INT_NUM                               96
#define INTERRUPT_97_NUM                           97        //RESERVED
#define TIGERP_PLATFORM_NE_32K_256K4_INT_NUM       98
#define INTERRUPT_99_NUM                           99        //RESERVED
#define VPU2_INT_NUM                               100
#define EMI_PROG_INT_NUM                           101
#define GPU2_INT_NUM                               102
#define GPIO5_INT15_0_NUM                          103
#define GPIO5_INT31_16_NUM                         104
#define GPIO6_INT15_0_NUM                          105
#define GPIO6_INT31_16_NUM                         106
#define GPIO7_INT15_0_NUM                          107
#define GPIO7_INT31_16_NUM                         108
#define INTERRUPT_109_128_NUM                      109       //RESERVED

#ifdef ROC_TEST
#define ROC_ABORT_INTERRUPT  127 //abort interrupt for ROC test only!!! (shayg)
#endif //ROC_TEST

// FIQ INTERRUPT
extern void ( *FIQ_INTERRUPT_0 )(void);                //RESERVED
extern void ( *FIQ_ESDHC1_INT_ROUTINE )(void);
extern void ( *FIQ_ESDHC2_INT_ROUTINE )(void);
extern void ( *FIQ_ESDHC3_INT_ROUTINE )(void);
extern void ( *FIQ_ESDHC4_INT_ROUTINE )(void);
extern void ( *FIQ_DAP_INT_ROUTINE )(void);
extern void ( *FIQ_SDMA_INT_ROUTINE )(void);
extern void ( *FIQ_IOMUX_INT_ROUTINE )(void);
extern void ( *FIQ_EMI1_INT_ROUTINE )(void);
extern void ( *FIQ_VPU1_INT_ROUTINE )(void);
extern void ( *FIQ_IPU_ERR_INT_ROUTINE )(void);
extern void ( *FIQ_IPU_FUNC_INT_ROUTINE )(void);
extern void ( *FIQ_GPU1_INT_ROUTINE )(void);
extern void ( *FIQ_UART4_ANDED_INT_ROUTINE )(void);      
extern void ( *FIQ_USB_UH1_INT_ROUTINE )(void);
extern void ( *FIQ_EMI2_INT_ROUTINE )(void);
extern void ( *FIQ_USB_UH2_INT_ROUTINE )(void);
extern void ( *FIQ_USB_UH3_INT_ROUTINE )(void);
extern void ( *FIQ_USB_UOTG_INT_ROUTINE )(void);
extern void ( *FIQ_SAHARA_INT1_ROUTINE )(void);
extern void ( *FIQ_SAHARA_INT2_ROUTINE )(void);
extern void ( *FIQ_SCC_SMON_INT_ROUTINE )(void);
extern void ( *FIQ_SCC_SCTL_INT_ROUTINE )(void);
extern void ( *FIQ_SCC_SCTL_NS_INT_ROUTINE )(void);
extern void ( *FIQ_SRTC_INT_ROUTINE )(void);
extern void ( *FIQ_SRTC_SEC_INT_ROUTINE )(void);
extern void ( *FIQ_RTIC_INT_ROUTINE )(void);
extern void ( *FIQ_CSU_INT_ROUTINE )(void);
extern void ( *FIQ_SATA_INT_ROUTINE )(void);
extern void ( *FIQ_SSI1_INT_ROUTINE )(void);
extern void ( *FIQ_SSI2_INT_ROUTINE )(void);
extern void ( *FIQ_UART1_ANDED_INT_ROUTINE )(void);
extern void ( *FIQ_UART2_ANDED_INT_ROUTINE )(void);
extern void ( *FIQ_UART3_ANDED_INT_ROUTINE )(void);
extern void ( *FIQ_RTC_INT_ROUTINE )(void);
extern void ( *FIQ_PTP_INT_ROUTINE )(void);
extern void ( *FIQ_ECSPI1_INT_ROUTINE )(void);
extern void ( *FIQ_ECSPI2_INT_ROUTINE )(void);
extern void ( *FIQ_CSPI_INT_ROUTINE )(void);
extern void ( *FIQ_GPT_INT_ROUTINE )(void);
extern void ( *FIQ_EPIT1_INT_ROUTINE )(void);
extern void ( *FIQ_EPIT2_INT_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT7_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT6_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT5_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT4_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT3_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT2_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT1_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT0_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO1_INT31_16_ROUTINE )(void);
extern void ( *FIQ_GPIO2_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO2_INT31_16_ROUTINE )(void);
extern void ( *FIQ_GPIO3_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO3_INT31_16_ROUTINE )(void);
extern void ( *FIQ_GPIO4_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO4_INT31_16_ROUTINE )(void);
extern void ( *FIQ_WDOG1_INT_ROUTINE )(void);
extern void ( *FIQ_WDOG2_INT_ROUTINE )(void);
extern void ( *FIQ_KPP_INT_ROUTINE )(void);
extern void ( *FIQ_PWM1_INT_ROUTINE )(void);
extern void ( *FIQ_I2C1_INT_ROUTINE )(void);
extern void ( *FIQ_I2C2_INT_ROUTINE )(void);
extern void ( *FIQ_I2C3_INT_ROUTINE )(void);
extern void ( *FIQ_MLB_INT_ROUTINE )(void);
extern void ( *FIQ_ASRC_INT_ROUTINE )(void);
extern void ( *FIQ_SPDIF_INT_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_68 )(void);               //RESERVED
extern void ( *FIQ_IIM_INT_ROUTINE )(void);
extern void ( *FIQ_PATA_INT_ROUTINE )(void);
extern void ( *FIQ_CCM_INT1_ROUTINE )(void);
extern void ( *FIQ_CCM_INT2_ROUTINE )(void);
extern void ( *FIQ_GPC_INT1_ROUTINE )(void);
extern void ( *FIQ_GPC_INT2_ROUTINE )(void);
extern void ( *FIQ_SRC_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K_NM_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K_PMU_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K_CTI_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K1_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K2_INT_ROUTINE )(void);
extern void ( *FIQ_ESAI1_INT_ROUTINE )(void);
extern void ( *FIQ_CAN1_INT_ROUTINE )(void);
extern void ( *FIQ_CAN2_INT_ROUTINE )(void);
extern void ( *FIQ_GPU2D_IRQ_INT_ROUTINE )(void);
extern void ( *FIQ_GPU2D_BUSY_INT_ROUTINE )(void);
extern void ( *FIQ_UART5_ANDED_INT_ROUTINE )(void);
extern void ( *FIQ_FEC_INT_ROUTINE )(void);
extern void ( *FIQ_OWIRE_INT_ROUTINE )(void);
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K3_INT_ROUTINE )(void);
extern void ( *FIQ_SJC_INT_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_91 )(void);               //RESERVED
extern void ( *FIQ_TVOUT_INT_ROUTINE )(void);
extern void ( *FIQ_FIRI_INT_ROUTINE )(void);
extern void ( *FIQ_PWM2_INT_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_95 )(void);               //RESERVED
extern void ( *FIQ_SSI3_INT_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_97 )(void);               //RESERVED
extern void ( *FIQ_TIGERP_PLATFORM_NE_32K_256K4_INT_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_99 )(void);               //RESERVED
extern void ( *FIQ_VPU2_INT_ROUTINE )(void);
extern void ( *FIQ_EMI_PROG_INT_ROUTINE )(void);
extern void ( *FIQ_GPU2_INT_ROUTINE )(void);
extern void ( *FIQ_GPIO5_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO5_INT31_16_ROUTINE )(void);
extern void ( *FIQ_GPIO6_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO6_INT31_16_ROUTINE )(void);
extern void ( *FIQ_GPIO7_INT15_0_ROUTINE )(void);
extern void ( *FIQ_GPIO7_INT31_16_ROUTINE )(void);
extern void ( *FIQ_INTERRUPT_109_128 )(void);          //RESERVED

// FIQ TZIC INTERRUPT NUMBER
#define FIQ_INTERRUPT_0_NUM                            0         //RESERVED
#define FIQ_ESDHC1_INT_NUM                             1
#define FIQ_ESDHC2_INT_NUM                             2
#define FIQ_ESDHC3_INT_NUM                             3
#define FIQ_ESDHC4_INT_NUM                             4
#define FIQ_DAP_INT_NUM                                5
#define FIQ_SDMA_INT_NUM                               6
#define FIQ_IOMUX_INT_NUM                              7
#define FIQ_EMI1_INT_NUM                               8
#define FIQ_VPU1_INT_NUM                               9
#define FIQ_IPU_ERR_INT_NUM                            10
#define FIQ_IPU_FUNC_INT_NUM                           11
#define FIQ_GPU1_INT_NUM                               12
#define FIQ_UART4_ANDED_INT_NUM                        13     
#define FIQ_USB_UH1_INT_NUM                            14
#define FIQ_EMI2_INT_NUM                               15
#define FIQ_USB_UH2_INT_NUM                            16
#define FIQ_USB_UH3_INT_NUM                            17
#define FIQ_USB_UOTG_INT_NUM                           18
#define FIQ_SAHARA_INT1_NUM                            19
#define FIQ_SAHARA_INT2_NUM                            20
#define FIQ_SCC_SMON_INT_NUM                           21
#define FIQ_SCC_SCTL_INT_NUM                           22
#define FIQ_SCC_SCTL_NS_INT_NUM                        23
#define FIQ_SRTC_INT_NUM                               24
#define FIQ_SRTC_SEC_INT_NUM                           25
#define FIQ_RTIC_INT_NUM                               26
#define FIQ_CSU_INT_NUM                                27
#define FIQ_SATA_INT_NUM                               28
#define FIQ_SSI1_INT_NUM                               29
#define FIQ_SSI2_INT_NUM                               30
#define FIQ_UART1_ANDED_INT_NUM                        31
#define FIQ_UART2_ANDED_INT_NUM                        32
#define FIQ_UART3_ANDED_INT_NUM                        33
#define FIQ_RTC_INT_NUM                                34
#define FIQ_PTP_INT_NUM                                35
#define FIQ_ECSPI1_INT_NUM                             36
#define FIQ_ECSPI2_INT_NUM                             37
#define FIQ_CSPI_INT_NUM                               38
#define FIQ_GPT_INT_NUM                                39
#define FIQ_EPIT1_INT_NUM                              40
#define FIQ_EPIT2_INT_NUM                              41
#define FIQ_GPIO1_INT7_NUM                             42
#define FIQ_GPIO1_INT6_NUM                             43
#define FIQ_GPIO1_INT5_NUM                             44
#define FIQ_GPIO1_INT4_NUM                             45
#define FIQ_GPIO1_INT3_NUM                             46
#define FIQ_GPIO1_INT2_NUM                             47
#define FIQ_GPIO1_INT1_NUM                             48
#define FIQ_GPIO1_INT0_NUM                             49
#define FIQ_GPIO1_INT15_0_NUM                          50
#define FIQ_GPIO1_INT31_16_NUM                         51
#define FIQ_GPIO2_INT15_0_NUM                          52
#define FIQ_GPIO2_INT31_16_NUM                         53
#define FIQ_GPIO3_INT15_0_NUM                          54
#define FIQ_GPIO3_INT31_16_NUM                         55
#define FIQ_GPIO4_INT15_0_NUM                          56
#define FIQ_GPIO4_INT31_16_NUM                         57
#define FIQ_WDOG1_INT_NUM                              58
#define FIQ_WDOG2_INT_NUM                              59
#define FIQ_KPP_INT_NUM                                60
#define FIQ_PWM1_INT_NUM                               61
#define FIQ_I2C1_INT_NUM                               62
#define FIQ_I2C2_INT_NUM                               63
#define FIQ_I2C3_INT_NUM                               64
#define FIQ_MLB_INT_NUM                                65
#define FIQ_ASRC_INT_NUM                               66
#define FIQ_SPDIF_INT_NUM                              67
#define FIQ_INTERRUPT_68_NUM                           68        //RESERVED
#define FIQ_IIM_INT_NUM                                69
#define FIQ_PATA_INT_NUM                               70
#define FIQ_CCM_INT1_NUM                               71
#define FIQ_CCM_INT2_NUM                               72
#define FIQ_GPC_INT1_NUM                               73
#define FIQ_GPC_INT2_NUM                               74
#define FIQ_SRC_INT_NUM                                75
#define FIQ_TIGERP_PLATFORM_NE_32K_256K_NM_INT_NUM     76
#define FIQ_TIGERP_PLATFORM_NE_32K_256K_PMU_INT_NUM    77
#define FIQ_TIGERP_PLATFORM_NE_32K_256K_CTI_INT_NUM    78
#define FIQ_TIGERP_PLATFORM_NE_32K_256K1_INT_NUM       79
#define FIQ_TIGERP_PLATFORM_NE_32K_256K2_INT_NUM       80
#define FIQ_ESAI1_INT_NUM                              81
#define FIQ_CAN1_INT_NUM                               82
#define FIQ_CAN2_INT_NUM                               83
#define FIQ_GPU2D_IRQ_INT_NUM                          84
#define FIQ_GPU2D_BUSY_INT_NUM                         85
#define FIQ_UART5_ANDED_INT_NUM                        86    
#define FIQ_FEC_INT_NUM                                87
#define FIQ_OWIRE_INT_NUM                              88
#define FIQ_TIGERP_PLATFORM_NE_32K_256K3_INT_NUM       89
#define FIQ_SJC_INT_NUM                                90
#define FIQ_INTERRUPT_91_NUM                           91        //RESERVED
#define FIQ_TVOUT_INT_NUM                              92
#define FIQ_FIRI_INT_NUM                               93
#define FIQ_PWM2_INT_NUM                               94
#define FIQ_INTERRUPT_95_NUM                           95        //RESERVED
#define FIQ_SSI3_INT_NUM                               96
#define FIQ_INTERRUPT_97_NUM                           97
#define FIQ_TIGERP_PLATFORM_NE_32K_256K4_INT_NUM       98
#define FIQ_INTERRUPT_99_NUM                           99        //RESERVED
#define FIQ_VPU2_INT_NUM                               100
#define FIQ_EMI_PROG_INT_NUM                           101
#define FIQ_GPU2_INT_NUM                               102
#define FIQ_GPIO5_INT15_0_NUM                          103
#define FIQ_GPIO5_INT31_16_NUM                         104
#define FIQ_GPIO6_INT15_0_NUM                          105
#define FIQ_GPIO6_INT31_16_NUM                         106
#define FIQ_GPIO7_INT15_0_NUM                          107
#define FIQ_GPIO7_INT31_16_NUM                         108
#define FIQ_INTERRUPT_109_128_NUM                      109       //RESERVED

2. crt0.s

    .global   RESET_HLDR
    .global   UNDEF_HLDR
    .global   SWI_HLDR
    .global   PREFETCH_HLDR
    .global   ABORT_HLDR
    .global   IRQ_HLDR
    .global   FIQ_HLDR
    .global   SMI_HLDR

    .extern   __init_main
    .extern   main
    .extern   main_section
    .extern   SMI_RANDOM

  .global    _start

  .global undef_hdler
  .global swi_hdler
  .global prefetch_hdler
  .global abort_hdler
  .global irq_hdler
  .global fiq_hdler
  .global smi_hdler
  .extern rompatch_tbl_ptr

  .extern c_main
  .extern UNDEF_HLDR_EXCEPT
  .extern SWI_HLDR_EXCEPT
  .extern PREFETCH_HLDR_EXCEPT
  .extern ABORT_HLDR_EXCEPT
  .extern IRQ_HLDR_EXCEPT
  .extern FIQ_HLDR_EXCEPT
  .extern SMI_HLDR_EXCEPT

    .align    4
    .arm

    .section .start

.macro  write_reg addr, val
    ldr r0, =\addr
    ldr r1, =\val
    str r1, [r0]
.endm

.macro  read_reg addr, reg
    ldr r0, =\addr
    ldr \reg, [r0]
.endm

.equ TZIC_BASE_ADDR,                 0x0FFFC000
.equ IRAM_BASE_ADDR,                 0xF8000000
.equ RAM_TEST_CODE_ADDR,             IRAM_BASE_ADDR+0x1000  @; F800_1000 - F800_FFFF (EFFF)  Test code

_start:
    nop
CRT0_START:

@;@@@@@@@@@@@@@@@@@NORMAL@@@@@@@@@@@@@

    @; initialize registers in USER mode

    mov    r0,#0
    mov    r1,#0
    mov    r2,#0
    mov    r3,#0
    mov    r4,#0
    mov    r5,#0
    mov    r6,#0
    mov    r7,#0
    mov    r8,#0
    mov    r9,#0
    mov    r10,#0
    mov    r11,#0
    mov    r12,#0

   @; ARM_EMBEDDED_MODE

    mrs    r7,CPSR
    bic    r7,r7,#0x0f    @; clear mode bits
    add    r6,r7,#0x01
    msr    CPSR,r6        @; goto FIQ mode

    @; initialize registers in FIQ mode

    mov    r8,#0
    mov    r9,#0
    mov    r10,#0
    mov    r11,#0
    mov    r12,#0
    ldr    sp,=__SP_FIQ
    mov    lr,#0

    add    r6,r7,#0x02
    msr    CPSR,r6        @; goto IRQ mode

    @; initialize registers in IRQ mode

    ldr    sp,=__SP_IRQ
    mov    lr,#0

    add    r6,r7,#0x03
    msr    CPSR,r6        @; goto SVC mode

    @; initialize registers in SVC mode

@; Read Secure or Nonsecure Vector Base Address Register
    mrc    p15,0,r5,c12,c0,1
    ldr    r5,=vects1_start
@; Write Secure or Nonsecure Vector Base Address Register
    mcr    p15,0,r5,c12,c0,1

    ldr    sp,=__SP_SVC
    mov    lr,#0

    add    r6,r7,#0x06
    msr    CPSR,r6         @;go to MON mode

@;initialize registers in monitor mode
    ldr    sp,=__SP_MON
    mov    lr,#0

    add    r6,r7,#0x07
    msr    CPSR,r6        @; goto ABORT mode

@; initialize registers in ABORT mode

    ldr    sp,=__SP_ABORT
    mov    lr,#0

    add    r6,r7,#0x0b
    msr    CPSR,r6        @; goto UNDEF mode

@; initialize registers in UNDEF mode

    ldr    sp,=__SP_UNDEF
    mov    lr,#0

    add    r6,r7,#0x0f
    msr    CPSR,r6        @; goto SYSTEM mode

    mrs r0, cpsr
    bic r1,r0, #0x100    @;@ try to clear the A bit
    msr cpsr_cxsf, r1
    mrs r0, cpsr

@; initialize registers in SYSTEM mode
@;
@; Note:    SYSTEM mode does not share r13 and r14 (i.e. sp and lr) with USER mode

    ldr    sp,=__SP_SYSTEM
    mov    lr,#0

@; Enable exceptions

    @; clean up and call the C 'main' function
    mrs    r6,CPSR
    bic    r7,r6,#0xc0    @; enable exceptions
    msr    CPSR,r7

    @; enable the coprocessors
  ldr r0,=0xffffffff
    mcr p15,0,r0,c1,c0,2

    @; ensure the return stack does not have x's  which can cause core to hang
        BL rs_label0
rs_label0:
        BL rs_label1
rs_label1:
        BL rs_label2
rs_label2:
        BL rs_label3
rs_label3:
        BL rs_label4
rs_label4:
        BL rs_label5
rs_label5:
        BL rs_label6
rs_label6:
        BL rs_label7
rs_label7:

@;; edof  27.8
@;; MOV to spvr mode so test will start in SPVR mode with SP_svc and LR_svc
  mrs r0,CPSR   @;; Read CPSR
  bic r0,r0,#0x1f  @;; Clear Mode bits
  orr r0,r0,#0x13 @;; Set the Mode bits to SPVR mode
  msr CPSR_c,r0 @;; Update the control bits in the CPSR , now in SPVR mode

@; Mapping the special handler UNDEF_HLDR,SWI_HLDR,PREFECH_HLDR,ABORT_HLDR,IRQ_HLDR,FIQ_HLDR.
@; look in $DESIGN_DIR/project_settings/testbench/arm_gnu/src/vectable.s for the HDLR order

    LDR r5, = 0x00000004
    LDR r6, = 0xE59FF014        @;op.code -> jump to the address in pc+0x1C

    LDR r1, = IRAM_BASE_ADDR+0x1FFBC  @;; RAM address,the ARM jump to this address when UNDEF occur.
    str r6, [r1]

    add r1,r1,r5    @; RAM address,the ARM jump to this address when SWI occur.
    str r6, [r1]

    add r1,r1,r5    @; RAM address,the ARM jump to this address when PREFECH occur.
    str r6, [r1]

    add r1,r1,r5    @; RAM address,the ARM jump to this address when ABORT occur.
    str r6, [r1]

    add r1,r1,r5    @; NOP - empty
    str r6, [r1]

    add r1,r1,r5    @; RAM address,the ARM jump to this address when IRQ occur.
    str r6, [r1]

    add r1,r1,r5    @; RAM address,the ARM jump to this address when FIQ occur.
    str r6, [r1]

    LDR r6, = RAM_TEST_CODE_ADDR        @;;UNDEF_HLDR place when running from RAM

    add r1,r1,r5
    str r6, [r1]    @;;UNDEF_HLDR place

    add r1,r1,r5
    ldr r2,= 0x1c
    add r6,r6,r2    @; addr=base+0x1c
    str r6, [r1]    @;;SWI_HLDR place

    add r1,r1,r5
    ldr r2,= 0x38
    add r6,r6,r2    @; addr=base+0x54
    str r6, [r1]    @;;PREFECH_HLDR place

    add r1,r1,r5
    ldr r2,= 0x1c
    add r6,r6,r2    @; addr=base+0x70
    str r6, [r1]    @;;ABORT_HLDR place

    add r1,r1,r5
    ldr r2,= 0x00
    add r6,r6,r2    @;
    str r6, [r1]    @;;NOP place

    add r1,r1,r5
    ldr r2,= 0x3c
    add r6,r6,r2    @; addr=base+0xac
    str r6, [r1]    @;;IRQ_HLDR place

    add r1,r1,r5
    ldr r2,= 0x94
    add r6,r6,r2    @; addr=base+0x140
    str r6, [r1]    @;;FIQ_HLDR place

    ldr r6,= 0x00001fff
    add r1,r1,r5
    str r6, [r1]    @; Data so we will not read xxxx (r1=SCC_RAM_BASE_ADDR+0x1FFF4)
    add r1,r1,r5
    str r6, [r1]    @; Data so we will not read xxxx (r1=SCC_RAM_BASE_ADDR+0x1FFF8)
    add r1,r1,r5
    str r6, [r1]    @; Data so we will not read xxxx (r1=SCC_RAM_BASE_ADDR+0x1FFFC)

  b       c_main

UNDEF_HLDR:
    stmfd   sp!, {r0,lr}           @; push our temp reg, R0, since C seems to feel free to bash it anyway
    ldr     lr,=undef_hdler        @; load address of pointer to undef handler function using LR temporarily
    ldr     r0,[lr]                @; load the undef handler function pointer into R0
    mov     lr,pc                  @; preserve PC in LR so that called code can return.
    bx      r0                     @; this way of doing the call allows Thumb code to be called
    ldmfd   sp!, {r0,lr}           @; then, pull back preserved R0.
    movs    pc,lr                  @; return from the interrupt to wherever LR points.

SWI_HLDR:
    stmfd   sp!, {r0-r1,lr}        @; push register onto SWI stack
    mrs     r0, spsr               @; get saved status register
    tst     r0, #0x20              @; check if call was in THUMB mode
    ldrneh  r0, [lr,#-2]           @; yes: load opcode half-word and
    bicne   r0, r0, #0xff00        @; yes: extract THUMB comment
    ldreq   r0, [lr,#-4]           @; no: load opcode word and
    biceq   r0, r0, #0xff000000    @; no: extract ARM comment
                                   @; now r0 has comment field
    ldr     lr,=swi_hdler          @; >= 16: pointer to standard SWI
    ldr     r1,[lr]                @; handler
    mov     lr,pc                  @; >= 16: set link register
    bx      r1                     @; >= 16: jump to standard SWI
                                   @; handler
    ldmfd   sp!, {r0-r1,pc}^

    .ltorg

PREFETCH_HLDR:
    stmfd    sp!, {r0,lr}           @; see UNDEF_HLDR for commentary
                                    @; as this only differs in return mechanism
    ldr      lr,=prefetch_hdler
    ldr      r0,[lr]
    mov      lr,pc
    bx       r0
    ldmfd    sp!, {r0,lr}
    subs     pc,lr,#4

ABORT_HLDR:
    stmfd    sp!, {r0-r2,lr}        @; see UNDEF_HLDR for commentary
                                    @; as this only differs in return mechanism
    ldr      lr,=abort_hdler
    ldr      r0,[lr]
    mov      lr,pc
    bx       r0
    mrc      p15,0,r0,c5,c0,0
    ldr      r1,=0x40f
    and      r0,r0,r1
    ldr      r2,=0x406
    cmp      r0,r2
    bne      NOT_IMPRECISE_ABORT
    ldmfd    sp!, {r0-r2,lr}
    subs     pc,lr,#8
NOT_IMPRECISE_ABORT :
    ldmfd    sp!, {r0-r2,lr}
    subs     pc,lr,#4

IRQ_HLDR:
  stmfd   sp!, {r0-r12,lr}

  ldr  r0,= TZIC_BASE_ADDR+0xD80 @; HIPND0 interrupt pending register
  ldr  r0,[r0]
  mov r2, #0x0
  cmp r0, #0
  bne FIND_NUMBER

    ldr  r0,= TZIC_BASE_ADDR+0xD84 @; HIPND1 interrupt pending register
  ldr  r0,[r0]
  mov r2, #32
  cmp r0, #0
  bne FIND_NUMBER

  ldr  r0,=  TZIC_BASE_ADDR+0xD88 @; HIPND2 interrupt pending register
  ldr  r0,[r0]
  mov r2, #64
  cmp r0, #0
  bne FIND_NUMBER

  ldr  r0,=  TZIC_BASE_ADDR+0xD8C @; HIPND3 interrupt pending register
  ldr  r0,[r0]
  mov r2, #96
  cmp r0, #0
  bne FIND_NUMBER

FIND_NUMBER:
  mov r0, r0, lsr #1
  cmp r0, #0
  beq FOUND_NUMBER
  add r2, r2, #0x1
  b FIND_NUMBER

FOUND_NUMBER:
  mov r2, r2, lsl #2
  mov r0, r2

  ldr  lr,=INTERRUPT_0
  ldr  r0,[lr,r0]
  mov     lr,pc
  bx      r0
    mrs  r0, cpsr
    bic  r1, r0, #0x100
    msr  cpsr_cxsf, r1
    ldmfd   sp!, {r0-r12,lr}
  subs    pc,lr,#4

FIQ_HLDR:
  stmfd   sp!, {r0-r12,lr}

  ldr  r0,= TZIC_BASE_ADDR+0xD80 @; HIPND0 interrupt pending register
  ldr  r0,[r0]
  mov r2, #0x0
  cmp r0, #0
  bne FIQ_FIND_NUMBER

    ldr  r0,= TZIC_BASE_ADDR+0xD84 @; HIPND1 interrupt pending register
  ldr  r0,[r0]
  mov r2, #32
  cmp r0, #0
  bne FIQ_FIND_NUMBER

  ldr  r0,= TZIC_BASE_ADDR+0xD88 @; HIPND2 interrupt pending register
  ldr  r0,[r0]
  mov r2, #64
  cmp r0, #0
  bne FIQ_FIND_NUMBER

  ldr  r0,= TZIC_BASE_ADDR+0xD8C @; HIPND3 interrupt pending register
  ldr  r0,[r0]
  mov r2, #96
  cmp r0, #0
  bne FIQ_FIND_NUMBER

FIQ_FIND_NUMBER:
  mov r0, r0, lsr #1
  cmp r0, #0
  beq FIQ_FOUND_NUMBER
  add r2, r2, #0x1
  b FIQ_FIND_NUMBER

FIQ_FOUND_NUMBER:
  mov r2, r2, lsl #2
  mov r0, r2

  ldr  lr,=FIQ_INTERRUPT_0
  ldr  r0,[lr,r0]
  mov     lr,pc
  bx      r0
  mrs  r0, cpsr
  bic  r1, r0, #0x100
  msr  cpsr_cxsf, r1
  ldmfd   sp!, {r0-r12,lr}
  subs    pc,lr,#4

@;MODIFIED 26-May(IDC)
.align 5
vects1_start:

      nop      @; offset 0x00
      nop      @; offset 0x04
      ldr     pc, =SMI_HLDR  @; offset 0x08
      nop      @; offset 0x0c
      nop      @; offset 0x10
      nop      @; offset 0x14
      nop      @; offset 0x18
      ldr     pc, =FIQ_HLDR  @; offset 0x1c
      nop      @; offset 0x20
      nop      @; offset 0x24
      nop      @; offset 0x28
      nop      @; offset 0x2c
      nop      @; offset 0x30
      nop      @; offset 0x34
      nop      @; offset 0x38
      nop      @; offset 0x3c
      nop      @; offset 0x40
      nop      @; offset 0x44
      nop      @; offset 0x48
      nop      @; offset 0x4c
      nop      @; offset 0x50
      nop      @; offset 0x54
      nop      @; offset 0x58
      nop      @; offset 0x5c
      nop      @; offset 0x60
      nop      @; offset 0x64
      nop      @; offset 0x68
      nop      @; offset 0x6c
      nop      @; offset 0x70
      nop      @; offset 0x74
      nop      @; offset 0x78
      nop      @; offset 0x7c
      nop      @; offset 0x80
      nop      @; offset 0x84
      nop      @; offset 0x88
      ldr     pc, =SMI_HLDR  @; offset 0x8c

@;MODIFIED 11-May(IDC)

SMI_HLDR:
    stmfd   sp!, {r0-r1,lr}        @; push register onto SMI stack
    ldr     r1,=smi_hdler          @; >= 16: pointer to standard SMI
    ldr     r0,[r1]                @; handler
    mov     lr,pc                  @; >= 16: set link register
    bx      r0                     @; >= 16: jump to standard SMI
                                   @; handler
    ldmfd   sp!, {r0-r1,pc}^

  @;Following is Exception Table
undef_hdler:
  .long  UNDEF_HLDR_EXCEPT
swi_hdler:
  .long  SWI_HLDR_EXCEPT
prefetch_hdler:
  .long  PREFETCH_HLDR_EXCEPT
abort_hdler:
  .long  ABORT_HLDR_EXCEPT
irq_hdler:
  .long  IRQ_HLDR_EXCEPT
fiq_hdler:
  .long  FIQ_HLDR_EXCEPT
smi_hdler:
  .long   SMI_HLDR_EXCEPT

CRT0_END:
  .ltorg    @; literal dump

3. 链接脚本


MEMORY
{
   rom  :   org = 0x00000000, len = 0x00008000
   ram  :   org = 0xf8000000, len = 0x00020000 
}

/*********************************************************
 ** Define memory regions for secure ROM and BOOT
 *********************************************************/
__SEC_ROM_START  = 0x00000000;
__NORM_ROM_START = 0x00000000;

SECTIONS
{
    .rom        : { vectors.o   (.vectors);     } > rom
    .rom        : { crt0.o(.start)  *(.text);   } > rom
    .rom        : { * (.text);  *(.rodata);     } > rom

    .ram        : { *(.glue_7)  *(.glue_7t) ;   } > ram
    .data       : { *(.data) ;          } > ram
    .bss        : { *(.bss)     *(.sbss) ;  } > ram
    .stack      : { . += 0x1000;        } > ram
    .mmu        : { *(.mmu) ;           } > ram
    .vfp11_veneer   : { *(.vfp11_veneer) ;  } > ram
}

/* ------------------------------------------------------------------------- */
/* Definitions of identifiers used by sbrk.c, init.c, and the different      */
/* crt0.s files. Their purpose is to control initialization and memory       */
/* allocation.                                                               */
/*                                                                           */
/* __HEAP_START : Start of memory used by malloc() etc.                      */
/* __HEAP_END   : End of heap memory                                         */
/* __SP_INIT    : Initial address of stack pointer                           */
/* __SP_END     : Only used when stack probing                               */
/* __DATA_ROM   : Address of initialized data in ROM                         */
/* __DATA_RAM   : Address of initialized data in RAM                         */
/* __DATA_END   : End of allocated initialized data                          */
/* __BSS_START  : Start of uninitialized data                                */
/* __BSS_END    : End of data to be cleared                                  */
/* ------------------------------------------------------------------------- */

__HEAP_START    = ADDR(.bss)+SIZEOF(.bss);  
__SP_UNDEF      = ADDR(.stack)+SIZEOF(.stack);
__SP_ABORT      = __SP_UNDEF - 0x0200;
__SP_SVC        = __SP_UNDEF - 0x0400;
__SP_IRQ        = __SP_UNDEF - 0x0600;
__SP_FIQ        = __SP_UNDEF - 0x0800;
__SP_SYSTEM     = __SP_UNDEF - 0x0a00;
__SP_MON        = __SP_UNDEF - 0x0c00;
__HEAP_END      = __SP_UNDEF - 0x8000;
__SP_END        = __HEAP_END; 
__DATA_ROM      = ADDR(.data); 
__DATA_RAM      = ADDR(.data); 
__DATA_END      = ADDR(.data)+SIZEOF(.data);
__BSS_START     = ADDR(.bss);
__BSS_END       = ADDR(.bss)+SIZEOF(.bss);

/* ------------------------------------------------------------------------- */
/* Some targets use an extra underscore in front of identifiers              */
/* ------------------------------------------------------------------------- */
___HEAP_START   = __HEAP_START;
___HEAP_END     = __HEAP_END;
___SP_INIT      = __SP_SYSTEM;
___SP_END       = __SP_END;
___DATA_ROM     = __DATA_ROM;
___DATA_RAM     = __DATA_RAM;
___DATA_END     = __DATA_END;
___BSS_START    = __BSS_START;
___BSS_END      = __BSS_END;

参考文献

  1. ARM汇编--汇编中符号和变量
  2. ARM汇编.global和.extern
  3. ARM中C和汇编混合编程及示例
  4. 函数指针和指针函数用法和区别
  5. 《ARM体系与结构编程》
  6. ARM嵌入式系统开发软件设计与优化

本当の声を響かせてよ