;* ;File:os_cpu_a.s ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; author: yuanguiyou ; date : 2007 JAN 15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SwiV EQU 0x08 IrqV EQU 0x18 FiqV EQU 0x1c NoInt EQU 0x80 SVC32MODE EQU 0x13 IRQ32MODE EQU 0x12 FIQ32MODE EQU 0x11 OSEnterSWI EQU 0x00 BIT_TIMER0 EQU 0x01 T0IR EQU 0xE0004000 VICVectAddr EQU 0xFFFFF030 AREA |subr|,CODE,READONLY IMPORT OSTCBCur ;addr_OSTCBCur DCD OSTCBCur IMPORT OSTCBHighRdy ;addr_OSTCBHighRdy DCD OSTCBHighRdy IMPORT OSPrioCur ;addr_OSPrioCur DCD OSPrioCur IMPORT OSPrioHighRdy ;addr_OSPrioHighRdy DCD OSPrioHighRdy IMPORT OSIntNesting ;addr_OSIntNesting DCD OSIntNesting IMPORT OSTimeTick IMPORT OSRunning ; IMPORT OSTaskSwHook ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;************************************************************************** ;* 中断程序中进行任务切换函数 ;*------------------------------------------------------------------------- ;* 说明:1、调整SP,将上下文保存到被打断的任务堆栈里 ;* 2、将就绪的最高级任务的上下文从任务堆栈中恢复出来 ;* 3、此程序被OSIntExit函数调用,用于在中断程序里进行任务切换。不能随便调用, ;* 要注意堆栈的调整 ;* 4、此程序必须在关中断的情况下进行 ;************************************************************************** EXPORT OSIntCtxSw OSIntCtxSw ; BL OSTaskSwHook ; 调用用户自定义的钩子函数 LDR R0, =OSTCBCur LDR R1, =OSTCBHighRdy LDR R2, [R1] STR R2, [R0] ; 令OSTCBCur为OSTCBHighRdy LDR R0, =OSPrioCur LDR R1, =OSPrioHighRdy LDRB R3, [R1] STRB R3, [R0] ; 令OSPrioCur为OSPrioHighRdy LDR SP, [R2] ; 得到即将运行的任务SP LDMFD SP!,{R0} MSR SPSR_cxsf,R0 LDMFD SP!, {R0} MSR CPSR_cxsf, R0 ; 恢复CPSR LDMFD SP!, {R0-R12, LR, PC} ; 恢复其余的寄存器 ;************************************************************************** ;* 操作系统的定时器中断服务程序 ;*------------------------------------------------------------------------- ;* 说明:1、该程序为系统提供延时,保证OSTimdDly等函数正常运行 ;* 2、每次定时器中断,就将任务的TCB中的OSTCBDly减一,若变为0,就置任务状态为 ;* 就绪态 ;* 3、要保证当定时器中断时,跳入该程序 ;************************************************************************** IMPORT OSIntEnter IMPORT OSIntExit IMPORT OSTimeTick EXPORT TickHandler IMPORT myTick TickHandler SUB LR, LR, #4 ; 得到返回PC STMFD SP!, {R0-R3,LR} ; 将R0-R3, PC存入中断堆栈中 LDR R0, =T0IR LDR R1, =BIT_TIMER0 STR R1, [R0] ; 清除中断pending位 LDR R0,=VICVectAddr MOV R1,#0x0 STR R1,[R0] MOV R1, LR ; R1 = 返回PC MOV R2, SP ; R2 = SP_irq ADD SP, SP, #20 ; 调整SP_irq ;bl myTick MRS R3, spsr ; R3 = SPSR_irq ORR R0, R3, #0x80 ; 屏蔽中断 MSR CPSR_cxsf,R0 LDR R0,=SAVED_IRQ_SPSR STR R3,[R0] STMFD SP!,{R1} LDMFD R2, {R0-R3} ; 从IRQ堆栈中恢复出R0-R3 STMFD SP!, {R0-R12,LR} ; 将R0-R3存入IntReStack堆栈中 LDR R0,=SAVED_IRQ_SPSR LDR R0,[R0] STMFD SP!,{R0} MRS R0,SPSR STMFD SP!,{R0} LDR R0, =SAVED_SVC_SP ; STR SP, [R0] ; 将被打断的任务SP存入SAVED_SVC_SP变量中 BL OSIntEnter LDR R0, =OSIntNesting ; LDRB R0, [R0] CMP R0, #1 ;是否是中断嵌套,只在第一次中断处保持SP的值 LDREQ R0, =OSTCBCur LDREQ R0, [R0] STREQ SP, [R0] BL OSTimeTick ; 调用ISR BL OSIntExit ; 调用OSIntExit,推出中断 LDR R0, =SAVED_SVC_SP ; 若是,就从任务堆栈中恢复上下文 LDR SP, [R0] LDMFD SP!,{R0} MSR SPSR_cxsf,R0 LDMFD SP!, {R0} MSR CPSR_cxsf, R0 ; CPSR出栈 LDMFD SP!, {R0-R12, LR, PC} ; 其余上下文出栈 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; void DisableInt(void) ; void EnableInt(void) ; ; Disable and enable IRQ and FIQ preserving current CPU mode. ; EXPORT ARMDisableInt ARMDisableInt ;STMDB sp!, {r0} MRS r0, CPSR ORR r0, r0, #NoInt MSR CPSR_cxsf, r0 ;LDMIA sp!, {r0} MOV pc, lr EXPORT ARMEnableInt ARMEnableInt MRS r0, CPSR BIC r0, r0, #NoInt MSR CPSR_cxsf, r0 MOV pc, lr ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; void OS_TASK_SW(void) ; ; Perform a context switch. ; ; On entry, OSTCBCur and OSPrioCur hold the current TCB and priority ; and OSTCBHighRdy and OSPrioHighRdy contain the same for the task ; to be switched to. ; ; The following code assumes that the virtual memory is directly ; mapped into physical memory. If this is not true, the cache must ; be flushed at context switch to avoid address aliasing. EXPORT OS_TASK_SW OS_TASK_SW STMFD sp!, {lr} ; save pc STMFD sp!, {lr} ; save lr STMFD sp!, {r0-r12} ; save register file and ret address MRS r4, CPSR STMFD sp!, {r4} ; save current PSR MRS r4, SPSR STMFD sp!, {r4} ; save SPSR ; OSPrioCur = OSPrioHighRdy LDR r4, =OSPrioCur LDR r5, =OSPrioHighRdy LDRB r6, [r5] STRB r6, [r4] ; Get current task TCB address LDR r4, =OSTCBCur LDR r5, [r4] STR sp, [r5] ; store sp in preempted tasks's TCB ; Get highest priority task TCB address LDR r6, =OSTCBHighRdy LDR r6, [r6] LDR sp, [r6] ; get new task's stack pointer ; OSTCBCur = OSTCBHighRdy STR r6, [r4] ; set new current task TCB address LDMFD sp!, {r4} MSR SPSR_cxsf, r4 LDMFD sp!, {r4} MSR CPSR_cxsf, r4 LDMFD sp!, {r0-r12, lr, pc} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; void ResetCPU(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; reset the cpu EXPORT ResetCPU ResetCPU MOV R0,#0xD3 MSR SPSR_cxsf,R0 MSR CPSR_cxsf,R0 MOV LR,#0x0 LDR PC,=0x0 ; void OSStartHighRdy(void) ; ; Start the task with the highest priority; ; EXPORT OSStartHighRdy OSStartHighRdy MSR CPSR_cxsf,#0xD3 ; BL OSTaskSwHook LDR r0,=OSRunning MOV r1,#1 STRB r1,[r0] LDR r4, =OSTCBCur ; Get current task TCB address LDR r5, =OSTCBHighRdy ; Get highest priority task TCB address LDR r5, [r5] ; get stack pointer LDR sp, [r5] ; switch to the new stack STR r5, [r4] ; set new current task TCB address LDMFD sp!, {r4} ; YYY MSR SPSR_cxsf, r4 LDMFD sp!, {r4} ; get new state from top of the stack MSR CPSR_cxsf, r4 ; CPSR should be SVC32Mode LDMFD sp!, {r0-r12, lr, pc } ; start the new task AREA INT_DATA, DATA, READWRITE SAVED_SVC_SP DCD 0 ; 用于保存被打断的任务SP SAVED_IRQ_SPSR DCD 0 ; 此区域专用于保存中断嵌套时的上下文 END