關於44b0的中斷調用的問題

關於44b0的中斷調用的問題:

我在網上下了一個源碼,在閱讀的過程中,我的理解來說。希望各位指教下,具體是這樣的:

下面的代碼因爲44b0中的各個中斷類型相似的,所以只是以timer爲例。

在init.s中有這樣的代碼:
首先是一個宏的定義:
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 doest 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
然後有一個vector_branch
 ......
entry
 ......
VECTOR_BRANCH
 ......
 ldr pc,=HandlerTIMER1
 ......
IRQ_Handler
 IMPORT ISR_IrqHandler
 STMFD sp!, {r0-r12, lr}
 BL ISR_IrqHandler
 LDMFD sp!, {r0-r12, lr}
 SUBS pc, lr, #4

 EXPORT IRQ_Handler
 ......
HandlerTIMER1 HANDLER HandleTIMER1
 ......
 ;Setup IRQ handler
     ldr     r0,=HandleIRQ ;This routine is needed
     ldr     r1,=IRQ_Handler ;=IsrIRQ,if there isn't 'subs pc,lr,#4' at 0x18,

0x1c
     str     r1,[r0]

然後,在另外的文件isr_address.s中有下面的語句:
 
 AREA    ISR_STARTADDRESS, DATA, NOINIT
 ......
 EXPORT HandleTIMER1
 ......
 HandleTIMER1 SPACE 4
 ......
 END

另外,在scat_ram.scf中對存儲空間的分配有:
RAM_LOAD 0x00008000
{
    RAM_EXEC 0x00008000
    {
        init.o (init, +First)
        * (+RO)
    }

    RAM 0x0x00100000
    {
        * (+RW,+ZI)
    }

    HEAP +0 UNINIT
    {
        heap.o (+ZI)
    }

    STACKS 0x0020000 UNINIT
    {
        stack.o (+ZI)
    }

    ISR_STARTADDRESS 0x0020000
    {
     isr_address.o (+ZI)
    }

}
在uHALr_InterruptRequestInit()中,有定義下面的東西
void uHALr_InterruptRequestInit()
{
 pISR_UNDEF= (unsigned) DebugUNDEF;
 pISR_SWI= (unsigned) DebugSWI;
 ......
 SetISR_Interrupt(INT_TIMER1_OFFSET,OSTimeTick,NULL);
 ......
 pISR_ADC= (unsigned) BreakPoint;
 pISR_RTC= (unsigned) BreakPoint;
}
然後,在文件isr.c和isr.h中定義下面的函數和數據結構。
void (*InterruptHandlers[MAXHNDLRS])(void)={NULL,};
有函數
void SetISR_Interrupt(int vector, void (*handler)(), int Exint)
{
 ......
 InterruptHandlers[vector] = handler;
 ......
}

在說的理解之前,要謹記44b0提供了兩種向量和非向量的中斷mode。
下面是我的理解:
(1)在向量中斷時採取的操作
從scat_ram.scf和isr_address.s中,可以得到從0x0020000處開始的位置,爲每一箇中斷留出了4個字節

的空間,其中包括timer1.這些空間應該是用來存儲isr的地址(指針)的。

繼續,從scat_ram.scf也可以得到,從0x00008000開始存放init.s的數據。
將HandlerTIMER1 HANDLER HandleTIMER1的宏展開,得到

HandlerTIMER1
    sub     sp,sp,#4    
    stmfd   sp!,{r0}   
    ldr     r0,=HandleTIMER1
    ldr     r0,[r0]    
    str     r0,[sp,#4]    
    ldmfd   sp!,{r0,pc}    
這裏結合VECTOR_BRACH中的代碼
ldr pc,=HandlerTIMER1
來看,假設現在timer1中斷到來,那麼執行該ldr命令,pc值指向sub處開始執行。ldr    

r0,=HandleTIMER1會將isr_address.s中export的HandleTIMER1加載到r0中,這裏的r0中所放的實際上也

是一個地址,指向相應isr指針的指針,執行ldr r0,[r0]後,r0中才是指向isr的指針(地址),通過

堆棧的巧妙操作,pc指向了isr,開始執行相應的isr。這個isr怎樣是怎樣和相應的Handle對應的呢?在

函數uHALr_InterruptRequestInit()中,有pISR_UNDEF= (unsigned) DebugUNDEF等,這些的意思是在

pISR_UNDEF所代表的地址處放置指向DebugUNDEF的指針(地址)。
(2)非向量中斷下的操作

回到init.s中,有語句
;Setup IRQ handler
     ldr     r0,=HandleIRQ ;This routine is needed
     ldr     r1,=IRQ_Handler ;=IsrIRQ,if there isn't 'subs pc,lr,#4' at 0x18,

0x1c
     str     r1,[r0]
這裏要注意了,HandleIRQ也是isr_address.s中的那個,只是這裏將IRQ_Handler的地址放到HandleIRQ預

留的空間中。
同樣,如果在這種mode下,有一個irq中斷到來,那麼首先系統也會像(1)那樣找到HandleIRQ,但是現在

那裏放置的是IRQ_Handle的地址,所以轉向IRQ_Handle,繼而轉向ISR_IrqHandler。在ISR_IrqHandler中

,利用I_ISPC寄存器找到中斷源,然後調用相應源的處理函數。
借用linux的概念,這個執行的isr應該在系統初始化的時候被註冊。這個任務應該是由函數
SetISR_Interrupt完成的,在SetISR_Interrupt中,調用了(*InterruptHandlers[MAXHNDLRS])(void),

有InterruptHandlers[vector] = handler;這個vector明顯是44b0定義的若干irq中斷的相對偏移。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章