中断服务程序小结

                    ---------------by nasiry 
                                     转载请说明出处,并通知我 

MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel
 sub sp,sp,#4 ;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,#4]      ;store the contents(ISR) of HandleXXX to stack
 ldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)
 MEND


        b ResetHandler     ;0x0
 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

 LTORG
HandlerFIQ      HANDLER HandleFIQ
HandlerIRQ      HANDLER HandleIRQ
HandlerUndef    HANDLER HandleUndef
HandlerSWI      HANDLER HandleSWI
HandlerDabort   HANDLER HandleDabort
HandlerPabort   HANDLER HandlePabort

 

IsrIRQ
 sub sp,sp,#4       ;reserved for PC
 stmfd sp!,{r8-r9}

 ldr r9,=INTOFFSET
 ldr r9,[r9]
 ldr r8,=HandleEINT0
 add r8,r8,r9,lsl #2
 ldr r8,[r8]
 str r8,[sp,#8]
 ldmfd sp!,{r8-r9,pc}

   ; Setup IRQ handler
 ldr r0,=HandleIRQ       ;This routine is needed
 ldr r1,=IsrIRQ   ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
 str r1,[r0]
与中断相关的内容展开来看:

0x1c: b HandlerIRQ

HandlerIRQ:
  sub sp,sp,#4 ;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 HandleXXX to r0  //注意是HandleIRQ不是HandlerIRQ
 ldr     r0,[r0]   ;load the contents(service routine start address) of HandleXXX
 str     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stack
 ldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)

IsrIRQ
 sub sp,sp,#4       ;reserved for PC
 stmfd sp!,{r8-r9}

 ldr r9,=INTOFFSET
 ldr r9,[r9]
 ldr r8,=HandleEINT0
 add r8,r8,r9,lsl #2
 ldr r8,[r8]
 str r8,[sp,#8]
 ldmfd sp!,{r8-r9,pc}

   ; Setup IRQ handler
 ldr r0,=HandleIRQ       ;This routine is needed
 ldr r1,=IsrIRQ   ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
 str r1,[r0]
看这个具体的例子说明了中断的安装过程其实也就是设置变量HandleIRQ的过程,这样一来有很多好处,使得原本静态安装的中断服务程序具备了动态特性。也同时约束了中断程序所要求的一些特性:1.中断使用前必须初始化。2.初始化的动作必须在使用前完成 3.中断服务程序的初始化仅仅需要挂接相应的函数指针就可以完成。


 

针对smdk2440的eboot该如何添加中断代码?
smdk2440的eboot工作在所谓的catfish模式:这个eboot以在RAM中运行为特点,也就说不具备xip的特性,由于我们使用的eboot是从0x0启动的,也就是说我们需要搬运相应的中断向量到影射后的0x0区域,也就是0x30000000区域,代码如下
BringUpWinCE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Modify for ROM Bootloader NASIRY 2004.6.28
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MoveLoaderToRAM
; ands r9, pc, #0xFF000000 ; see if we are in flash or in ram
;  bne %F15   ; go ahead if we are already in ram 
  ldr r2,=0x0
  ldr r3,=0x30038000

  ldr r0, [r2], #4
  str r0, [r3], #4
  cmp r2,#0x60000
  bne %b1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Modify by nasiry for interrupt handle
;; Setup IRQ handler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InitVector
  ldr r2,=0x0
  ldr r3,=0x30000000

  ldr r0, [r2], #4
  str r0, [r3], #4
  cmp r2,#0x1000
  bne %b1
InstallIrqIsr
 ldr r0,=HandleIRQ       ;This routine is needed
 ldr r1,=IsrIRQ   ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
 str r1,[r0]

就是把eboot搬运到ram以后再搬运最前端的1K代码到0x3000 0000,然后将IsrIRQ的地址装入HandleIRQ地址所代表的内存单元。

中断部分的代码如下:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Modify by nasiry for ISR
;;2004.9.20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HandleIRQ     EQU   0x33ffff18
HandleFIQ   EQU  0x33ffff1c

 STARTUPTEXT
 LEAF_ENTRY StartUp
1 b  ResetHandler
 b  %B1  ;handler for Undefined mode
 b  %B1  ;handler for SWI interrupt
 b  %B1  ;handler for PAbort
 b  %B1  ;handler for DAbort
 b  %B1  ;reserved
 ;b  %B1    ;handler for IRQ interrupt
 b   IRQHandler   ;modify by nasiry for interrupt
 ;b  HandlerFIQ      ;handler for FIQ interrupt

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;modify by nasiry for add interrupt route for USB Fucntion
;;2004.9.20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
IRQHandler
 sub sp,sp,#4      ;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 HandleXXX to r0
 ldr     r0,[r0]      ;load the contents(service routine start address) of HandleXXX
 str     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stack
 ldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)
 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

中断的安装就就此完成。
由于C语言不能直接操作CPSR故而使用如下汇编代码构建开启中断的函数。
   MACRO
        RETURN
        bx      lr
        MEND
;-------------------------------------------------------------------------------
; INTERRUPTS_ON - enable interrupts
;-------------------------------------------------------------------------------
        LEAF_ENTRY INTERRUPTS_ON
        mrs     r0, cpsr                        ; (r0) = current status
        bic     r1, r0, #0x80                   ; clear interrupt disable bit
        msr     cpsr, r1                        ; update status register
        RETURN                                  ; return to caller

;-------------------------------------------------------------------------------
; INTERRUPTS_OFF - disable interrupts
;-------------------------------------------------------------------------------
        LEAF_ENTRY INTERRUPTS_OFF
        mrs     r0, cpsr                        ; (r0) = current status
        orr     r1, r0, #0x80                   ; set interrupt disable bit
        msr     cpsr, r1                        ; update status register

        RETURN                                  ; return to caller
该代码完全遵循ATPCS,可以在armcc下直接使用。


 

由于windowsCE编译器会在最前端的0x1000区域保留一个空区域所以上面所修改的中断向量都不会得到执行。如果使用偏移代码/数据副本的办法来填补这个区域的话,又必须保持一份原数据/代码,两份代码/数据之间的空间仅仅有4K所以偏移的办法基本上没有什么实际的用途。

因此上面的代码不能用。


另外就只有参考ATPCS动态通过C/Cpp装载中断向量的办法,通过 MMU构建一个位于ram中的高向量/低向量,然后通过构造的办法来实现中断向量。

所以这样一来,ISR就没有必要放在fw.s中单独拿出来就行了。

然后通过下列语句装载

VectorIRQ =(unsigned)(0xEA000000)+(((unsigned)IRQHandler - (0x8c000000 + 0x18 + 0x8) )>>2);

posted @ 2004-09-20 14:51  nasiry  阅读(8101)  评论(1编辑  收藏  举报