📄 os_cpu_a.asm
字号:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2005, Micrium, Weston, FL
; All Rights Reserved
;
; Generic ARM Port
;
; File : OS_CPU_A.ASM
; Version : V2.00(Rev)
; By : Jean J. Labrosse
; Rev By : leafboy(2006.12.16-2006.12.28)
;
; For : ARM7 or ARM9
; Mode : ARM or Thumb
; Toolchain : KEIL's RV V3.03A and higher
;********************************************************************************************************
OS_TASK_SW_HOOK EQU 0
ASM_KEILRV EQU 1
;--------------------------------
;- ARM Core Mode and Status Bits
;--------------------------------
ARM_MODE_USER EQU 0x10
ARM_MODE_FIQ EQU 0x11
ARM_MODE_IRQ EQU 0x12
ARM_MODE_SVC EQU 0x13
ARM_MODE_ABORT EQU 0x17
ARM_MODE_UNDEF EQU 0x1B
ARM_MODE_SYS EQU 0x1F
I_BIT EQU 0x80
F_BIT EQU 0x40
T_BIT EQU 0x20
EXTERN OSRunning ; External references
EXTERN OSPrioCur
EXTERN OSPrioHighRdy
EXTERN OSTCBCur
EXTERN OSTCBHighRdy
EXTERN OSIntNesting
EXTERN OSIntExit
EXTERN OSTaskSwHook
EXPORT OS_CPU_SR_Save ; Functions declared in this file
EXPORT OS_CPU_SR_Restore
EXPORT OSStartHighRdy
EXPORT OSCtxSw
EXPORT OSIntCtxSw ; OSIntCtxSw() for OSIntExit() @ os_core.c as null
;*********************************************************************************************************
; 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.
;
; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s) : 1) These functions are used in general like this:
;
; void Task (void *p_arg)
; {
; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
; OS_CPU_SR cpu_sr;
; #endif
;
; :
; :
; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */
; :
; :
; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */
; :
; :
; }
;
; 2) OS_CPU_SaveSR() is implemented as recommended by Atmel's application note:
;
; "Disabling Interrupts at Processor Level"
;*********************************************************************************************************
IF (ASM_KEILRV > 0)
PRESERVE8
AREA |.text|, CODE, READONLY
ARM
ELSE
RSEG CODE:CODE:NOROOT(2)
CODE32
ENDIF
OS_CPU_SR_Save
MRS R0,CPSR ; Set IRQ and FIQ bits in CPSR to disable all interrupts
ORR R1,R0,#(I_BIT | F_BIT)
MSR CPSR_c,R1
BX LR ; Disabled, return the original CPSR contents in R0
OS_CPU_SR_Restore
MSR CPSR_c,R0
BX LR
;*********************************************************************************************************
; START MULTITASKING
; void OSStartHighRdy(void)
;
; Note(s) : 1) OSStartHighRdy() MUST:
; a) Call OSTaskSwHook() then,
; b) Set OSRunning to TRUE,
; c) Switch to the highest priority task.
;*********************************************************************************************************
IF (ASM_KEILRV > 0)
PRESERVE8
AREA |.text|, CODE, READONLY
ARM
ELSE
RSEG CODE:CODE:NOROOT(2)
CODE32
ENDIF
OSStartHighRdy
IF (OS_TASK_SW_HOOK >= 1)
LDR R0, OS_TaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
ENDIF
MSR CPSR_c, #(I_BIT | F_BIT | ARM_MODE_SYS) ; Switch to SYS mode with IRQ and FIQ disabled
LDR R4, OS_Running ; OSRunning = TRUE
MOV R5, #1
STRB R5, [R4]
; SWITCH TO HIGHEST PRIORITY TASK
LDR R4, OS_TCBHighRdy ; Get highest priority task TCB address
LDR R6, [R4] ; get stack pointer
;---------------------------------------------------------------------------------
; LDR SP, [R6] ; switch to the new stack
; LDR R4, [SP], #4 ; pop new task's CPSR
; MSR CPSR_cxsf, R4 ; has CPSR only at SYS mode
; LDMFD SP!, {R0-R12,LR,PC} ; pop new task's context
;---------------------------------------------------------------------------------
B OSCtxSw2
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw()
;
; Note(s) : 1) OSCtxSw() is called in SYS mode with BOTH FIQ and IRQ interrupts DISABLED
;
; 2) The pseudo-code for OSCtxSw() is:
; a) Save the current task's context onto the current task's stack
; b) OSTCBCur->OSTCBStkPtr = SP;
; c) OSTaskSwHook();
; d) OSPrioCur = OSPrioHighRdy;
; e) OSTCBCur = OSTCBHighRdy;
; f) SP = OSTCBHighRdy->OSTCBStkPtr;
; g) Restore the new task's context from the new task's stack
; h) Return to new task's code
;
; 3) Upon entry:
; OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;*********************************************************************************************************
IF (ASM_KEILRV > 0)
PRESERVE8
AREA |.text|, CODE, READONLY
ARM
ELSE
RSEG CODE:CODE:NOROOT(2)
CODE32
ENDIF
OSCtxSw
; SAVE CURRENT TASK'S CONTEXT
STMFD SP!, {LR} ; Push return address
STMFD SP!, {R0-R12, LR} ; Push registers
MRS R4, CPSR ; Push current CPSR
TST LR, #1 ; See if called from Thumb mode
ORRNE R4, R4, #T_BIT ; If yes, Set the T-bit
STMFD SP!, {R4}
OSCtxSw1
LDR R4, OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
IF (OS_TASK_SW_HOOK >= 1)
LDR R0, OS_TaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
ENDIF
LDR R4, OS_PrioCur ; OSPrioCur = OSPrioHighRdy
LDR R5, OS_PrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, OS_TCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R6, OS_TCBHighRdy
LDR R6, [R6]
STR R6, [R4]
OSCtxSw2
;---------------------------------------------------------------------------------
;LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; RESTORE NEW TASK'S CONTEXT
;LDMFD SP!, {R4} ; Pop new task's CPSR
;MSR CPSR_cxsf, R4 ; has CPSR only at SYS mode
;LDMFD SP!, {R0-R12,LR,PC} ; pop new task's context
;---------------------------------------------------------------------------------
LDR R4, [R6] ; R4(SP) = OSTCBHighRdy->OSTCBStkPtr;
ADD SP, R4, #16*4 ; Adjust SYS stack pointer
LDR LR, [SP, #-2*4] ; get new task's register LR_sys
MSR CPSR_c, #(I_BIT | F_BIT | ARM_MODE_UNDEF) ; Switch to UNDEF mode
MOV SP, R4
; RESTORE NEW TASK'S CONTEXT
LDMFD SP!, {R4} ; Pop new task's CPSR
MSR SPSR_cxsf, R4 ; has SPSR only at UNDEF mode
LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's context
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw()
;
; Note(s) : 1) OSIntCtxSw() is called in SYS mode with BOTH FIQ and IRQ interrupts DISABLED
;
; 2) The pseudo-code for OSCtxSw() is:
; a) OSTaskSwHook();
; b) OSPrioCur = OSPrioHighRdy;
; c) OSTCBCur = OSTCBHighRdy;
; d) SP = OSTCBHighRdy->OSTCBStkPtr;
; e) Restore the new task's context from the new task's stack
; f) Return to new task's code
;
; 3) Upon entry:
; OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;*********************************************************************************************************
IF (ASM_KEILRV > 0)
PRESERVE8
AREA |.text|, CODE, READONLY
ARM
ELSE
RSEG CODE:CODE:NOROOT(2)
CODE32
ENDIF
OSIntCtxSw
;********************************************************************
; IRQ STACK <LOW> R4 R14 | SPSR R0 R1 R2 R3 R11 R12 LR(PC) <HIGH>
;********************************************************************
; SAVE TASK'S CONTEXT ONTO TASK'S STACK
;ADD SP, SP, #2*4 ; Adjust IRQ stack pointer (OSIntExit=2*4)
;LDMFD SP!, {R4, R14} ; Restore, See OSIntExit() @ os_core.c
ADD SP, SP, #(0+8)*4 ; Adjust IRQ stack pointer
; {R4,R14}=2*4, {SPSR, R0-R3, R11, R12, LR}=8*4
SUB R0, SP, #3*4 ; R0->R11
MSR CPSR_c, #(I_BIT | F_BIT | ARM_MODE_SYS) ; Switch to SYS mode
LDMIA R0, {R1-R3} ; R11,R12,LR(PC)=>R1,R2,R3
SUB R0, R0, #5*4 ; Moving (SPSR, R3-R0)
STMFD SP!, {R3} ; R3(PC)=>[SP]
STMFD SP!, {R1-R2, LR} ; R1(R11),R2(R12),LR=>[SP]
STMFD SP!, {R4-R10} ; R4-R10=>[SP]
LDMIA R0, {R4-R8} ; SPSR,R0-R3=>R4-R8
STMFD SP!, {R4-R8} ; R4(SPSR),R5-R8(R0-R3)=>[SP]
B OSCtxSw1
;*********************************************************************************************************
; POINTERS TO VARIABLES
;*********************************************************************************************************
IF (OS_TASK_SW_HOOK >= 1)
OS_TaskSwHook
DCD OSTaskSwHook
ENDIF
OS_IntExit
DCD OSIntExit
OS_IntNesting
DCD OSIntNesting
OS_PrioCur
DCD OSPrioCur
OS_PrioHighRdy
DCD OSPrioHighRdy
OS_Running
DCD OSRunning
OS_TCBCur
DCD OSTCBCur
OS_TCBHighRdy
DCD OSTCBHighRdy
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -