📄 os_cpu_a.s
字号:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2004, Micrium, Weston, FL
; All Rights Reserved
;
; Generic ARM Port
;
; File : OS_CPU_A.ASM
; Version : V1.60
; By : Jean J. Labrosse
;
; For : ARM7 or ARM9
; Mode : ARM or Thumb
; Toolchain : IARs EWARM V4.11a and higher
;********************************************************************************************************
IMPORT OSRunning ; External references
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSIntNesting
IMPORT OSIntExit
IMPORT OSTaskSwHook
IMPORT Time0_IRQhandler
EXPORT OS_CPU_SR_Save ; Functions declared in this file
EXPORT OS_CPU_SR_Restore
EXPORT OSStartHighRdy
EXPORT OSCtxSw
EXPORT OSIntCtxSw
EXPORT Time0_irq
NO_INT EQU 0xC0 ; Mask used to disable interrupts (Both FIR and IRQ)
SVC32_MODE EQU 0x13
FIQ32_MODE EQU 0x11
IRQ32_MODE EQU 0x12
;*********************************************************************************************************
; 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 Atmels application note:
;
; "Disabling Interrupts at Processor Level"
;*********************************************************************************************************
AREA OSCPU, CODE, READONLY
CODE32
OS_CPU_SR_Save
MRS R0,CPSR ; Set IRQ and FIQ bits in CPSR to disable all interrupts
ORR R1,R0,#NO_INT
MSR CPSR_c,R1
MRS R1,CPSR ; Confirm that CPSR contains the proper interrupt disable flags
AND R1,R1,#NO_INT
CMP R1,#NO_INT
BNE OS_CPU_SR_Save ; Not properly disabled (try again)
MOV PC,LR ; Disabled, return the original CPSR contents in R0
OS_CPU_SR_Restore
MSR CPSR_c,R0
MOV PC,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.
;*********************************************************************************************************
OSStartHighRdy
;MSR CPSR_cxsf, #0xD3 ; Switch to SVC mode with IRQ and FIQ disabled
;LDR R0, OS_TaskSwHook ; OSTaskSwHook();
;MOV LR, PC
; BX R0
BL OSTaskSwHook
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 R4, [R4] ; get stack pointer
LDR SP, [R4] ; switch to the new stack
LDR R4, [SP], #4 ; pop new tasks CPSR
MSR CPSR_cxsf,R4
LDMFD SP!, {R0-R12,LR,PC} ; pop new tasks context
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw()
;
; Note(s) : 1) OSCtxSw() is called in SVC 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 tasks 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
;*********************************************************************************************************
OSCtxSw
; SAVE CURRENT TASKS CONTEXT
STMFD SP!, {LR} ; Push return address
STMFD SP!, {LR}
STMFD SP!, {R0-R12} ; Push registers
MRS R4, CPSR ; Push current CPSR
;TST LR, #1 ; See if called from Thumb mode
;ORRNE R4, R4, #0x20 ; If yes, Set the T-bit
STMFD SP!, {R4}
LDR R4, OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
;LDR R0, OS_TaskSwHook ; OSTaskSwHook();
;MOV LR, PC
;BX R0
BL OSTaskSwHook
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]
LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; RESTORE NEW TASKS CONTEXT
LDMFD SP!, {R4} ; Pop new tasks CPSR
MSR CPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC} ; Pop new tasks context
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw()
;
; Note(s) : 1) OSIntCtxSw() is called in Svc 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 tasks 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
;*********************************************************************************************************
OSIntCtxSw
;LDR R0, OS_TaskSwHook ; OSTaskSwHook();
;MOV LR, PC
;BX R0
BL OSTaskSwHook
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]
LDR SP,[R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; RESTORE NEW TASKS CONTEXT
LDMFD SP!, {R4} ; Pop new tasks CPSR
MSR CPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC} ; Pop new tasks context
;*********************************************************************************************************
; IRQ Interrupt Service Routine
;*********************************************************************************************************
Time0_irq
STMFD SP!, {R1-R3} ; PUSH WORKING REGISTERS ONTO IRQ STACK
MOV R1, SP ; Save IRQ stack pointer
ADD SP, SP,#12 ; Adjust IRQ stack pointer
SUB R2, LR,#4 ; Adjust PC for return address to task
MRS R3, SPSR ; Copy SPSR (i.e. interrupted tasks CPSR) to R3
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; Change to svc mode
; SAVE TASK'S CONTEXT ONTO TASK'S STACK
STMFD SP!, {R2} ; Push tasks Return PC
STMFD SP!, {LR} ; Push tasks LR
STMFD SP!, {R4-R12} ; Push tasks R12-R4
LDMFD R1!, {R4-R6} ; Move tasks R1-R3 from IRQ stack to SVC stack
STMFD SP!, {R4-R6}
STMFD SP!, {R0} ; Push tasks R0 onto tasks stack
STMFD SP!, {R3} ; Push tasks CPSR (i.e. IRQs SPSR)
; HANDLE NESTING COUNTER
LDR R0, OS_IntNesting ; OSIntNesting++;
LDRB R1, [R0]
ADD R1, R1,#1
STRB R1, [R0]
CMP R1, #1 ; if (OSIntNesting == 1) {
LDREQ R4, OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP
LDREQ R5, [R4]
STREQ SP, [R5] ; }
MSR CPSR_c, #(NO_INT | IRQ32_MODE) ; Change to IRQ mode (to use the IRQ stack to handle interrupt)
; LDR R0, $IRQ_Exception ; OS_CPU_IRQ_ISR_Handler();
; MOV LR, PC
; BX R0
BL Time0_IRQhandler
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; Change to SVC mode
;LDR R0, OS_IntExit ; OSIntExit();
;MOV LR, PC
;BX R0
BL OSIntExit
; RESTORE NEW TASKS CONTEXT
LDMFD SP!, {R4} ; Pop new tasks CPSR
MSR CPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC} ; Pop new tasks context
;*********************************************************************************************************
; POINTERS TO VARIABLES
;*********************************************************************************************************
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 + -