You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

307 lines
14 KiB

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