📄 shexcept.src
字号:
; 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 + -