|
ChibiOS/RT
2.5.1 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 /** 00022 * @file GCC/ARMCMx/chcore_v7m.h 00023 * @brief ARMv7-M architecture port macros and structures. 00024 * 00025 * @addtogroup ARMCMx_V7M_CORE 00026 * @{ 00027 */ 00028 00029 #ifndef _CHCORE_V7M_H_ 00030 #define _CHCORE_V7M_H_ 00031 00032 /*===========================================================================*/ 00033 /* Port constants. */ 00034 /*===========================================================================*/ 00035 00036 /** 00037 * @brief Disabled value for BASEPRI register. 00038 */ 00039 #define CORTEX_BASEPRI_DISABLED 0 00040 00041 /*===========================================================================*/ 00042 /* Port macros. */ 00043 /*===========================================================================*/ 00044 00045 /*===========================================================================*/ 00046 /* Port configurable parameters. */ 00047 /*===========================================================================*/ 00048 00049 /** 00050 * @brief Stack size for the system idle thread. 00051 * @details This size depends on the idle thread implementation, usually 00052 * the idle thread should take no more space than those reserved 00053 * by @p PORT_INT_REQUIRED_STACK. 00054 * @note In this port it is set to 16 because the idle thread does have 00055 * a stack frame when compiling without optimizations. You may 00056 * reduce this value to zero when compiling with optimizations. 00057 */ 00058 #if !defined(PORT_IDLE_THREAD_STACK_SIZE) 00059 #define PORT_IDLE_THREAD_STACK_SIZE 16 00060 #endif 00061 00062 /** 00063 * @brief Per-thread stack overhead for interrupts servicing. 00064 * @details This constant is used in the calculation of the correct working 00065 * area size. 00066 * @note In this port this value is conservatively set to 32 because the 00067 * function @p chSchDoReschedule() can have a stack frame, especially 00068 * with compiler optimizations disabled. The value can be reduced 00069 * when compiler optimizations are enabled. 00070 */ 00071 #if !defined(PORT_INT_REQUIRED_STACK) 00072 #define PORT_INT_REQUIRED_STACK 32 00073 #endif 00074 00075 /** 00076 * @brief Enables the use of the WFI instruction in the idle thread loop. 00077 */ 00078 #if !defined(CORTEX_ENABLE_WFI_IDLE) 00079 #define CORTEX_ENABLE_WFI_IDLE FALSE 00080 #endif 00081 00082 /** 00083 * @brief SYSTICK handler priority. 00084 * @note The default SYSTICK handler priority is calculated as the priority 00085 * level in the middle of the numeric priorities range. 00086 */ 00087 #if !defined(CORTEX_PRIORITY_SYSTICK) 00088 #define CORTEX_PRIORITY_SYSTICK (CORTEX_PRIORITY_LEVELS >> 1) 00089 #elif !CORTEX_IS_VALID_PRIORITY(CORTEX_PRIORITY_SYSTICK) 00090 /* If it is externally redefined then better perform a validity check on it.*/ 00091 #error "invalid priority level specified for CORTEX_PRIORITY_SYSTICK" 00092 #endif 00093 00094 /** 00095 * @brief FPU support in context switch. 00096 * @details Activating this option activates the FPU support in the kernel. 00097 */ 00098 #if !defined(CORTEX_USE_FPU) 00099 #define CORTEX_USE_FPU CORTEX_HAS_FPU 00100 #elif CORTEX_USE_FPU && !CORTEX_HAS_FPU 00101 /* This setting requires an FPU presence check in case it is externally 00102 redefined.*/ 00103 #error "the selected core does not have an FPU" 00104 #endif 00105 00106 /** 00107 * @brief Simplified priority handling flag. 00108 * @details Activating this option makes the Kernel work in compact mode. 00109 */ 00110 #if !defined(CORTEX_SIMPLIFIED_PRIORITY) 00111 #define CORTEX_SIMPLIFIED_PRIORITY FALSE 00112 #endif 00113 00114 /** 00115 * @brief SVCALL handler priority. 00116 * @note The default SVCALL handler priority is defaulted to 00117 * @p CORTEX_MAXIMUM_PRIORITY+1, this reserves the 00118 * @p CORTEX_MAXIMUM_PRIORITY priority level as fast interrupts 00119 * priority level. 00120 */ 00121 #if !defined(CORTEX_PRIORITY_SVCALL) 00122 #define CORTEX_PRIORITY_SVCALL (CORTEX_MAXIMUM_PRIORITY + 1) 00123 #elif !CORTEX_IS_VALID_PRIORITY(CORTEX_PRIORITY_SVCALL) 00124 /* If it is externally redefined then better perform a validity check on it.*/ 00125 #error "invalid priority level specified for CORTEX_PRIORITY_SVCALL" 00126 #endif 00127 00128 /** 00129 * @brief NVIC VTOR initialization expression. 00130 */ 00131 #if !defined(CORTEX_VTOR_INIT) || defined(__DOXYGEN__) 00132 #define CORTEX_VTOR_INIT 0x00000000 00133 #endif 00134 00135 /** 00136 * @brief NVIC PRIGROUP initialization expression. 00137 * @details The default assigns all available priority bits as preemption 00138 * priority with no sub-priority. 00139 */ 00140 #if !defined(CORTEX_PRIGROUP_INIT) || defined(__DOXYGEN__) 00141 #define CORTEX_PRIGROUP_INIT (7 - CORTEX_PRIORITY_BITS) 00142 #endif 00143 00144 /*===========================================================================*/ 00145 /* Port derived parameters. */ 00146 /*===========================================================================*/ 00147 00148 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00149 /** 00150 * @brief Maximum usable priority for normal ISRs. 00151 */ 00152 #define CORTEX_MAX_KERNEL_PRIORITY (CORTEX_PRIORITY_SVCALL + 1) 00153 00154 /** 00155 * @brief BASEPRI level within kernel lock. 00156 * @note In compact kernel mode this constant value is enforced to zero. 00157 */ 00158 #define CORTEX_BASEPRI_KERNEL \ 00159 CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY) 00160 #else 00161 00162 #define CORTEX_MAX_KERNEL_PRIORITY 1 00163 #define CORTEX_BASEPRI_KERNEL 0 00164 #endif 00165 00166 /** 00167 * @brief PendSV priority level. 00168 * @note This priority is enforced to be equal to @p CORTEX_BASEPRI_KERNEL, 00169 * this handler always have the highest priority that cannot preempt 00170 * the kernel. 00171 */ 00172 #define CORTEX_PRIORITY_PENDSV CORTEX_BASEPRI_KERNEL 00173 00174 /*===========================================================================*/ 00175 /* Port exported info. */ 00176 /*===========================================================================*/ 00177 00178 #if (CORTEX_MODEL == CORTEX_M3) || defined(__DOXYGEN__) 00179 /** 00180 * @brief Macro defining the specific ARM architecture. 00181 */ 00182 #define CH_ARCHITECTURE_ARM_v7M 00183 00184 /** 00185 * @brief Name of the implemented architecture. 00186 */ 00187 #define CH_ARCHITECTURE_NAME "ARMv7-M" 00188 00189 /** 00190 * @brief Name of the architecture variant. 00191 */ 00192 #define CH_CORE_VARIANT_NAME "Cortex-M3" 00193 00194 #elif (CORTEX_MODEL == CORTEX_M4) 00195 #define CH_ARCHITECTURE_ARM_v7ME 00196 #define CH_ARCHITECTURE_NAME "ARMv7-ME" 00197 #if CORTEX_USE_FPU 00198 #define CH_CORE_VARIANT_NAME "Cortex-M4F" 00199 #else 00200 #define CH_CORE_VARIANT_NAME "Cortex-M4" 00201 #endif 00202 #endif 00203 00204 /** 00205 * @brief Port-specific information string. 00206 */ 00207 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00208 #define CH_PORT_INFO "Advanced kernel mode" 00209 #else 00210 #define CH_PORT_INFO "Compact kernel mode" 00211 #endif 00212 00213 /*===========================================================================*/ 00214 /* Port implementation part. */ 00215 /*===========================================================================*/ 00216 00217 #if !defined(_FROM_ASM_) 00218 00219 /** 00220 * @brief Generic ARM register. 00221 */ 00222 typedef void *regarm_t; 00223 00224 /* The documentation of the following declarations is in chconf.h in order 00225 to not have duplicated structure names into the documentation.*/ 00226 #if !defined(__DOXYGEN__) 00227 00228 typedef uint64_t stkalign_t __attribute__ ((aligned (8))); 00229 00230 struct extctx { 00231 regarm_t r0; 00232 regarm_t r1; 00233 regarm_t r2; 00234 regarm_t r3; 00235 regarm_t r12; 00236 regarm_t lr_thd; 00237 regarm_t pc; 00238 regarm_t xpsr; 00239 #if CORTEX_USE_FPU 00240 regarm_t s0; 00241 regarm_t s1; 00242 regarm_t s2; 00243 regarm_t s3; 00244 regarm_t s4; 00245 regarm_t s5; 00246 regarm_t s6; 00247 regarm_t s7; 00248 regarm_t s8; 00249 regarm_t s9; 00250 regarm_t s10; 00251 regarm_t s11; 00252 regarm_t s12; 00253 regarm_t s13; 00254 regarm_t s14; 00255 regarm_t s15; 00256 regarm_t fpscr; 00257 regarm_t fpccr; 00258 #endif /* CORTEX_USE_FPU */ 00259 }; 00260 00261 struct intctx { 00262 #if CORTEX_USE_FPU 00263 regarm_t s16; 00264 regarm_t s17; 00265 regarm_t s18; 00266 regarm_t s19; 00267 regarm_t s20; 00268 regarm_t s21; 00269 regarm_t s22; 00270 regarm_t s23; 00271 regarm_t s24; 00272 regarm_t s25; 00273 regarm_t s26; 00274 regarm_t s27; 00275 regarm_t s28; 00276 regarm_t s29; 00277 regarm_t s30; 00278 regarm_t s31; 00279 #endif /* CORTEX_USE_FPU */ 00280 regarm_t r4; 00281 regarm_t r5; 00282 regarm_t r6; 00283 regarm_t r7; 00284 regarm_t r8; 00285 regarm_t r9; 00286 regarm_t r10; 00287 regarm_t r11; 00288 regarm_t lr; 00289 }; 00290 00291 #endif /* !defined(__DOXYGEN__) */ 00292 00293 /** 00294 * @brief Platform dependent part of the @p Thread structure. 00295 * @details In this port the structure just holds a pointer to the @p intctx 00296 * structure representing the stack pointer at context switch time. 00297 */ 00298 struct context { 00299 struct intctx *r13; 00300 }; 00301 00302 /** 00303 * @brief Platform dependent part of the @p chThdCreateI() API. 00304 * @details This code usually setup the context switching frame represented 00305 * by an @p intctx structure. 00306 */ 00307 #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ 00308 tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ 00309 wsize - \ 00310 sizeof(struct intctx)); \ 00311 tp->p_ctx.r13->r4 = (void *)(pf); \ 00312 tp->p_ctx.r13->r5 = (void *)(arg); \ 00313 tp->p_ctx.r13->lr = (void *)(_port_thread_start); \ 00314 } 00315 00316 /** 00317 * @brief Enforces a correct alignment for a stack area size value. 00318 */ 00319 #define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1) 00320 00321 /** 00322 * @brief Computes the thread working area global size. 00323 */ 00324 #define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \ 00325 sizeof(struct intctx) + \ 00326 sizeof(struct extctx) + \ 00327 (n) + (PORT_INT_REQUIRED_STACK)) 00328 00329 /** 00330 * @brief Static working area allocation. 00331 * @details This macro is used to allocate a static thread working area 00332 * aligned as both position and size. 00333 */ 00334 #define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)] 00335 00336 /** 00337 * @brief IRQ prologue code. 00338 * @details This macro must be inserted at the start of all IRQ handlers 00339 * enabled to invoke system APIs. 00340 */ 00341 #define PORT_IRQ_PROLOGUE() 00342 00343 /** 00344 * @brief IRQ epilogue code. 00345 * @details This macro must be inserted at the end of all IRQ handlers 00346 * enabled to invoke system APIs. 00347 */ 00348 #define PORT_IRQ_EPILOGUE() _port_irq_epilogue() 00349 00350 /** 00351 * @brief IRQ handler function declaration. 00352 * @note @p id can be a function name or a vector number depending on the 00353 * port implementation. 00354 */ 00355 #define PORT_IRQ_HANDLER(id) void id(void) 00356 00357 /** 00358 * @brief Fast IRQ handler function declaration. 00359 * @note @p id can be a function name or a vector number depending on the 00360 * port implementation. 00361 */ 00362 #define PORT_FAST_IRQ_HANDLER(id) void id(void) 00363 00364 /** 00365 * @brief Port-related initialization code. 00366 */ 00367 #define port_init() _port_init() 00368 00369 /** 00370 * @brief Kernel-lock action. 00371 * @details Usually this function just disables interrupts but may perform 00372 * more actions. 00373 * @note In this port this it raises the base priority to kernel level. 00374 */ 00375 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00376 #if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__) 00377 #define port_lock() { \ 00378 register uint32_t tmp asm ("r3") = CORTEX_BASEPRI_KERNEL; \ 00379 asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory"); \ 00380 } 00381 #else /* !CH_OPTIMIZE_SPEED */ 00382 #define port_lock() { \ 00383 asm volatile ("bl _port_lock" : : : "r3", "lr", "memory"); \ 00384 } 00385 #endif /* !CH_OPTIMIZE_SPEED */ 00386 #else /* CORTEX_SIMPLIFIED_PRIORITY */ 00387 #define port_lock() asm volatile ("cpsid i" : : : "memory") 00388 #endif /* CORTEX_SIMPLIFIED_PRIORITY */ 00389 00390 /** 00391 * @brief Kernel-unlock action. 00392 * @details Usually this function just enables interrupts but may perform 00393 * more actions. 00394 * @note In this port this it lowers the base priority to user level. 00395 */ 00396 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00397 #if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__) 00398 #define port_unlock() { \ 00399 register uint32_t tmp asm ("r3") = CORTEX_BASEPRI_DISABLED; \ 00400 asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory"); \ 00401 } 00402 #else /* !CH_OPTIMIZE_SPEED */ 00403 #define port_unlock() { \ 00404 asm volatile ("bl _port_unlock" : : : "r3", "lr", "memory"); \ 00405 } 00406 #endif /* !CH_OPTIMIZE_SPEED */ 00407 #else /* CORTEX_SIMPLIFIED_PRIORITY */ 00408 #define port_unlock() asm volatile ("cpsie i" : : : "memory") 00409 #endif /* CORTEX_SIMPLIFIED_PRIORITY */ 00410 00411 /** 00412 * @brief Kernel-lock action from an interrupt handler. 00413 * @details This function is invoked before invoking I-class APIs from 00414 * interrupt handlers. The implementation is architecture dependent, 00415 * in its simplest form it is void. 00416 * @note Same as @p port_lock() in this port. 00417 */ 00418 #define port_lock_from_isr() port_lock() 00419 00420 /** 00421 * @brief Kernel-unlock action from an interrupt handler. 00422 * @details This function is invoked after invoking I-class APIs from interrupt 00423 * handlers. The implementation is architecture dependent, in its 00424 * simplest form it is void. 00425 * @note Same as @p port_unlock() in this port. 00426 */ 00427 #define port_unlock_from_isr() port_unlock() 00428 00429 /** 00430 * @brief Disables all the interrupt sources. 00431 * @note Of course non-maskable interrupt sources are not included. 00432 * @note In this port it disables all the interrupt sources by raising 00433 * the priority mask to level 0. 00434 */ 00435 #define port_disable() asm volatile ("cpsid i" : : : "memory") 00436 00437 /** 00438 * @brief Disables the interrupt sources below kernel-level priority. 00439 * @note Interrupt sources above kernel level remains enabled. 00440 * @note In this port it raises/lowers the base priority to kernel level. 00441 */ 00442 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00443 #define port_suspend() { \ 00444 register uint32_t tmp asm ("r3") = CORTEX_BASEPRI_KERNEL; \ 00445 asm volatile ("msr BASEPRI, %0 \n\t" \ 00446 "cpsie i" : : "r" (tmp) : "memory"); \ 00447 } 00448 #else /* CORTEX_SIMPLIFIED_PRIORITY */ 00449 #define port_suspend() asm volatile ("cpsid i" : : : "memory") 00450 #endif /* CORTEX_SIMPLIFIED_PRIORITY */ 00451 00452 /** 00453 * @brief Enables all the interrupt sources. 00454 * @note In this port it lowers the base priority to user level. 00455 */ 00456 #if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__) 00457 #define port_enable() { \ 00458 register uint32_t tmp asm ("r3") = CORTEX_BASEPRI_DISABLED; \ 00459 asm volatile ("msr BASEPRI, %0 \n\t" \ 00460 "cpsie i" : : "r" (tmp) : "memory"); \ 00461 } 00462 #else /* CORTEX_SIMPLIFIED_PRIORITY */ 00463 #define port_enable() asm volatile ("cpsie i" : : : "memory") 00464 #endif /* CORTEX_SIMPLIFIED_PRIORITY */ 00465 00466 /** 00467 * @brief Enters an architecture-dependent IRQ-waiting mode. 00468 * @details The function is meant to return when an interrupt becomes pending. 00469 * The simplest implementation is an empty function or macro but this 00470 * would not take advantage of architecture-specific power saving 00471 * modes. 00472 * @note Implemented as an inlined @p WFI instruction. 00473 */ 00474 #if CORTEX_ENABLE_WFI_IDLE || defined(__DOXYGEN__) 00475 #define port_wait_for_interrupt() { \ 00476 asm volatile ("wfi" : : : "memory"); \ 00477 } 00478 #else 00479 #define port_wait_for_interrupt() 00480 #endif 00481 00482 /** 00483 * @brief Performs a context switch between two threads. 00484 * @details This is the most critical code in any port, this function 00485 * is responsible for the context switch between 2 threads. 00486 * @note The implementation of this code affects <b>directly</b> the context 00487 * switch performance so optimize here as much as you can. 00488 * 00489 * @param[in] ntp the thread to be switched in 00490 * @param[in] otp the thread to be switched out 00491 */ 00492 #if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__) 00493 #define port_switch(ntp, otp) _port_switch(ntp, otp) 00494 #else 00495 #define port_switch(ntp, otp) { \ 00496 register struct intctx *r13 asm ("r13"); \ 00497 if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \ 00498 chDbgPanic("stack overflow"); \ 00499 _port_switch(ntp, otp); \ 00500 } 00501 #endif 00502 00503 #ifdef __cplusplus 00504 extern "C" { 00505 #endif 00506 void port_halt(void); 00507 void _port_init(void); 00508 void _port_irq_epilogue(void); 00509 void _port_switch_from_isr(void); 00510 void _port_exit_from_isr(void); 00511 void _port_switch(Thread *ntp, Thread *otp); 00512 void _port_thread_start(void); 00513 #if !CH_OPTIMIZE_SPEED 00514 void _port_lock(void); 00515 void _port_unlock(void); 00516 #endif 00517 #ifdef __cplusplus 00518 } 00519 #endif 00520 00521 #endif /* _FROM_ASM_ */ 00522 00523 #endif /* _CHCORE_V7M_H_ */ 00524 00525 /** @} */