;*****************************************************************************************
; uC/CPU
; CPU CONFIGURATION & PORT LAYER
;
; (c) Copyright 2004-2008; Micrium, Inc.; Weston, FL
; CPU PORT FILE
; ARM-Cortex-M3
; RealView Development Suite
; RealView Microcontroller Development Kit (MDK)
; ARM Developer Suite (ADS)
; Keil uVision
; Filename : cpu_a.asm
; Version : V1.19
; Programmer(s) : BAN
; PUBLIC FUNCTIONS
;*****************************************************************************************
EXPORT CPU_IntDis
EXPORT CPU_IntEn
EXPORT CPU_SR_Save
EXPORT CPU_SR_Restore
EXPORT CPU_CntLeadZeros
EXPORT CPU_RevBits
EXPORT CPU_WaitForInt
EXPORT CPU_WaitForExcept
;*****************************************************************************************
; CODE GENERATION DIRECTIVES
;*****************************************************************************************
AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
REQUIRE8
PRESERVE8
;******************************************************************************************
; DISABLE and ENABLE INTERRUPTS
; Description : Disable/Enable interrupts.
;
; Prototypes : void CPU_IntDis(void);
; void CPU_IntEn (void);
;******************************************************************************************
CPU_IntDis
CPSID I
BX LR
CPU_IntEn
CPSIE I
BX LR
;******************************************************************************************
; CRITICAL SECTION FUNCTIONS
; Description : Disable/Enable interrupts by preserving the state of interrupts. Generally speaking, the
; state of the interrupt disable flag is stored in the local variable 'cpu_sr' & interrupts
; are then disabled ('cpu_sr' is allocated in all functions that need to disable interrupts).
; The previous interrupt state is restored by copying 'cpu_sr' into the CPU's status register.
;
; Prototypes : CPU_SR CPU_SR_Save (void);
; void CPU_SR_Restore(CPU_SR cpu_sr);
;
; Note(s) : (1) These functions are used in general like this:
;
; void Task (void *p_arg)
; {
; /* Allocate storage for CPU status register */
; #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
; CPU_SR cpu_sr;
; #endif
; CPU_CRITICAL_ENTER(); /* cpu_sr = CPU_SR_Save(); */
; :
; CPU_CRITICAL_EXIT(); /* CPU_SR_Restore(cpu_sr); */
; :
; }
;******************************************************************************************
CPU_SR_Save
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I
BX LR
CPU_SR_Restore ; See Note #2.
MSR PRIMASK, R0
BX LR
;*****************************************************************************************
; COUNT LEADING ZEROS
;
; Description : Counts the number of binary zero bits before the first binary one bit in the argument.
; If the argument is zero, the value 32 is returned.
;
; Prototypes : CPU_INT32U CPU_CntLeadZeros (CPU_INT32U val)
;
; Argument(s) : val variable to count leading zeros
;*****************************************************************************************
CPU_CntLeadZeros
CLZ R0, R0 ; Count leading zeros
BX LR
;*****************************************************************************************
; REVERSE BITS
;
; Description : Reverses the bits in the argument.
;
; Prototypes : CPU_INT32U CPU_RevBits (CPU_INT32U val)
;
; Argument(s) : val variable to reverse
;*****************************************************************************************
CPU_RevBits
RBIT R0, R0 ; Reverse bits
BX LR
;*****************************************************************************************
; WAIT FOR INTERRUPT
;
; Description : Enters sleep state, which will be exited when an interrupt is received.
;
; Prototypes : void CPU_WaitForInt (void)
;
; Argument(s) : none.
;*****************************************************************************************
CPU_WaitForInt
WFI ; Wait for interrupt
BX LR
;*****************************************************************************************
; WAIT FOR EXCEPTION
;
; Description : Enters sleep state, which will be exited when an exception is received.
;
; Prototypes : void CPU_WaitForExcept (void)
;
; Argument(s) : none.
;*****************************************************************************************
CPU_WaitForExcept
WFE ; Wait for exception
BX LR
;*****************************************************************************************
; CPU ASSEMBLY PORT FILE END
;*****************************************************************************************
END
;*****************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2006, Micrium, Weston, FL
; All Rights Reserved
; Generic ARM Port
; File : OS_CPU_A.ASM
; Version : V2.86
; By : Jean J. Labrosse
;
; For : ARMv7M Cortex-M3
; Mode : Thumb2
; Toolchain : RealView Development Suite
; RealView Microcontroller Development Kit (MDK)
; ARM Developer Suite (ADS)
; Keil uVision
;*****************************************************************************************
;*****************************************************************************************
; PUBLIC FUNCTIONS
;*****************************************************************************************
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
EXPORT OS_CPU_PendSVHandler
;*****************************************************************************************
; EQUATES
;*****************************************************************************************
NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register.
NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14).
NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest).
NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
;*****************************************************************************************
; CODE GENERATION DIRECTIVES
;*****************************************************************************************
AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
REQUIRE8
PRESERVE8
;*****************************************************************************************
; 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); */
; :
; :
; }
;*****************************************************************************************
OS_CPU_SR_Save
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I ;Disable interrupts and configurable fault handlers (set PRIMASK)
BX LR ;Return from function call
OS_CPU_SR_Restore
MSR PRIMASK, R0
BX LR
;*****************************************************************************************
; START MULTITASKING
; void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
; the first task to start.
;
; 2) OSStartHighRdy() MUST:
; a) Setup PendSV exception priority to lowest;
; b) Set initial PSP to 0, to tell context switcher this is first run;
; c) Set OSRunning to TRUE;
; d) Trigger PendSV exception;
; e) Enable interrupts (tasks will run with interrupts enabled).
;*****************************************************************************************
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
MSR PSP, R0
LDR R0, =OSRunning ; OSRunning = TRUE
MOVS R1, #1
STRB R1, [R0]
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
CPSIE I ; Enable interrupts at processor level
OSStartHang
B OSStartHang ; Should never get here
;*****************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level)
; void OSCtxSw(void)
; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function
; triggers the PendSV exception which is where the real work is done.
;*****************************************************************************************
OSCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;*****************************************************************************************
; PERFORM A CONTEXT SWITCH (From interrupt level)
; void OSIntCtxSw(void)
;
; Notes: 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as
; the result of an interrupt. This function simply triggers a PendSV exception which will
; be handled when there are no more interrupts active and interrupts are enabled.
;*****************************************************************************************
OSIntCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;*****************************************************************************************
; HANDLE PendSV EXCEPTION
; void OS_CPU_PendSVHandler(void)
;
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the
; processor context on any exception, and restores same on return from exception. So only
; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception
; this way means that context saving and restoring is identical whether it is initiated from
; a thread or occurs due to an interrupt or exception.
; 2) Pseudo-code is:
; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
; b) Save remaining regs r4-r11 on process stack;
; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
; d) Call OSTaskSwHook();
; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
; h) Restore R4-R11 from new process stack;
; i) Perform exception return which will restore remaining context.
; 3) On entry into PendSV handler:
; a) The following have been saved on the process stack (by processor):
; xPSR, PC, LR, R12, R0-R3
; b) Processor mode is switched to Handler mode (from Thread mode)
; c) Stack is Main stack (switched from Process stack)
; d) OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
; know that it will only be run when no other exception or interrupt is active, and
; therefore safe to assume that context being switched out was using the process stack (PSP).
;*****************************************************************************************
OS_CPU_PendSVHandler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
END