/*;* ;File:os_cpu_a.s ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */ .EQU SwiV, 0x08 .EQU IrqV, 0x18 .EQU FiqV, 0x1c .EQU NoInt,0x80 .EQU SVC32MODE,0x13 .EQU IRQ32MODE,0x12 .EQU FIQ32MODE,0x11 .EQU OSEnterSWI,0x00 .EQU BIT_TIMER0,0x01 .EQU T0IR,0xE0004000 .EQU VICVectAddr,0xFFFFF030 .text .arm .section .SUBR, "ax" .EXTERN OSTCBCur /*addr_OSTCBCur: .WORD OSTCBCur*/ .EXTERN OSTCBHighRdy /*addr_OSTCBHighRdy: .WORD OSTCBHighRdy*/ .EXTERN OSPrioCur /*addr_OSPrioCur: .WORD OSPrioCur*/ .EXTERN OSPrioHighRdy /*addr_OSPrioHighRdy: .WORD OSPrioHighRdy*/ .EXTERN OSTimeTick .EXTERN OSIntNesting .EXTERN OSRunning /* ; IMPORT OSTaskSwHook */ /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;************************************************************************** ;* 中断程序中进行任务切换函数 ;*------------------------------------------------------------------------- ;* 说明:1、调整SP,将上下文保存到被打断的任务堆栈里 ;* 2、将就绪的最高级任务的上下文从任务堆栈中恢复出来 ;* 3、此程序被OSIntExit函数调用,用于在中断程序里进行任务切换。不能随便调用, ;* 要注意堆栈的调整 ;* 4、此程序必须在关中断的情况下进行 ;************************************************************************** */ .GLOBAL OSIntCtxSw .FUNC 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 LDMFD SP!, {R0-R12, LR, PC} .ENDFUNC /* ;************************************************************************** ;* 操作系统的定时器中断服务程序 ;*------------------------------------------------------------------------- ;* 说明:1、该程序为系统提供延时,保证OSTimdDly等函数正常运行 ;* 2、每次定时器中断,就将任务的TCB中的OSTCBDly减一,若变为0,就置任务状态为 ;* 就绪态 ;* 3、要保证当定时器中断时,跳入该程序 ;**************************************************************************/ .EXTERN OSIntEnter .EXTERN OSIntExit .EXTERN OSTimeTick .extern SAVED_IRQ_SPSR .extern SAVED_SVC_SP .extern myTick .GLOBAL TickHandler .FUNC TickHandler TickHandler: SUB LR, LR, #4 /*; 得到返回PC */ STMFD SP!, {R0-R3,LR} /*; 将R0-R3, PC存入中断堆栈中 */ LDR R0, =T0IR LDR R1, =BIT_TIMER0 STR R1, [R0] 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 */ 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} /* ; 其余上下文出栈 */ .ENDFUNC /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; void DisableInt(void) ; void EnableInt(void) ; ; Disable and enable IRQ and FIQ preserving current CPU mode. ;*/ .GLOBAL ARMDisableInt .FUNC ARMDisableInt ARMDisableInt: MRS r0, CPSR ORR r0, r0, #NoInt MSR CPSR_cxsf, r0 MOV pc, lr .ENDFUNC .GLOBAL ARMEnableInt .FUNC ARMEnableInt ARMEnableInt: MRS r0, CPSR BIC r0, r0, #NoInt MSR CPSR_cxsf, r0 MOV pc, lr .ENDFUNC /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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.*/ .GLOBAL OS_TASK_SW .FUNC 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} LDR r4, =OSPrioCur LDR r5, =OSPrioHighRdy LDRB r6, [r5] STRB r6, [r4] 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} .ENDFUNC /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; void ResetCPU(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; reset the cpu ; void OSStartHighRdy(void) ; ; Start the task with the highest priority; ; */ .GLOBAL OSStartHighRdy .FUNC OSStartHighRdy OSStartHighRdy: MSR CPSR_cxsf,#0xD3 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} 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 */ .ENDFUNC