os_cpu_a.asm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. ;********************************************************************************************************
  2. ; uC/OS-II
  3. ; The Real-Time Kernel
  4. ;
  5. ; (c) Copyright 1992-2006, Micrium, Weston, FL
  6. ; All Rights Reserved
  7. ;
  8. ; ARM Cortex-M3 Port
  9. ;
  10. ; File : OS_CPU_A.ASM
  11. ; Version : V2.89
  12. ; By : Jean J. Labrosse
  13. ; Brian Nagel
  14. ;
  15. ; For : ARMv7M Cortex-M3
  16. ; Mode : Thumb2
  17. ; Toolchain : RealView Development Suite
  18. ; RealView Microcontroller Development Kit (MDK)
  19. ; ARM Developer Suite (ADS)
  20. ; Keil uVision
  21. ;********************************************************************************************************
  22. ;********************************************************************************************************
  23. ; PUBLIC FUNCTIONS
  24. ;********************************************************************************************************
  25. EXTERN OSRunning ; External references
  26. EXTERN OSPrioCur
  27. EXTERN OSPrioHighRdy
  28. EXTERN OSTCBCur
  29. EXTERN OSTCBHighRdy
  30. EXTERN OSIntExit
  31. EXTERN OSTaskSwHook
  32. EXTERN OS_CPU_ExceptStkBase
  33. EXPORT OS_CPU_SR_Save ; Functions declared in this file
  34. EXPORT OS_CPU_SR_Restore
  35. EXPORT OSStartHighRdy
  36. EXPORT OSCtxSw
  37. EXPORT OSIntCtxSw
  38. EXPORT PendSV_Handler
  39. ;********************************************************************************************************
  40. ; EQUATES
  41. ;********************************************************************************************************
  42. NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register.
  43. NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14).
  44. NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest).
  45. NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
  46. ;********************************************************************************************************
  47. ; CODE GENERATION DIRECTIVES
  48. ;********************************************************************************************************
  49. AREA |.text|, CODE, READONLY, ALIGN=2
  50. THUMB
  51. REQUIRE8
  52. PRESERVE8
  53. ;********************************************************************************************************
  54. ; CRITICAL SECTION METHOD 3 FUNCTIONS
  55. ;
  56. ; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
  57. ; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
  58. ; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
  59. ; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
  60. ; into the CPU's status register.
  61. ;
  62. ; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
  63. ; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
  64. ;
  65. ;
  66. ; Note(s) : 1) These functions are used in general like this:
  67. ;
  68. ; void Task (void *p_arg)
  69. ; {
  70. ; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  71. ; OS_CPU_SR cpu_sr;
  72. ; #endif
  73. ;
  74. ; :
  75. ; :
  76. ; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */
  77. ; :
  78. ; :
  79. ; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */
  80. ; :
  81. ; :
  82. ; }
  83. ;********************************************************************************************************
  84. OS_CPU_SR_Save
  85. MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
  86. CPSID I
  87. BX LR
  88. OS_CPU_SR_Restore
  89. MSR PRIMASK, R0
  90. BX LR
  91. ;********************************************************************************************************
  92. ; START MULTITASKING
  93. ; void OSStartHighRdy(void)
  94. ;
  95. ; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
  96. ; the first task to start.
  97. ;
  98. ; 2) OSStartHighRdy() MUST:
  99. ; a) Setup PendSV exception priority to lowest;
  100. ; b) Set initial PSP to 0, to tell context switcher this is first run;
  101. ; c) Set the main stack to OS_CPU_ExceptStkBase;
  102. ; d) Set OSRunning to TRUE;
  103. ; e) Trigger PendSV exception;
  104. ; f) Enable interrupts (tasks will run with interrupts enabled).
  105. ;********************************************************************************************************
  106. OSStartHighRdy
  107. LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
  108. LDR R1, =NVIC_PENDSV_PRI
  109. STRB R1, [R0]
  110. MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
  111. MSR PSP, R0
  112. LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase
  113. LDR R1, [R0]
  114. MSR MSP, R1
  115. LDR R0, =OSRunning ; OSRunning = TRUE
  116. MOVS R1, #1
  117. STRB R1, [R0]
  118. LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
  119. LDR R1, =NVIC_PENDSVSET
  120. STR R1, [R0]
  121. CPSIE I ; Enable interrupts at processor level
  122. OSStartHang
  123. B OSStartHang ; Should never get here
  124. ;********************************************************************************************************
  125. ; PERFORM A CONTEXT SWITCH (From task level)
  126. ; void OSCtxSw(void)
  127. ;
  128. ; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function
  129. ; triggers the PendSV exception which is where the real work is done.
  130. ;********************************************************************************************************
  131. OSCtxSw
  132. LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
  133. LDR R1, =NVIC_PENDSVSET
  134. STR R1, [R0]
  135. BX LR
  136. ;********************************************************************************************************
  137. ; PERFORM A CONTEXT SWITCH (From interrupt level)
  138. ; void OSIntCtxSw(void)
  139. ;
  140. ; Notes: 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as
  141. ; the result of an interrupt. This function simply triggers a PendSV exception which will
  142. ; be handled when there are no more interrupts active and interrupts are enabled.
  143. ;********************************************************************************************************
  144. OSIntCtxSw
  145. LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
  146. LDR R1, =NVIC_PENDSVSET
  147. STR R1, [R0]
  148. BX LR
  149. ;********************************************************************************************************
  150. ; HANDLE PendSV EXCEPTION
  151. ; void OS_CPU_PendSVHandler(void)
  152. ;
  153. ; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
  154. ; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the
  155. ; processor context on any exception, and restores same on return from exception. So only
  156. ; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception
  157. ; this way means that context saving and restoring is identical whether it is initiated from
  158. ; a thread or occurs due to an interrupt or exception.
  159. ;
  160. ; 2) Pseudo-code is:
  161. ; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
  162. ; b) Save remaining regs r4-r11 on process stack;
  163. ; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
  164. ; d) Call OSTaskSwHook();
  165. ; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
  166. ; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
  167. ; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
  168. ; h) Restore R4-R11 from new process stack;
  169. ; i) Perform exception return which will restore remaining context.
  170. ;
  171. ; 3) On entry into PendSV handler:
  172. ; a) The following have been saved on the process stack (by processor):
  173. ; xPSR, PC, LR, R12, R0-R3
  174. ; b) Processor mode is switched to Handler mode (from Thread mode)
  175. ; c) Stack is Main stack (switched from Process stack)
  176. ; d) OSTCBCur points to the OS_TCB of the task to suspend
  177. ; OSTCBHighRdy points to the OS_TCB of the task to resume
  178. ;
  179. ; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
  180. ; know that it will only be run when no other exception or interrupt is active, and
  181. ; therefore safe to assume that context being switched out was using the process stack (PSP).
  182. ;********************************************************************************************************
  183. PendSV_Handler
  184. CPSID I ; Prevent interruption during context switch
  185. MRS R0, PSP ; PSP is process stack pointer
  186. CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time
  187. SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
  188. STM R0, {R4-R11}
  189. LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
  190. LDR R1, [R1]
  191. STR R0, [R1] ; R0 is SP of process being switched out
  192. ; At this point, entire context of process has been saved
  193. PendSV_Handler_Nosave
  194. PUSH {R14} ; Save LR exc_return value
  195. LDR R0, =OSTaskSwHook ; OSTaskSwHook();
  196. BLX R0
  197. POP {R14}
  198. LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
  199. LDR R1, =OSPrioHighRdy
  200. LDRB R2, [R1]
  201. STRB R2, [R0]
  202. LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
  203. LDR R1, =OSTCBHighRdy
  204. LDR R2, [R1]
  205. STR R2, [R0]
  206. LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
  207. LDM R0, {R4-R11} ; Restore r4-11 from new process stack
  208. ADDS R0, R0, #0x20
  209. MSR PSP, R0 ; Load PSP with new process SP
  210. ORR LR, LR, #0x04 ; Ensure exception return uses process stack
  211. CPSIE I
  212. BX LR ; Exception return will restore remaining context
  213. END