⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shexcept.src

📁 WinCE5.0部分核心源码
💻 SRC
📖 第 1 页 / 共 5 页
字号:
;       not be serviced until the next interrupt.
;       (r0) and (r2) are free to use
;
        ; are we in idle?
        mov.l   #fInIdle, r0            ; (r0) = &fInIdle
        mov.l   @r0, r0                 ; (r0) = fInIdle
        cmp/eq  #0, r0                  ; in idle?
        bt      ieh001                  ; normal processing if not

        ;
        ; We're in Idle. If SPC is at the "sleep" instruction, increment it by 2
        ;
        stc     SPC, r2                 ; (r2) = interrupt return address
        mov.w   @r2, r0                 ; (r0) = instruction at the address
        cmp/eq  #h'001b, r0             ; is this a "sleep" instruction?
        bf      ieh001                  ; normal processing if not

        ;
        ; We're right at sleep instruction, increment SPC
        ;
        add     #2, r2                  ; increment the return address
        ldc     r2, SPC      
ieh001:

;--------- End work around ------------------------
  .aendi

        ; go to bank 0, interrupt disabled
        mov     #PR_B0_BK, r2
        ldc     r2, SR

        ;
        ; on bank 0, interrupt disabled
        ;   (r1_bank) = ISR to call
        ;   (r3_bank) = ISR prio (from IntrPrio)
        ;

        ; save all volatile registers
        sts     PR,     @-r15
        stc     SPC,    @-r15
        stc     SSR,    @-r15
        sts     macl,   @-r15
        sts     mach,   @-r15
        stc     GBR,    @-r15
        mov.l   r0,     @-r15               ; save registers
        mov.l   r1,     @-r15               ; save registers
        mov.l   r2,     @-r15               ; save registers
        mov.l   r3,     @-r15               ; save registers
        mov.l   r4,     @-r15               ; save registers
        mov.l   r5,     @-r15               ; save registers
        mov.l   r6,     @-r15               ; save registers
        mov.l   r7,     @-r15               ; save registers

        ; reserve space for 4 registers on stack (C calling convention)
        add.l   #-16,   r15

  .aif NKPROF eq h'01
        ;
        ; NOTE : volatile registers are all saved, just call CelogInterrup directly
        ;
        mov     #_CeLogInterrupt, r2
        mov     #h'80000000, r4         ; r4 = mark as ISR entry
        jsr     @r2                     ; CeLogInterrupt (dwLogValue)
        nop
  .aendi

        ; retrieve r1_bank and r3_bank for ISR information
        stc     r1_bank, r1
        stc     r3_bank, r3

        mov     #PR_B0_IE, r2

        shll2   r3
        shll2   r3
        or      r3, r2

        ldc     r2, SR                  ; bank 0, lower prio interrupts masked

        jsr     @r1                     ; invoke interrupt service routine
        nop

        ; call the ISR hook (pfnOEMIntrOccurs is set to a faked function if not changed by OEM)
        mov     #_pfnOEMIntrOccurs, r3
        mov.l   @r3, r3                 ; (r3) = pfnOEMIntrOccurs
        jsr     @r3                     ; call the hook
        mov     r0, r4                  ; (delay slot) (r4) = SYSINTR returned == argument to pfnOEMIntrOccurs

        ; disable interrup, still in bank 0
        mov     #PR_B0_BK, r2
        ldc     r2, SR

        ; save return value in r3_bank
        ldc     r0, r3_bank


  .aif NKPROF eq h'01
        ;
        ; NOTE : volatile registers are all saved, just call CelogInterrupt directly
        ;
        mov     #_KData+cNest, r1
        mov.b   @r1, r1                 ; r1 = nest level (0, -1, -2, etc)
        neg     r1, r1                  ; r1 = nest level (0,  1,  2, etc)
        shll16  r1                      ; r1 <<= 16

        mov     #_CeLogInterrupt, r2
        jsr     @r2                     ; CeLogInterrupt (dwLogValue)
        or      r1, r4                  ; (delay slot) r4 = (-cNest << 16) | SYSINTR_val
  .aendi

        ; disable interrup, go to in bank 1
        mov     #PR_B1_BK, r2
        ldc     r2, SR

        ; restore all user registers
        add.l   #16,   r15

        ldc     @r15+,  r7_user
        ldc     @r15+,  r6_user
        ldc     @r15+,  r5_user
        ldc     @r15+,  r4_user
        ldc     @r15+,  r3_user
        ldc     @r15+,  r2_user
        ldc     @r15+,  r1_user
        ldc     @r15+,  r0_user
        ldc     @r15+,  GBR
        lds     @r15+,  mach
        lds     @r15+,  macl
        ldc     @r15+,  SSR
        ldc     @r15+,  SPC
        lds     @r15+,  PR

        ; (r3) = sysintr value
        mov     #_KData+bResched, r2
        mov.b   @(1,r2), r0
        add     #1, r0
        mov.b   r0, @(1,r2)
        cmp/eq  #1, r0
        bf      ieh02
        mov     @r15, r15
ieh02:
        mov     r3, r0

        mov     #SH3CTL_BASE, r7
        cmp/eq  #SYSINTR_NOP, r0
        bt      ieh48                   ; no additional processing needed
        cmp/eq  #SYSINTR_BREAK, r0
        bt      ieh60                   ; external break button pushed
        add     #-SYSINTR_DEVICES, r0
        cmp/pz  r0
        bf      ieh40

        ; valid SYSINTR
        mov     #32, r3                         ; r3 = 32
        mov     #_KData+PendEvents1, r1         ; r1 = &PendEvents1
        cmp/hs  r3, r0                          ; 'T' = (r0 >= 32)
        bt/s    ieh45                           ; go handle ISR# >= 32 if true
        mov     #1, r3                          ; (delay slot), (r3) =1
        
        mov.l   @r1, r2                         ; r2 = PendEvents1
        shld    r0, r3                          ; r3 = bit signifying current interrupt
        or      r3, r2                          ; r2 = all interrupts so far (bitmask)
        mov.l   r2, @r1                         ; store PendEvents1
ieh40:  mov     #_KData+bResched, r1
        mov.b   @(1,r1), r0                     ; cNest
        mov     #1, r2
        cmp/eq  #1, r0
        bf      ieh49
        bra     InterruptResched                ; jump to general exception handler
        mov.w   r2, @r1

        .nopool

ieh45:  add     #-32, r0                        ; ISR# -= 32
        mov.l   @(4, r1), r2                    ; r2 = PendEvents2
        shld    r0, r3                          ; r3 = bit signifying current interrupt
        or      r3, r2                          ; r2 = all interrupts so far (bitmask)
        bra     ieh40
        mov.l   r2, @(4, r1)                    ; (delay slot) store PendEvents2
        
        .nopool

; Check for bResched set by nested interrupt
ieh48:  mov     #_KData+bResched, r1
        mov     #0x0101, r2
        mov.w   @r1, r0         ; r0 = cNest << 8 + bResched
        cmp/eq  r0, r2          ; if((cNest ==1)&&(bResched ==1))
        bf      ieh50           ;    do rescheduling
        mov     #1, r2
        bra     InterruptResched
        mov.w   r2, @r1
        .nopool

; Check for interlocked API in progress. The interlocked apis are all located
; at the end of the user kernel page. If the PC is less than INTERLOCKED_END and
; greater than INTERLOCKED_START, then the PC is adjusted to restart the routine.
;
;       in register bank 1.

ieh49:  mov.b   r2, @r1                 ; set bResched flag
ieh50:  mov     #INTERLOCKED_END, r1    ; (r1) = end of interlocked api block
        stc     SPC, r0                 ; (r0) = interrupted PC
        cmp/hi  r0, r1                  ; 'T' = r1 > r0
        bt      ieh70                   ; PC < INTERLOCKED_END
ieh55:  rte
        nop
        .nopool

; External break button. Trap into the debugger.

ieh60:  mov     #16, r0
        mov     r0, @(TRPA,r7)          ; set trapa code to 16 (trapa #4)
        mov     #h'160, r0              ; (r0) = trapa expevt value
        bra     TLBMissError
        mov     r0, @(EXPEVT,r7)        ; set event code
        .nopool

; PC is below the end of the INTERLOCKED APIs, check lower bound and adjust the PC
; to restart the routine.
;
;       (r0) = interrupted PC

ieh70:  mov     #INTERLOCKED_START, r1  ; (r1) = start of interlocked api block
        tst     #1,r0
        bf      ieh55                   ; PC is odd, don't change it
        cmp/hi  r0, r1                  ; 'T' = r1 > r0
        bt      ieh55                   ; out of range, no backup
        mov     #-8, r1
        and     r1, r0                  ; (old PC) &= ~7
        ldc     r0, SPC                 ; update PC

        .aif INTRLOCK_LEDS eq 1
        mov     #h'AA001010, r2         ; (r2) = LED address
        mov.l   @r2, r0
        add     #1,r0
        mov.l   r0, @r2                 ; put it in lights
        .aendi
        rte
        nop

        .endf

_ExceptionBaseAddress   .data.l ExceptionBase
_ExceptionEndAddress    .data.l xKCall          ; The value must be right after all the 
                                                ; exception handlers. The value must be
                                                ; updated if we move xKCall for any reason.

        .global _ExceptionBaseAddress
        .global _ExceptionEndAddress

        NESTED_ENTRY xKCall
;++
; The following code is never executed. Its purpose is to support unwinding
; through the call to the exception dispatcher.
;--
        mov.l   r15, @(0,r15)           ; caller's stack pointer
        sts.l   PR, @-r15               ; return address
        add     #-16, r15               ; argument save area
        PROLOG_END

        ALTERNATE_ENTRY _KCall
; KCall - call kernel function
;
;       KCall invokes a kernel function in a non-preemtable state by incrementing
; the kernel nest level and switching onto a kernel stack.
;
;       While in a preemtible state, the thread's register save area is
; volatile. On the way in, nothing can be saved into the thread
; structure until KNest is set and on the way out anything needed from the
; thread structure must be loaded before restoring KNest.
;
;       The sequence of stack switching must be handled carefully because
; whenever KNest != 1, the general exception handler assumes that the kernel
; stack is current and will not switch stacks. On the way in, we must switch
; to the kernel stack before setting KNest but not use it until after KNest
; is set.  On the way out, we must reset KNest before restoring the thread's
; stack pointer.
;
;       Entry   (r4) = ptr to function to call
;               (r5) = first function arg
;               (r6) = second fucntion arg
;               (r7) = third function arg
;       Exit    (r0) = function return value
;       Uses    r0-r7

        mov     #_KData+bResched, r1
        mov     r4, r3                  ; (r3) = ptr to function to call
        mov.b   @(1,r1), r0             ; (r0) = kernel nest level
        mov     r5, r4                  ; ripple args down
        mov     r6, r5
        dt      r0
        bf/s    kc50                    ; already in non-preemtible state
        mov     r7, r6

; Entering non-preemptible state. We must switch onto the kernel stack
; before setting KNest in case an interrupt occurs during the switch.

        mov     r15, r2                 ; (r2) = original stack pointer
        mov     #_KStack, r15           ; switch to kernel stack
        mov.b   r0, @(1,r1)             ; enter non-preemtible state (KNest = 0)
        sts     PR, r0
        mov.l   r2, @(20,r15)           ; save thread's stack pointer
        jsr     @r3                     ; invoke non-preemtible function
        mov.l   r0, @(16,r15)           ; save return address

; Function complete. Return to preemtible state then check if a reschedule
; is needed.

        mov     #_KData+bResched, r1
        mov     r0, r3                  ; (r3) = function return value
        mov.l   @(16,r15), r2           ; (r2) = return address
        mov.l   @(20,r15), r5           ; (r5) = original stack pointer
        mov     #PR_B0_IM, r7           ; (r7) = new status: bank0, priv, ints masked
        stc     SR, r6                  ; (r6) = old status
        ldc     r7, SR                  ; mask all interrtupts

        mov.b   @r1, r0                 ; (r0) = reschedule flag
        lds     r2, pr
        cmp/eq  #1, r0
        bt      kc20                    ; reschedule required.

        mov     @(dwKCRes-bResched,r1), r0
        cmp/eq  #1, r0
        bt      kc20

        mov     #1, r0
        mov.b   r0, @(1,r1)             ; leave non-preemtible state
        mov     r3, r0                  ; (r0) = function return value
        ldc     r6, SR                  ; restore interrupt mask state
        rts
        mov     r5, r15                 ; restore stack pointer
        .nopool


; ReschedFlag set, so must run the scheduler to find which thread
; to dispatch next.
;
;       (r1) = ptr to bResched in KPage
;       (r2) = return address
;       (r3) = KCall return value
;       (r5) = original stack pointer
;       (r6) = old status register value

kc20:   ldc     r6, SR                  ; restore interrupt mask state
        mov.l   @(pCurThd-bResched, r1), r4     ; (r4) = ptr to current THREAD
        mov     r4, r1
        add     #THREAD_CONTEXT_OFFSET, r1      ; (r1) = ptr to thread's register context
        mov.l   r3, @(CtxR0, r1)        ; save return value
        add     #CtxR8, r1              ; (r1) = ptr to thread's R8
        mov     #PR_B0_IE, r3           ; (r3) = kernel mode PSR
        mov.l   r2, @(CtxFir-CtxR8, r1) ; thread resumes at the return address
        mov.l   r3, @(CtxPsr-CtxR8, r1) ;   & in kernel mode.
        mov.l   r14, @(CtxR14-CtxR8, r1); save thread's R14
        mov.l   r5, @(CtxR15-CtxR8, r1) ; save thread's stack pointer
        bra     SaveAndResched
        mov     r4, r14                 ; (r14) = ptr to current THREAD

kc25:   bra     resched
        mov     #0, r14                 ; no current thread

; Nested KCall. Just invoke the function directly.
;

⌨️ 快捷键说明

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