nucleus 学习 中断
时间:2019-10-09 08:48:01
手机看文章
扫描二维码
随时随地手机看文章
[导读];************************************************************************
;*
;* FUN
;************************************************************************
;*
;* FUNCTION
;*
;* INT_IRQ
;*
;* DESCRIPTION
;*
;* This routine is the board-specific section for
;* level 1 interrupt handling
;*
;* CALLED BY
;*
;* None
;*
;* CALLS
;*
;* TMT_Timer_Interrupt
;*
;* INPUTS
;*
;* None
;*
;*
;* OUTPUTS
;*
;* None
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* B. Ronquillo 05-10-00 Created initial version 1.0
;*
;************************************************************************
.def _INT_IRQ
_INT_IRQ
; ARM Core Check //确认CPSR,这里应该是确认是否在IRQ模式下
STMDB {r1}
MRS r1, SPSR
TST r1, #IRQ_BIT
LDMIA {r1}
SUBNES pc,lr,#4
STMDB sp!,{r0-r4} ; Save r0-r4 on temporary IRQ stack //sp=sp-4 保存R0~R4到栈
SUB lr,lr,#4 ; Adjust IRQ return address //lr=lr-4就是把lr下移了一格
;********************************
;* Begin Hardware Specific Code * //开始硬件特性代码?
;********************************
LDR r3, INT_CNTRL_BASE_1 ; load Interrupt Control Base //装载中断控制器基地址
LDR r4, [r3,#INT_CNTRL_MIR] ; Get enable register value //获取enable register的值,INT_CNTRL_MIR的值
;******************************
;* End Hardware Specific Code *
;******************************
STMDB sp!,{r4} ; Put the enable register value on the IRQ stack //把r4压入栈,r4是enable register的值
MVN r4,#0 ; Start with 0xFFFFFFFF to allow nesting of interrupts //全部置1
;********************************
;* Begin Hardware Specific Code *
;********************************
LDR r2, [r3,#INT_CNTRL_ITR] ; Read Pending reg //这次读取了INT_CNTRL_ITR的值
;******************************
;* End Hardware Specific Code *
;******************************
LDR r3, IRQ_Priority ; Get the Priority table address //获取IRQ优先级表的地址
IRQ_VECTOR_LOOP
LDR r0, [r3,#0] ; Load first vector to be checked from priority table
MOV r1, #1 ; Build mask
MOV r1, r1, LSL r0 ; Use vector number to set mask to correct bit position //逻辑左移优先级个数,不会溢出吗
TST r1, r2 ; Test if pending bit is set //判断
BNE IRQ_VECTOR_FOUND ; If bit is set, branch to found section... //找到IRQ_VECTOR
BIC r4,r4,r1 ; Clear mask bit to keep higher priority ints active //如果没找到查下一个向量表?
ADD r3, r3, #4 ; Move to next word in the priority table
ADR r0, Priority_End ; Load the end address for the priority table
CMP r0, r3 ; Make sure not at the end of the table (shouldn't happen!) BNE IRQ_VECTOR_LOOP ; Continue to loop if not at the end of the table
; No bits in pending register set, restore registers and exit interrupt servicing //恢复上下文
ADD sp,sp,#4 ; Adjust sp above IRQ enable value
LDMIA sp!,{r0-r4} ; Restore r0-r4
STMDB sp!,{lr} ; Put return address for IRQ on stack
LDMIA sp!,{pc}^ ; return to the point of the exception and restore SPSR
IRQ_VECTOR_FOUND
;********************************
;* Begin Hardware Specific Code *
;********************************
LDR r3, INT_CNTRL_BASE_1 ; load Interrupt Control Base //获取INT_CNTRL_BASE
MVN r2, r1 ; Get the inverse of the interrupt vector //之前r1和r2应该是一样的,取了反
STR r2, [r3,#INT_CNTRL_ITR] ; Write a zero to the interrupt being handled //写一个0到中断处理中
LDR r2, [r3,#INT_CNTRL_MIR] ; Read the Mask reg
ORR r4, r2, r4 ; Turn off lower priority pending bits and currently masked bits
STR r4, [r3,#INT_CNTRL_MIR] ; Disable(Mask) all lower priority interrupts and currently masked interrupts
MOV r1, #1 ; Clear the pending interrupt //清除pending中断位
STR r1, [r3,#INT_CNTRL_CONTROL_REG] ; by writing a 1 to the Control Reg //写入1清除
;******************************
;* End Hardware Specific Code *
;******************************
LDR r3, IRQ_Vectors ; Get IRQ vector table address
MOV r2, r0, LSL #2 ; Multiply vector by 4 to get offset into table
ADD r3, r3, r2 ; Adjust vector table address to correct offset
LDR r2, [r3,#0] ; Load branch address from vector table
MOV PC, r2 ; Jump to correct branch location based on vector table //跳转到中断向量表,这个跳转应该是找到对应的处理程序?
; END: INT_IRQ
中断向量表:
; Define vector table used by INT_IRQ to branch to necessary ISR
INT_IRQ_Vectors:
.word _INT_IRQ_2 ; Vector 0
.word INT_Interrupt_Shell ; Vector 1
.word INT_Interrupt_Shell ; Vector 2
.word INT_Interrupt_Shell ; Vector 3
.word INT_Interrupt_Shell ; Vector 4
.word INT_Interrupt_Shell ; Vector 5
.word INT_Interrupt_Shell ; Vector 6
.word INT_Interrupt_Shell ; Vector 7
.word INT_Interrupt_Shell ; Vector 8
.word INT_Interrupt_Shell ; Vector 9
.word INT_Interrupt_Shell ; Vector 10
.word INT_Interrupt_Shell ; Vector 11
.word INT_Interrupt_Shell ; Vector 12
.word INT_Interrupt_Shell ; Vector 13
.word INT_Interrupt_Shell ; Vector 14
.word INT_Interrupt_Shell ; Vector 15
.word INT_Interrupt_Shell ; Vector 16
.word INT_Interrupt_Shell ; Vector 17
.word INT_Interrupt_Shell ; Vector 18
.word INT_Interrupt_Shell ; Vector 19
.word INT_Interrupt_Shell ; Vector 20
.word INT_Interrupt_Shell ; Vector 21
.word INT_Interrupt_Shell ; Vector 22
.word INT_Interrupt_Shell ; Vector 23
.word INT_Interrupt_Shell ; Vector 24
.word INT_Interrupt_Shell ; Vector 25
.word INT_Interrupt_Shell ; Vector 26
.word INT_Interrupt_Shell ; Vector 27
.word INT_Interrupt_Shell ; Vector 28
.word INT_Interrupt_Shell ; Vector 29
.word INT_Timer_Interrupt ; Vector 30
.word INT_Interrupt_Shell ; Vector 31 。。。。。。。。。。。。。。。 INT_Interruopt_Shell(感觉只是跳转到_TCT_Interrupt_Context_Save):
;************************************************************************
;*
;* FUNCTION
;*
;* INT_Interrupt_Shell
;*
;* DESCRIPTION
;*
;* Handles all interrupts which use NU_Register_LISR.
;*
;*
;* CALLED BY
;*
;* INT_IRQ
;*
;* CALLS
;*
;* TCT_Dispatch_LISR
;* TCT_Interrupt_Context_Restore
;*
;* INPUTS
;*
;* vector (register r0)
;*
;* OUTPUTS
;*
;* None
;************************************************************************
.def INT_Interrupt_Shell
INT_Interrupt_Shell
MOV r4,lr ; Put IRQ return address into r4 //这里r4是PC的值
BL _TCT_Interrupt_Context_Save //什么直接跳转了?
BL _TCC_Dispatch_LISR //怎么两个跳转?LISR?
MRS r1,CPSR ; Pickup current CPSR //清除了中断,关了位
BIC r1,r1,#MODE_MASK ; Clear the mode bits
ORR r1,r1,#(IRQ_MODE_OR_LOCKOUT) ; Set the IRQ mode bits and Lockout interrupts
MSR CPSR,r1 ; Lockout interrupts/change to IRQ mode
;********************************
;* Begin Hardware Specific Code *
;********************************
LDMIA sp!,{r1} ; Get IRQ enable value off IRQ stack //提取栈中的值到sp
LDR r2, INT_CNTRL_BASE_1 ; Get IRQ0 base register address //获取IRQ0基地址
STR r1,[r2,#INT_CNTRL_MIR] ; Re-enable all lower priority interrupts //重新开启低优先级中断
;******************************
;* End Hardware Specific Code *
;******************************
MRS r1,CPSR ; Pickup current CPSR
BIC r1,r1,#MODE_MASK ; Clear the mode bits
ORR r1,r1,#SUP_MODE ; Set the SVC mode bits
MSR CPSR,r1 ; Change to SVC mode //切换成svc模式
B _TCT_Interrupt_Context_Restore 既然跳转到_TCT_Interrupt_Context_Save那就继续学习吧:
;************************************************************************
;*
;* FUNCTION
;*
;* TCT_Interrupt_Context_Save
;*
;* DESCRIPTION
;*
;* This function saves the interrupted thread's context. Nested
;* interrupts are also supported. If a task or HISR thread was
;* interrupted, the stack pointer is switched to the system stack
;* after the context is saved.
;*
;* CALLED BY
;*
;* Application ISRs Assembly language ISRs
;* INT_Interrupt_Shell Interrupt handler shell
;*
;* CALLS
;*
;* None
;*
;* INPUTS
;*
;* vector Interrupt's vector number
;*
;* OUTPUTS
;*
;* None
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* W. Lamie 02-15-1994 Created initial version 1.0
;* D. Lamie 02-15-1994 Verified version 1.0
;* D. Driscoll 01-04-2002 Released version 1.13.3.
;* Updated to handle nested /
;* prioritized IRQs
;************************************************************************
;VOID TCT_Interrupt_Context_Save(INT vector)
;{
.def $TCT_Interrupt_Context_Save
$TCT_Interrupt_Context_Save ; Dual-state interworking veneer
.state16
BX r15
NOP
.state32
B _TCT_Interrupt_Context_Save
.def _TCT_Interrupt_Context_Save
_TCT_Interrupt_Context_Save
; Determine if this is a nested interrupt. //确定是不是嵌套中断
LDR r1,Int_Count ; Pickup address of interrupt count //Int_Count是中断计数
LDR r2,[r1, #0] ; Pickup interrupt counter
ADD r2,r2,#1 ; Add 1 to interrupt counter
STR r2,[r1, #0] ; Store new interrupt counter value //更新中断计数
CMP r2,#1 ; Is it nested?
BEQ TCT_Not_Nested_Save ; No //如果不是嵌套就跳转
; Nested interrupt. Save complete context on the current stack.
TCT_Nested_Save
; 1. Save another register on the exception stack so we have enough to work with //保存另一个寄存器(r5)到异常栈,腾出空间来。r13是sp指针
STMDB r13!,{r5}
; 2. Save the necessary exception registers into r1-r3 //保存必要的异常寄存器到r1-r3
MOV r1,r13 ; Put the exception r13 into r1
MOV r2,r14 ; Move the return address for the caller
; of this function into r2
MRS r3,spsr ; Put the exception spsr into r3
; 3. Adjust the exception stack pointer for future exceptions //调整异常栈指针为之后的异常
ADD r13,r13,#24 ; r13 will point to enable reg value when done
; 4. Switch CPU modes to save context on system stack //转换CPU模式到system stack(之前初始化过的)
MRS r5,CPSR ; Pickup the current CPSR
BIC r5,r5,#MODE_MASK ; Clear the mode bits
ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
MSR CPSR,r5 ; Switch modes (IRQ->SVC)
; 5. Store the SVC r13 into r5 so the r13 can be saved as is. //这里明明是把r5放进r13(sp)
MOV r5,r13
; 6. Save the exception return address on the stack (r15). //保存r4进栈
STMDB r5!,{r4}
; 7. Save r6-r14 on stack //保存r6-r14进栈
STMDB r5!,{r6-r14}
; 8. Switch back to using r13 now that the original r13 has been saved. //又把r13换回来了,回到sp回到原来的位置了 MOV r13,r5
; 9. Get r5 and exception enable registers off of exception stack and //
; save r5 (stored in r4) back to the system stack. //保存r5(存在r4中)到system stack中,好吧之前的mov都理解错了,mov 目的,源
LDMIA r1!,{r4-r5}
STMDB r13!,{r4}
MOV r4,r5 ; Put exception enable value into r4
; 10. Get the rest of the registers off the exception stack and //获取剩下的exception stack到system stack中
; save them onto the system stack.
LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
; 11. Store the exception enable value back on the exception stack.
STMDB r1,{r4}
; 12. Save the SPSR on the system stack (CPSR)
STMDB r13!,{r3}
; 13. Re-enable interrupts //重新开启中断
MRS r1,CPSR
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
MSR CPSR,r1
BX r2 ; Return to calling ISR
; }
; else
; {
TCT_Not_Nested_Save
; Determine if a thread was interrupted. //判断是否进程产生了中断
; if (TCD_Current_Thread) //如果TCD_Current_Thread是空,则在schedule中因为初始化线程是关中断的
; {
LDR r1,Current_Thread ; Pickup current thread ptr address
LDR r1,[r1, #0] ; Pickup the current thread pointer
CMP r1,#0 ; Is it NU_NULL?
BEQ TCT_Idle_Context_Save ; If no, no real save is necessary
; Yes, a thread was interrupted. Save complete context on the
; thread's stack.
; 1. Save another register on the exception stack so we have enough to work with
STMDB r13!,{r5}
; 2. Save the necessary exception registers into r1-r3
MOV r1,r13 ; Put the exception r13 into r1
MOV r2,r14 ; Move the return address for the caller
; of this function into r2
MRS r3,spsr ; Put the exception spsr into r3
; 3. Adjust the exception stack pointer for future exceptions
ADD r13,r13,#24 ; r13 will point to enable reg value when done
; 4. Switch CPU modes to save context on system stack
MRS r5,CPSR ; Pickup the current CPSR
BIC r5,r5,#MODE_MASK ; Clear the mode bits
ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
MSR CPSR,r5 ; Switch modes (IRQ->SVC)
; 5. Store the SVC r13 into r5 so the r13 can be saved as is.
MOV r5,r13
; 6. Save the exception return address on the stack (r15).
STMDB r5!,{r4}
; 7. Save r6-r14 on stack
STMDB r5!,{r6-r14}
; 8. Switch back to using r13 now that the original r13 has been saved.
MOV r13,r5
; 9. Get r5 and exception enable registers off of exception stack and
; save r5 (stored in r4) back to the system stack.
LDMIA r1!,{r4-r5}
STMDB r13!,{r4}
MOV r4,r5 ; Put exception enable value into r4
; 10. Get the rest of the registers off the exception stack and
; save them onto the system stack.
LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
; 11. Store the exception enable value back on the exception stack.
STMDB r1,{r4}
; 12. Save the SPSR on the system stack (CPSR)
STMDB r13!,{r3}
; 13. Save stack type to the task stack (1=interrupt stack)
MOV r1,#1 ; Interrupt stack type
STMDB r13!,{r1}
; Save the thread's stack pointer in the control block.
; REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread
; REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr
LDR r1,Current_Thread ; Pickup current thread ptr address
LDR r3,[r1, #0] ; Pickup current thread pointer
STR r13,[r3, #TC_STACK_POINTER] ; Save stack pointer
; Switch to the system stack.
; REG_Stack_Ptr = TCD_System_Stack
LDR r1,System_Stack ; Pickup address of stack pointer
LDR r3,System_Limit ; Pickup address of stack limit ptr
LDR r13,[r1, #0] ; Switch to system stack
LDR r10,[r3, #0] ; Setup system stack limit
; Re-enable interrupts
MRS r1,CPSR
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
MSR CPSR,r1
; Return to caller ISR.
BX r2 ; Return to caller ISR
; }
TCT_Idle_Context_Save
MOV r2,r14 ; Save r14 in r2
LDR r3,[r13] ; Get exception enable value from stack
ADD r13,r13,#20 ; Adjust exception r13 for future interrupts
STR r3,[r13] ; Put exception enable value back on stack
MRS r1,CPSR ; Pickup current CPSR
BIC r1,r1,#MODE_MASK ; Clear the current mode
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) ; Re-enable interrupts
ORR r1,r1,#SUP_MODE ; Prepare to switch to supervisor
; mode (SVC)
MSR CPSR,r1 ; Switch to supervisor mode (SVC)
BX r2 ; Return to caller ISR
; }
;} NU对于中断上下文的保存具体操作如下: (1)在中断发生后执行的入口函数INT_IRQ()中,将r0-r4保存至irq的栈中 (2)查找到对应的interrupt_shell(),clear中断源,更新全局的中断计数器,然后进行interrupt_contex_save (3)首先利用r1,r2,r3保存irq模式下的sp,lr,spsr,这里sp是用来切换至系统栈后拷贝lr和spsr的,这里保存lr和spsr是目的是task被抢占后,当再次schedule时可以返回task之前的状态。 (4)切换至SVC模式,如果是非嵌套的中断则保存上下文至task stack中,将irq模式下的lr作为顶端PC的返回值入栈,将SVC模式下的r6-r14入栈,将irq模式下的sp保存至r4中入栈,最后将保存在irq_stack中的r0-r4入栈 (5)如果是嵌套中断,中断的嵌套发生在LISR中,在执行LISR时已经切换至system stack,因此嵌套中断要将中断的上下文保存至system stack中,与task stack中interrupt stack相比只是少了栈顶用来标记嵌套的标志(1 not nested) (6)有一个分支判断,就是如果当前线程是空,即TCD_Current_Thread == NULL,表明当前是schedule中,因为初始化线程是关中断的,这样就不为schedule线程建立栈帧,因为schedule不需要保存上下文,在restore中断上下文时直接跳转至schedule。
中断上下文的恢复 全局的中断计数器INT_Count是否为0来判定当前出栈的信息,如果是嵌套则返回LISR中,否则切换至system stack执行schedule
阅读(40) | 评论(0) | 转发(0) | 0
;* FUNCTION
;*
;* INT_IRQ
;*
;* DESCRIPTION
;*
;* This routine is the board-specific section for
;* level 1 interrupt handling
;*
;* CALLED BY
;*
;* None
;*
;* CALLS
;*
;* TMT_Timer_Interrupt
;*
;* INPUTS
;*
;* None
;*
;*
;* OUTPUTS
;*
;* None
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* B. Ronquillo 05-10-00 Created initial version 1.0
;*
;************************************************************************
.def _INT_IRQ
_INT_IRQ
; ARM Core Check //确认CPSR,这里应该是确认是否在IRQ模式下
STMDB {r1}
MRS r1, SPSR
TST r1, #IRQ_BIT
LDMIA {r1}
SUBNES pc,lr,#4
STMDB sp!,{r0-r4} ; Save r0-r4 on temporary IRQ stack //sp=sp-4 保存R0~R4到栈
SUB lr,lr,#4 ; Adjust IRQ return address //lr=lr-4就是把lr下移了一格
;********************************
;* Begin Hardware Specific Code * //开始硬件特性代码?
;********************************
LDR r3, INT_CNTRL_BASE_1 ; load Interrupt Control Base //装载中断控制器基地址
LDR r4, [r3,#INT_CNTRL_MIR] ; Get enable register value //获取enable register的值,INT_CNTRL_MIR的值
;******************************
;* End Hardware Specific Code *
;******************************
STMDB sp!,{r4} ; Put the enable register value on the IRQ stack //把r4压入栈,r4是enable register的值
MVN r4,#0 ; Start with 0xFFFFFFFF to allow nesting of interrupts //全部置1
;********************************
;* Begin Hardware Specific Code *
;********************************
LDR r2, [r3,#INT_CNTRL_ITR] ; Read Pending reg //这次读取了INT_CNTRL_ITR的值
;******************************
;* End Hardware Specific Code *
;******************************
LDR r3, IRQ_Priority ; Get the Priority table address //获取IRQ优先级表的地址
IRQ_VECTOR_LOOP
LDR r0, [r3,#0] ; Load first vector to be checked from priority table
MOV r1, #1 ; Build mask
MOV r1, r1, LSL r0 ; Use vector number to set mask to correct bit position //逻辑左移优先级个数,不会溢出吗
TST r1, r2 ; Test if pending bit is set //判断
BNE IRQ_VECTOR_FOUND ; If bit is set, branch to found section... //找到IRQ_VECTOR
BIC r4,r4,r1 ; Clear mask bit to keep higher priority ints active //如果没找到查下一个向量表?
ADD r3, r3, #4 ; Move to next word in the priority table
ADR r0, Priority_End ; Load the end address for the priority table
CMP r0, r3 ; Make sure not at the end of the table (shouldn't happen!) BNE IRQ_VECTOR_LOOP ; Continue to loop if not at the end of the table
; No bits in pending register set, restore registers and exit interrupt servicing //恢复上下文
ADD sp,sp,#4 ; Adjust sp above IRQ enable value
LDMIA sp!,{r0-r4} ; Restore r0-r4
STMDB sp!,{lr} ; Put return address for IRQ on stack
LDMIA sp!,{pc}^ ; return to the point of the exception and restore SPSR
IRQ_VECTOR_FOUND
;********************************
;* Begin Hardware Specific Code *
;********************************
LDR r3, INT_CNTRL_BASE_1 ; load Interrupt Control Base //获取INT_CNTRL_BASE
MVN r2, r1 ; Get the inverse of the interrupt vector //之前r1和r2应该是一样的,取了反
STR r2, [r3,#INT_CNTRL_ITR] ; Write a zero to the interrupt being handled //写一个0到中断处理中
LDR r2, [r3,#INT_CNTRL_MIR] ; Read the Mask reg
ORR r4, r2, r4 ; Turn off lower priority pending bits and currently masked bits
STR r4, [r3,#INT_CNTRL_MIR] ; Disable(Mask) all lower priority interrupts and currently masked interrupts
MOV r1, #1 ; Clear the pending interrupt //清除pending中断位
STR r1, [r3,#INT_CNTRL_CONTROL_REG] ; by writing a 1 to the Control Reg //写入1清除
;******************************
;* End Hardware Specific Code *
;******************************
LDR r3, IRQ_Vectors ; Get IRQ vector table address
MOV r2, r0, LSL #2 ; Multiply vector by 4 to get offset into table
ADD r3, r3, r2 ; Adjust vector table address to correct offset
LDR r2, [r3,#0] ; Load branch address from vector table
MOV PC, r2 ; Jump to correct branch location based on vector table //跳转到中断向量表,这个跳转应该是找到对应的处理程序?
; END: INT_IRQ
中断向量表:
; Define vector table used by INT_IRQ to branch to necessary ISR
INT_IRQ_Vectors:
.word _INT_IRQ_2 ; Vector 0
.word INT_Interrupt_Shell ; Vector 1
.word INT_Interrupt_Shell ; Vector 2
.word INT_Interrupt_Shell ; Vector 3
.word INT_Interrupt_Shell ; Vector 4
.word INT_Interrupt_Shell ; Vector 5
.word INT_Interrupt_Shell ; Vector 6
.word INT_Interrupt_Shell ; Vector 7
.word INT_Interrupt_Shell ; Vector 8
.word INT_Interrupt_Shell ; Vector 9
.word INT_Interrupt_Shell ; Vector 10
.word INT_Interrupt_Shell ; Vector 11
.word INT_Interrupt_Shell ; Vector 12
.word INT_Interrupt_Shell ; Vector 13
.word INT_Interrupt_Shell ; Vector 14
.word INT_Interrupt_Shell ; Vector 15
.word INT_Interrupt_Shell ; Vector 16
.word INT_Interrupt_Shell ; Vector 17
.word INT_Interrupt_Shell ; Vector 18
.word INT_Interrupt_Shell ; Vector 19
.word INT_Interrupt_Shell ; Vector 20
.word INT_Interrupt_Shell ; Vector 21
.word INT_Interrupt_Shell ; Vector 22
.word INT_Interrupt_Shell ; Vector 23
.word INT_Interrupt_Shell ; Vector 24
.word INT_Interrupt_Shell ; Vector 25
.word INT_Interrupt_Shell ; Vector 26
.word INT_Interrupt_Shell ; Vector 27
.word INT_Interrupt_Shell ; Vector 28
.word INT_Interrupt_Shell ; Vector 29
.word INT_Timer_Interrupt ; Vector 30
.word INT_Interrupt_Shell ; Vector 31 。。。。。。。。。。。。。。。 INT_Interruopt_Shell(感觉只是跳转到_TCT_Interrupt_Context_Save):
;************************************************************************
;*
;* FUNCTION
;*
;* INT_Interrupt_Shell
;*
;* DESCRIPTION
;*
;* Handles all interrupts which use NU_Register_LISR.
;*
;*
;* CALLED BY
;*
;* INT_IRQ
;*
;* CALLS
;*
;* TCT_Dispatch_LISR
;* TCT_Interrupt_Context_Restore
;*
;* INPUTS
;*
;* vector (register r0)
;*
;* OUTPUTS
;*
;* None
;************************************************************************
.def INT_Interrupt_Shell
INT_Interrupt_Shell
MOV r4,lr ; Put IRQ return address into r4 //这里r4是PC的值
BL _TCT_Interrupt_Context_Save //什么直接跳转了?
BL _TCC_Dispatch_LISR //怎么两个跳转?LISR?
MRS r1,CPSR ; Pickup current CPSR //清除了中断,关了位
BIC r1,r1,#MODE_MASK ; Clear the mode bits
ORR r1,r1,#(IRQ_MODE_OR_LOCKOUT) ; Set the IRQ mode bits and Lockout interrupts
MSR CPSR,r1 ; Lockout interrupts/change to IRQ mode
;********************************
;* Begin Hardware Specific Code *
;********************************
LDMIA sp!,{r1} ; Get IRQ enable value off IRQ stack //提取栈中的值到sp
LDR r2, INT_CNTRL_BASE_1 ; Get IRQ0 base register address //获取IRQ0基地址
STR r1,[r2,#INT_CNTRL_MIR] ; Re-enable all lower priority interrupts //重新开启低优先级中断
;******************************
;* End Hardware Specific Code *
;******************************
MRS r1,CPSR ; Pickup current CPSR
BIC r1,r1,#MODE_MASK ; Clear the mode bits
ORR r1,r1,#SUP_MODE ; Set the SVC mode bits
MSR CPSR,r1 ; Change to SVC mode //切换成svc模式
B _TCT_Interrupt_Context_Restore 既然跳转到_TCT_Interrupt_Context_Save那就继续学习吧:
;************************************************************************
;*
;* FUNCTION
;*
;* TCT_Interrupt_Context_Save
;*
;* DESCRIPTION
;*
;* This function saves the interrupted thread's context. Nested
;* interrupts are also supported. If a task or HISR thread was
;* interrupted, the stack pointer is switched to the system stack
;* after the context is saved.
;*
;* CALLED BY
;*
;* Application ISRs Assembly language ISRs
;* INT_Interrupt_Shell Interrupt handler shell
;*
;* CALLS
;*
;* None
;*
;* INPUTS
;*
;* vector Interrupt's vector number
;*
;* OUTPUTS
;*
;* None
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* W. Lamie 02-15-1994 Created initial version 1.0
;* D. Lamie 02-15-1994 Verified version 1.0
;* D. Driscoll 01-04-2002 Released version 1.13.3.
;* Updated to handle nested /
;* prioritized IRQs
;************************************************************************
;VOID TCT_Interrupt_Context_Save(INT vector)
;{
.def $TCT_Interrupt_Context_Save
$TCT_Interrupt_Context_Save ; Dual-state interworking veneer
.state16
BX r15
NOP
.state32
B _TCT_Interrupt_Context_Save
.def _TCT_Interrupt_Context_Save
_TCT_Interrupt_Context_Save
; Determine if this is a nested interrupt. //确定是不是嵌套中断
LDR r1,Int_Count ; Pickup address of interrupt count //Int_Count是中断计数
LDR r2,[r1, #0] ; Pickup interrupt counter
ADD r2,r2,#1 ; Add 1 to interrupt counter
STR r2,[r1, #0] ; Store new interrupt counter value //更新中断计数
CMP r2,#1 ; Is it nested?
BEQ TCT_Not_Nested_Save ; No //如果不是嵌套就跳转
; Nested interrupt. Save complete context on the current stack.
TCT_Nested_Save
; 1. Save another register on the exception stack so we have enough to work with //保存另一个寄存器(r5)到异常栈,腾出空间来。r13是sp指针
STMDB r13!,{r5}
; 2. Save the necessary exception registers into r1-r3 //保存必要的异常寄存器到r1-r3
MOV r1,r13 ; Put the exception r13 into r1
MOV r2,r14 ; Move the return address for the caller
; of this function into r2
MRS r3,spsr ; Put the exception spsr into r3
; 3. Adjust the exception stack pointer for future exceptions //调整异常栈指针为之后的异常
ADD r13,r13,#24 ; r13 will point to enable reg value when done
; 4. Switch CPU modes to save context on system stack //转换CPU模式到system stack(之前初始化过的)
MRS r5,CPSR ; Pickup the current CPSR
BIC r5,r5,#MODE_MASK ; Clear the mode bits
ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
MSR CPSR,r5 ; Switch modes (IRQ->SVC)
; 5. Store the SVC r13 into r5 so the r13 can be saved as is. //这里明明是把r5放进r13(sp)
MOV r5,r13
; 6. Save the exception return address on the stack (r15). //保存r4进栈
STMDB r5!,{r4}
; 7. Save r6-r14 on stack //保存r6-r14进栈
STMDB r5!,{r6-r14}
; 8. Switch back to using r13 now that the original r13 has been saved. //又把r13换回来了,回到sp回到原来的位置了 MOV r13,r5
; 9. Get r5 and exception enable registers off of exception stack and //
; save r5 (stored in r4) back to the system stack. //保存r5(存在r4中)到system stack中,好吧之前的mov都理解错了,mov 目的,源
LDMIA r1!,{r4-r5}
STMDB r13!,{r4}
MOV r4,r5 ; Put exception enable value into r4
; 10. Get the rest of the registers off the exception stack and //获取剩下的exception stack到system stack中
; save them onto the system stack.
LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
; 11. Store the exception enable value back on the exception stack.
STMDB r1,{r4}
; 12. Save the SPSR on the system stack (CPSR)
STMDB r13!,{r3}
; 13. Re-enable interrupts //重新开启中断
MRS r1,CPSR
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
MSR CPSR,r1
BX r2 ; Return to calling ISR
; }
; else
; {
TCT_Not_Nested_Save
; Determine if a thread was interrupted. //判断是否进程产生了中断
; if (TCD_Current_Thread) //如果TCD_Current_Thread是空,则在schedule中因为初始化线程是关中断的
; {
LDR r1,Current_Thread ; Pickup current thread ptr address
LDR r1,[r1, #0] ; Pickup the current thread pointer
CMP r1,#0 ; Is it NU_NULL?
BEQ TCT_Idle_Context_Save ; If no, no real save is necessary
; Yes, a thread was interrupted. Save complete context on the
; thread's stack.
; 1. Save another register on the exception stack so we have enough to work with
STMDB r13!,{r5}
; 2. Save the necessary exception registers into r1-r3
MOV r1,r13 ; Put the exception r13 into r1
MOV r2,r14 ; Move the return address for the caller
; of this function into r2
MRS r3,spsr ; Put the exception spsr into r3
; 3. Adjust the exception stack pointer for future exceptions
ADD r13,r13,#24 ; r13 will point to enable reg value when done
; 4. Switch CPU modes to save context on system stack
MRS r5,CPSR ; Pickup the current CPSR
BIC r5,r5,#MODE_MASK ; Clear the mode bits
ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
MSR CPSR,r5 ; Switch modes (IRQ->SVC)
; 5. Store the SVC r13 into r5 so the r13 can be saved as is.
MOV r5,r13
; 6. Save the exception return address on the stack (r15).
STMDB r5!,{r4}
; 7. Save r6-r14 on stack
STMDB r5!,{r6-r14}
; 8. Switch back to using r13 now that the original r13 has been saved.
MOV r13,r5
; 9. Get r5 and exception enable registers off of exception stack and
; save r5 (stored in r4) back to the system stack.
LDMIA r1!,{r4-r5}
STMDB r13!,{r4}
MOV r4,r5 ; Put exception enable value into r4
; 10. Get the rest of the registers off the exception stack and
; save them onto the system stack.
LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
; 11. Store the exception enable value back on the exception stack.
STMDB r1,{r4}
; 12. Save the SPSR on the system stack (CPSR)
STMDB r13!,{r3}
; 13. Save stack type to the task stack (1=interrupt stack)
MOV r1,#1 ; Interrupt stack type
STMDB r13!,{r1}
; Save the thread's stack pointer in the control block.
; REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread
; REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr
LDR r1,Current_Thread ; Pickup current thread ptr address
LDR r3,[r1, #0] ; Pickup current thread pointer
STR r13,[r3, #TC_STACK_POINTER] ; Save stack pointer
; Switch to the system stack.
; REG_Stack_Ptr = TCD_System_Stack
LDR r1,System_Stack ; Pickup address of stack pointer
LDR r3,System_Limit ; Pickup address of stack limit ptr
LDR r13,[r1, #0] ; Switch to system stack
LDR r10,[r3, #0] ; Setup system stack limit
; Re-enable interrupts
MRS r1,CPSR
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
MSR CPSR,r1
; Return to caller ISR.
BX r2 ; Return to caller ISR
; }
TCT_Idle_Context_Save
MOV r2,r14 ; Save r14 in r2
LDR r3,[r13] ; Get exception enable value from stack
ADD r13,r13,#20 ; Adjust exception r13 for future interrupts
STR r3,[r13] ; Put exception enable value back on stack
MRS r1,CPSR ; Pickup current CPSR
BIC r1,r1,#MODE_MASK ; Clear the current mode
BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) ; Re-enable interrupts
ORR r1,r1,#SUP_MODE ; Prepare to switch to supervisor
; mode (SVC)
MSR CPSR,r1 ; Switch to supervisor mode (SVC)
BX r2 ; Return to caller ISR
; }
;} NU对于中断上下文的保存具体操作如下: (1)在中断发生后执行的入口函数INT_IRQ()中,将r0-r4保存至irq的栈中 (2)查找到对应的interrupt_shell(),clear中断源,更新全局的中断计数器,然后进行interrupt_contex_save (3)首先利用r1,r2,r3保存irq模式下的sp,lr,spsr,这里sp是用来切换至系统栈后拷贝lr和spsr的,这里保存lr和spsr是目的是task被抢占后,当再次schedule时可以返回task之前的状态。 (4)切换至SVC模式,如果是非嵌套的中断则保存上下文至task stack中,将irq模式下的lr作为顶端PC的返回值入栈,将SVC模式下的r6-r14入栈,将irq模式下的sp保存至r4中入栈,最后将保存在irq_stack中的r0-r4入栈 (5)如果是嵌套中断,中断的嵌套发生在LISR中,在执行LISR时已经切换至system stack,因此嵌套中断要将中断的上下文保存至system stack中,与task stack中interrupt stack相比只是少了栈顶用来标记嵌套的标志(1 not nested) (6)有一个分支判断,就是如果当前线程是空,即TCD_Current_Thread == NULL,表明当前是schedule中,因为初始化线程是关中断的,这样就不为schedule线程建立栈帧,因为schedule不需要保存上下文,在restore中断上下文时直接跳转至schedule。
中断上下文的恢复 全局的中断计数器INT_Count是否为0来判定当前出栈的信息,如果是嵌套则返回LISR中,否则切换至system stack执行schedule
阅读(40) | 评论(0) | 转发(0) | 0
上一篇:nucleus plus学习总结
下一篇:nucleus plus学习总结(后续)
相关热门文章 SHTML是什么_SSI有什么用... 查看linux中某个端口(port)... 卡尔曼滤波的原理说明... shell中字符串操作 关于java中的“错误:找不到或... 给主人留下些什么吧!~~ 评论热议