iar_reentrant_irq.s

来自「最新版IAR FOR ARM(EWARM)5.11中的代码例子」· S 代码 · 共 210 行

S
210
字号
;********************************************************************************
;*                                                                              *
;*    Copyright (C) 2002 Oki Electric Industry Co., LTD.                        *
;*                                                                              *
;*    System Name    :  ML67405x                                                *
;*    Module Name    :  Reentrant irq handler routine                           *
;*    File   Name    :  reentrant_irq_handler.s                                 *
;*    Revision       :  01.00                                                   *
;*    Date           :  2005/04/20 initial version                              *
;*                                                                              *
;********************************************************************************

        SECTION .text:CODE(2)
        ARM

;   <<< bit field of status registers (CPSR, SPSR) >>>
;   31  30  29  28        7   6   5   4   3   2   1   0
; +---+---+---+---+-----+---+---+---+---+---+---+---+---+
; | N | Z | C | V | - - | I | F | T | M4| M3| M2| M1| M0|
; +---+---+---+---+-----+---+---+---+---+---+---+---+---+
; M0-M4 10010 : IRQ mode
;       11111 : SYSTEM mode
;   T       0 : ARM mode
;           1 : THUMB mode
;   F       0 : FIQ is allowed
;           1 : FIQ is not allowed
;   I       0 : IRQ is allowed
;           1 : IRQ is not allowed
; N,Z,C,V     : condition flags. flags change with the results of ALU.
;
;
;   <<< use situation of registers >>>
;        IRQ         change to       handler   change to  IRQ
;       start         SYS mode     start  end  IRQ mode   end
;       --|--------------|-----------|-----|-----|--------|-->
;      r0 +--+--+--@========@========@--X--+--+--+--+--+--+ r0
;      r1 +--+--+--+--+--+--+--@=====@--X--+--+--+--+--+--+ r1
;      r2 +--+--+--+--+--+--+--+--+--@--X--+--+--+--+--@--+ r2
;      r3 +--+--+--+--+--@--+--+--+--+--X--+--+--@--+--+--+ r3
;      r4 +--@========@=================O=====@=====@--+--+ r4
;      r5 +--+--@=======================O==============@--+ r5
;  r6-r11 +--+--+--+--+--+--+--+--+--+--O--+--+--+--+--+--+ r6-r11
;     r12 +--+--+--+--+--+--+--+--+--+--X--+--+--+--+--+--+ r12
;  lr_IRQ @=============== = = = = = = = = = = = =========@ lr_IRQ
;  lr_USR - - - - - - - - --+--+--@=====O==@--+-- - - - - - lr_USR
;spsr_IRQ @=============== = = = = = = = = = = = =========@ spsr_IRQ
;         |<------------>|<--------------------->|<------>|
;             IRQ mode           SYS mode         IRQ mode
;
; now some standard definitions...
Mode_USR        EQU     0x10
Mode_IRQ        EQU     0x12
Mode_SVC        EQU     0x13
Mode_SYS        EQU     0x1F

I_Bit           EQU     0x80
F_Bit           EQU     0x40

GPCTL           EQU     0xb7000000  ; address of GPCTL
	
IRQSIZE         EQU     64          ; number of IRQ interrupt factor.
IRQ_BASE        EQU     0x78000000  ; base address of registers about IRQ.
FIQ 	          EQU     0x78000008

        IMPORT  IRQ_HANDLER_TABLE
        IMPORT  count_interval

        EXPORT  fiq_handler
        EXPORT  irq_handler

;**********************************************************************
;*  IRQ Handler                                                       *
;*  Function : void IRQ_Handler(void)                                 *
;*      Parameters                                                    *
;*          input  : nothing                                          *
;*          output : nothing                                          *
;**********************************************************************
irq_handler
        SUB     lr, lr, #4; construct the return address

        ;; registers which may be overwritten are saved.(IRQ mode)
        ;; r0-r5 : these are used in this handler.
        ;; lr_IRQ(r14) : if IRQ handler is reentered, this is overwritten.
        ;; registers which may be overwritten are r1-r6,lr_IRQ(r14).
        STMFD   sp!, {r1-r6, lr}

        ;; spsr_IRQ is saved to saved_spsr_irq(r4).
        ;; if IRQ handler is reentered, spsr_IRQ is overwritten.
        MRS     r4, spsr

        ;; check 'I' bit of spsr
        ;; please refer to the following section of FAQ at the ARM website for details.
        ;;   FAQ - ARM Cores
        ;;     4. Interrupt behaviour:
        ;;       - What happens if an interrupt occurs as it is being disabled?
        TST     r4, #I_Bit
        LDMNEFD sp!, {r0-r5, pc}^

        ;; IRQ number is got from IRN register. IRQ number is saved to irn(r6).
        ;; after the value of IRN register is read,
        ;; the bit of CIL register corresponding to interrupt level is set.
        MOV     r5, #IRQ_BASE     ; IRQ_BASE(0x78000000) is saved to irq_base(r5).
        LDR     r6, [r5, #0x14]   ; IRQ number is saved to irn(r6).

        ;; mode is changed into SYS mode. and IRQ is enabled.
        ;; if IRQ is enabled before a CIL register is set,
        ;; this program does not operate appropriately.
        ;; in SYS mode, USR mode registers are used.
        TST     r4, #F_Bit              ; FIQ is available ?
        MOVEQ   r3, #Mode_SVC     ; available
        MOVNE   r3, #Mode_SVC|F_Bit; not abailable
        MSR     cpsr_c, r3        ; change to SYS mode and enable IRQ

        ;; check IRQ number
        ;; if IRQ number is invalid(irn > IRQSIZE),
        ;; this routine doesn't branch to handler corresponding to interrupt's factor.
        CMP     r6, #IRQSIZE
        BCS     LABEL

        ;; USR mode registers which may be overwritten
        ;; and registers which are not saved by callee are saved.
        ;; -- USR mode registers which may be overwritten --
        ;; lr_USR(r14) : this is overwritten.
        ;; -- registers which is not saved by callee --
        ;; r0-r3,r12 : these aren't saved by callee.
        ;;             but there is no influence even if values of r1-r3 change.
        ;; registers which need to be saved are r0, r12 and lr_USR.
        STMFD   sp!, {r0, r12, lr}; R0, R12 and lr_USR(r14) are saved.

        ;; address of IRQ_HANDLER_TABLE is got.
        ;; address of IRQ_HANDLER_TABLE is saved to irq_handler_table(r1).
        LDR     r1, =IRQ_HANDLER_TABLE

        ;; branch to handler corresponding to interrupt's factor
        BL      BRANCH_TO_HANDLER

        LDMFD   sp!, {r0, r12, lr}; R0, R12 and link register is restored.
LABEL

        ;; mode is changed to IRQ mode. and IRQ is disabled.
        ;; if IRQ is still being allowed after CIL register is cleared,
        ;; this program does not operate appropriately.
        TST     r4, #F_Bit; FIQ is available ?
        MOVEQ   r3, #Mode_IRQ|I_Bit; available
        MOVNE   r3, #Mode_IRQ|I_Bit|F_Bit; not abailable
        MSR     cpsr_c, r3        ; change to IRQ mode and disable IRQ
        MSR     spsr_cf, r4       ; spsr_IRQ is restored.

        ;; the most significant '1' bit of CIL register is cleared.
        ;; if arbitrary value is written in CILCL register,
        ;; the most significant '1' bit of CIL register will be cleared.
        STR     r2, [r5, #0x28]; arbitrary value is written to
                                            ; CILCL register.

        ;; saved registers are restored, and control is returned from IRQ.
        LDMFD   sp!, {r1-r6, pc}^
; end of IRQ_Handler

;**********************************************************************
;*  Branch to handler corresponding to interrupt's factor.            *
;*  Handler doesn't return to this function.                          *
;*  Handler directry returns to IRQ_Handler.                          *
;*  Function : void BRANCH_TO_HANDLER(void)                           *
;*      Parameters                                                    *
;*          input  : nothing                                          *
;*          output : nothing(This function doesn't return.)           *
;**********************************************************************
BRANCH_TO_HANDLER
        ;; address of handler and information that handler is ARM or THUMB
        ;; is saved at irq_handler_table + irn*4.
        LDR     r2, [r1, r6, lsl #2];
        BX      r2      ; branch to handler corresponding to
                        ; interrupt's factor
; end of BRANCH_TO_HANDLER

;**********************************************************************
;*  fir_handler                                                       *
;*  the count_interval is taken from FIQ sample                       *
;*  fiq_handler handles FIQ interrupt.                                *
;*  Function : void fiq_handler(void)                                 *
;*      Parameters                                                    *
;*          input  : nothing                                          *
;*          output : nothing                                          *
;**********************************************************************
; --- The FIQ handler starts here
fiq_handler
        SUB     lr, lr, #4              ; construct the return address
        STMFD   sp!, {r0-r3, lr}        ; store low registers to FIQ stack
        LDR     r0,=count_interval      ; load variable address
        LDR     r1,[r0]
        ADD     r1, r1, #10             ; each FIQ casuses increment in count_interval
        STR     r1, [r0]

        LDR     r0, =FIQ		; load FIQ register address
Debounce_FIQ                            ; do not enable FIQ till FIQ source is de-asserted
	      MOV	    r3, #0
Debounce_FIQ100
        LDR     r1, [r0]                ; load contents of FIQ
        MOV     r2, #0x1
        AND     r1, r1, r2              ; zero out the high bits
        CMP     r1, #0x0                ; is FIQ still pending?
        BNE     Debounce_FIQ
	      ADD	    r3, r3,#1
	      CMP	    r3, #0x8000
	      BNE	    Debounce_FIQ100

        LDMFD   sp!, {r0-r3, pc}^  ; restore registers & return from FIQ

        END

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?