📄 os_cpu_a.s
字号:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
; All Rights Reserved
;
; File : OS_CPU_A.ASM
; By : Jean J. Labrosse
;********************************************************************************************************
;********************************************************************************************************
; ARM Port
;
; Target : ARM (Includes ARM7, ARM9)
; Ported by : Michael Anburaj
; URL : http://geocities.com/michaelanburaj/ Email : michaelanburaj@hotmail.com
;
;********************************************************************************************************
AREA UCOS_ARM, CODE, READONLY
;*********************************************************************************************************
; START MULTITASKING
; void OSStartHighRdy(void)
;
; Note : OSStartHighRdy() MUST:
; a) Call OSTaskSwHook() then,
; b) Set OSRunning to TRUE,
; c) Switch to the highest priority task.
;*********************************************************************************************************
IMPORT OSTaskSwHook
IMPORT OSRunning
IMPORT OSTCBHighRdy
EXPORT OSStartHighRdy
OSStartHighRdy
bl OSTaskSwHook ; Call user defined task switch hook
ldr r4,=OSRunning ; Indicate that multitasking has started
mov r5,#1
strb r5,[r4]
ldr r4,=OSTCBHighRdy ; Get highest priority task TCB address
ldr r4,[r4] ; get stack pointer
ldr sp,[r4] ; switch to the new stack
ldmfd sp!,{r4} ; pop new task's spsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ; pop new task's psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level)
; void OSCtxSw(void)
;
; Note(s): Upon entry,
; OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;
;*********************************************************************************************************
IMPORT OSTCBCur
IMPORT OSTaskSwHook
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
EXPORT OSCtxSw
OSCtxSw
; Special optimised code below:
stmfd sp!,{lr} ; push pc (lr should be pushed in place of PC)
stmfd sp!,{r0-r12,lr} ; push lr & register file
mrs r4,cpsr
stmfd sp!,{r4} ; push current psr
mrs r4,spsr
stmfd sp!,{r4} ; push current 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
bl OSTaskSwHook ; call Task Switch Hook
; 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} ; pop new task's spsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ; pop new task's psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From an ISR)
; void OSIntCtxSw(void)
;
; Note(s): This function only flags a context switch to the ISR Handler
;
;*********************************************************************************************************
IMPORT OSIntCtxSwFlag
EXPORT OSIntCtxSw
OSIntCtxSw
;OSIntCtxSwFlag = True
ldr r0,=OSIntCtxSwFlag
mov r1,#1
str r1,[r0]
mov pc,lr
;*********************************************************************************************************
; IRQ HANDLER
;
; This handles all the IRQs
; Note: FIQ Handler should be written similar to this
;
;*********************************************************************************************************
IMPORT int_vector_handler
IMPORT OSIntEnter
IMPORT OSIntExit
IMPORT OSIntCtxSwFlag
IMPORT OSTCBCur
IMPORT OSTaskSwHook
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
NOINT EQU 0xc0
EXPORT UCOS_IRQHandler
UCOS_IRQHandler
sub lr, lr, #4
stmfd sp!,{r0-r3,r12,lr}
bl OSIntEnter
bl int_vector_handler
bl OSIntExit
ldr r0,=OSIntCtxSwFlag
ldr r1,[r0]
cmp r1,#1
beq _IntCtxSw
ldmfd sp!,{r0-r3,r12,pc}^
_IntCtxSw
mov r1,#0
str r1,[r0]
ldmfd sp!,{r0-r3,r12,lr}
;//save r0 and r1 into temp variables IRQ_R0 and IRQ_R1
stmfd sp!, {r0,r1}
ldr r0, =IRQ_R1
str r1, [r0]
ldmfd sp!, {r0}
ldr r1, =IRQ_R0
str r0, [r1]
add r13, r13, #4 ;//restore the sp_irq top to original irq top
;//save IRQ_spsr into temp variables CPSR and SPSR
mrs r1, spsr
ldr r0, =CPSR
str r1, [r0]
ldr r0, =PSR
str r1, [r0]
mov r0, lr ;//save return address interrupted by int
orr r1, r1, #0x80 ;//close irq when change into SVC mode
msr cpsr_cxsf, r1 ;//change irq mode into svc
;//-----------the below code is under svc mode----------------------------
stmfd sp!, {r0} ;//push pc (r0 should be pushed in place of PC)
stmfd sp!, {lr} ;//push lr
;//-----------restore r0 and r1 from IRQ_R0 and IRQ_R1-----
ldr r0, =IRQ_R1
ldr r1, [r0]
stmfd sp!, {r1}
ldr r1, =IRQ_R0
ldr r0, [r1]
stmfd sp!, {r0}
ldmfd sp!, {r0,r1}
;//------------push r0-r12----------------------------------
stmfd sp!, {r0-r12}
ldr r4, =PSR
ldr r4, [r4]
stmfd sp!,{r4} ;//push current psr
ldr r4, =CPSR
ldr r4, [r4]
stmfd sp!,{r4} ;//push current 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
bl OSTaskSwHook ;//call Task Switch Hook
;//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} ;//pop new task's spsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ;//pop new task's psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ;//pop new task's r0-r12,lr & pc
;*********************************************************************************************************
; CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
; into the CPU's status register.
;
; OS_CPU_SR OSCPUSaveSR()
; Arguments : none
;
; Returns : OS_CPU_SR
;
; OSCPURestoreSR(OS_CPU_SR cpu_sr)
; Arguments : OS_CPU_SR
;
; Returns : none
;
; Note(s) : These functions are used in general like this,
;
; void Task (void *data)
; {
; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
; OS_CPU_SR cpu_sr;
; #endif
; :
; :
; OS_ENTER_CRITICAL(); /* cpu_sr = OSCPUSaveSR(); */
; :
; :
; OS_EXIT_CRITICAL(); /* OSCPURestoreSR(cpu_sr); */
; :
; :
; }
;*********************************************************************************************************
EXPORT OSCPUSaveSR
OSCPUSaveSR
mrs r0,CPSR
orr r1,r0,#NOINT
msr CPSR_c,r1
mov pc,lr
EXPORT OSCPURestoreSR
OSCPURestoreSR
msr CPSR_c,r0
mov pc,lr
;*************************************************************
IRQ_R1 DCD 0X0
IRQ_R0 DCD 0X0
PSR DCD 0X0
CPSR DCD 0X0
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -