|
ChibiOS/RT
2.6.0 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012,2013 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 A special exception to the GPL can be applied should you wish to distribute 00023 a combined work that includes ChibiOS/RT, without being obliged to provide 00024 the source code for any proprietary components. See the file exception.txt 00025 for full details of how and when the exception can be applied. 00026 */ 00027 00028 /** 00029 * @file ARM/chcore.h 00030 * @brief ARM7/9 architecture port macros and structures. 00031 * 00032 * @addtogroup ARM_CORE 00033 * @{ 00034 */ 00035 00036 #ifndef _CHCORE_H_ 00037 #define _CHCORE_H_ 00038 00039 /*===========================================================================*/ 00040 /* Port constants. */ 00041 /*===========================================================================*/ 00042 00043 /* Core variants identifiers.*/ 00044 #define ARM_CORE_ARM7TDMI 7 /**< ARM77TDMI core identifier. */ 00045 #define ARM_CORE_ARM9 9 /**< ARM9 core identifier. */ 00046 00047 /* Inclusion of the ARM implementation specific parameters.*/ 00048 #include "armparams.h" 00049 00050 /* ARM core check, only ARM7TDMI and ARM9 supported right now.*/ 00051 #if (ARM_CORE == ARM_CORE_ARM7TDMI) || (ARM_CORE == ARM_CORE_ARM9) 00052 #else 00053 #error "unknown or unsupported ARM core" 00054 #endif 00055 00056 /*===========================================================================*/ 00057 /* Port statically derived parameters. */ 00058 /*===========================================================================*/ 00059 00060 /*===========================================================================*/ 00061 /* Port macros. */ 00062 /*===========================================================================*/ 00063 00064 /*===========================================================================*/ 00065 /* Port configurable parameters. */ 00066 /*===========================================================================*/ 00067 00068 /** 00069 * @brief If enabled allows the idle thread to enter a low power mode. 00070 */ 00071 #ifndef ARM_ENABLE_WFI_IDLE 00072 #define ARM_ENABLE_WFI_IDLE FALSE 00073 #endif 00074 00075 /*===========================================================================*/ 00076 /* Port exported info. */ 00077 /*===========================================================================*/ 00078 00079 /** 00080 * @brief Macro defining a generic ARM architecture. 00081 */ 00082 #define CH_ARCHITECTURE_ARM 00083 00084 #if defined(__DOXYGEN__) 00085 /** 00086 * @brief Macro defining the specific ARM architecture. 00087 * @note This macro is for documentation only, the real name changes 00088 * depending on the selected architecture, the possible names are: 00089 * - CH_ARCHITECTURE_ARM7TDMI. 00090 * - CH_ARCHITECTURE_ARM9. 00091 * . 00092 */ 00093 #define CH_ARCHITECTURE_ARMx 00094 00095 /** 00096 * @brief Name of the implemented architecture. 00097 * @note The value is for documentation only, the real value changes 00098 * depending on the selected architecture, the possible values are: 00099 * - "ARM7". 00100 * - "ARM9". 00101 * . 00102 */ 00103 #define CH_ARCHITECTURE_NAME "ARMx" 00104 00105 /** 00106 * @brief Name of the architecture variant (optional). 00107 * @note The value is for documentation only, the real value changes 00108 * depending on the selected architecture, the possible values are: 00109 * - "ARM7TDMI" 00110 * - "ARM9" 00111 * . 00112 */ 00113 #define CH_CORE_VARIANT_NAME "ARMxy" 00114 00115 /** 00116 * @brief Port-specific information string. 00117 * @note The value is for documentation only, the real value changes 00118 * depending on the selected options, the possible values are: 00119 * - "Pure ARM" 00120 * - "Pure THUMB" 00121 * - "Interworking" 00122 * . 00123 */ 00124 #define CH_PORT_INFO "ARM|THUMB|Interworking" 00125 00126 #elif ARM_CORE == ARM_CORE_ARM7TDMI 00127 #define CH_ARCHITECTURE_ARM7TDMI 00128 #define CH_ARCHITECTURE_NAME "ARM7" 00129 #define CH_CORE_VARIANT_NAME "ARM7TDMI" 00130 00131 #elif ARM_MODEL == ARM_VARIANT_ARM9 00132 #define CH_ARCHITECTURE_ARM9 00133 #define CH_ARCHITECTURE_NAME "ARM9" 00134 #define CH_CORE_VARIANT_NAME "ARM9" 00135 #endif 00136 00137 #if THUMB_PRESENT 00138 #if THUMB_NO_INTERWORKING 00139 #define CH_PORT_INFO "Pure THUMB mode" 00140 #else /* !THUMB_NO_INTERWORKING */ 00141 #define CH_PORT_INFO "Interworking mode" 00142 #endif /* !THUMB_NO_INTERWORKING */ 00143 #else /* !THUMB_PRESENT */ 00144 #define CH_PORT_INFO "Pure ARM mode" 00145 #endif /* !THUMB_PRESENT */ 00146 00147 /** 00148 * @brief Name of the compiler supported by this port. 00149 */ 00150 #define CH_COMPILER_NAME "GCC " __VERSION__ 00151 00152 /*===========================================================================*/ 00153 /* Port implementation part (common). */ 00154 /*===========================================================================*/ 00155 00156 /** 00157 * @brief 32 bits stack and memory alignment enforcement. 00158 */ 00159 typedef uint32_t stkalign_t; 00160 00161 /** 00162 * @brief Generic ARM register. 00163 */ 00164 typedef void *regarm_t; 00165 00166 /** 00167 * @brief Interrupt saved context. 00168 * @details This structure represents the stack frame saved during a 00169 * preemption-capable interrupt handler. 00170 */ 00171 struct extctx { 00172 regarm_t spsr_irq; 00173 regarm_t lr_irq; 00174 regarm_t r0; 00175 regarm_t r1; 00176 regarm_t r2; 00177 regarm_t r3; 00178 regarm_t r12; 00179 regarm_t lr_usr; 00180 }; 00181 00182 /** 00183 * @brief System saved context. 00184 * @details This structure represents the inner stack frame during a context 00185 * switching. 00186 */ 00187 struct intctx { 00188 regarm_t r4; 00189 regarm_t r5; 00190 regarm_t r6; 00191 regarm_t r7; 00192 regarm_t r8; 00193 regarm_t r9; 00194 regarm_t r10; 00195 regarm_t r11; 00196 regarm_t lr; 00197 }; 00198 00199 /** 00200 * @brief Platform dependent part of the @p Thread structure. 00201 * @details In this port the structure just holds a pointer to the @p intctx 00202 * structure representing the stack pointer at context switch time. 00203 */ 00204 struct context { 00205 struct intctx *r13; 00206 }; 00207 00208 /** 00209 * @brief Platform dependent part of the @p chThdCreateI() API. 00210 * @details This code usually setup the context switching frame represented 00211 * by an @p intctx structure. 00212 */ 00213 #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ 00214 tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ 00215 wsize - \ 00216 sizeof(struct intctx)); \ 00217 tp->p_ctx.r13->r4 = pf; \ 00218 tp->p_ctx.r13->r5 = arg; \ 00219 tp->p_ctx.r13->lr = _port_thread_start; \ 00220 } 00221 00222 /** 00223 * @brief Stack size for the system idle thread. 00224 * @details This size depends on the idle thread implementation, usually 00225 * the idle thread should take no more space than those reserved 00226 * by @p PORT_INT_REQUIRED_STACK. 00227 * @note In this port it is set to 4 because the idle thread does have 00228 * a stack frame when compiling without optimizations. 00229 */ 00230 #ifndef PORT_IDLE_THREAD_STACK_SIZE 00231 #define PORT_IDLE_THREAD_STACK_SIZE 4 00232 #endif 00233 00234 /** 00235 * @brief Per-thread stack overhead for interrupts servicing. 00236 * @details This constant is used in the calculation of the correct working 00237 * area size. 00238 * This value can be zero on those architecture where there is a 00239 * separate interrupt stack and the stack space between @p intctx and 00240 * @p extctx is known to be zero. 00241 * @note In this port 0x10 is a safe value, it can be reduced after careful 00242 * analysis of the generated code. 00243 */ 00244 #ifndef PORT_INT_REQUIRED_STACK 00245 #define PORT_INT_REQUIRED_STACK 0x10 00246 #endif 00247 00248 /** 00249 * @brief Enforces a correct alignment for a stack area size value. 00250 */ 00251 #define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1) 00252 00253 /** 00254 * @brief Computes the thread working area global size. 00255 */ 00256 #define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \ 00257 sizeof(struct intctx) + \ 00258 sizeof(struct extctx) + \ 00259 (n) + (PORT_INT_REQUIRED_STACK)) 00260 00261 /** 00262 * @brief Static working area allocation. 00263 * @details This macro is used to allocate a static thread working area 00264 * aligned as both position and size. 00265 */ 00266 #define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)] 00267 00268 /** 00269 * @brief IRQ prologue code. 00270 * @details This macro must be inserted at the start of all IRQ handlers 00271 * enabled to invoke system APIs. 00272 * @note This macro has a different implementation depending if compiled in 00273 * ARM or THUMB mode. 00274 * @note The THUMB implementation starts with ARM code because interrupt 00275 * vectors are always invoked in ARM mode regardless the bit 0 00276 * value. The switch in THUMB mode is done in the function prologue so 00277 * it is transparent to the user code. 00278 */ 00279 #if !defined(PORT_IRQ_PROLOGUE) 00280 #ifdef THUMB 00281 #define PORT_IRQ_PROLOGUE() { \ 00282 asm volatile (".code 32 \n\t" \ 00283 "stmfd sp!, {r0-r3, r12, lr} \n\t" \ 00284 "add r0, pc, #1 \n\t" \ 00285 "bx r0 \n\t" \ 00286 ".code 16" : : : "memory"); \ 00287 } 00288 #else /* !THUMB */ 00289 #define PORT_IRQ_PROLOGUE() { \ 00290 asm volatile ("stmfd sp!, {r0-r3, r12, lr}" : : : "memory"); \ 00291 } 00292 #endif /* !THUMB */ 00293 #endif /* !defined(PORT_IRQ_PROLOGUE) */ 00294 00295 /** 00296 * @brief IRQ epilogue code. 00297 * @details This macro must be inserted at the end of all IRQ handlers 00298 * enabled to invoke system APIs. 00299 * @note This macro has a different implementation depending if compiled in 00300 * ARM or THUMB mode. 00301 */ 00302 #if !defined(PORT_IRQ_EPILOGUE) 00303 #ifdef THUMB 00304 #define PORT_IRQ_EPILOGUE() { \ 00305 asm volatile ("ldr r0, =_port_irq_common \n\t" \ 00306 "bx r0" : : : "memory"); \ 00307 } 00308 #else /* !THUMB */ 00309 #define PORT_IRQ_EPILOGUE() { \ 00310 asm volatile ("b _port_irq_common" : : : "memory"); \ 00311 } 00312 #endif /* !THUMB */ 00313 #endif /* !defined(PORT_IRQ_EPILOGUE) */ 00314 00315 /** 00316 * @brief IRQ handler function declaration. 00317 * @note @p id can be a function name or a vector number depending on the 00318 * port implementation. 00319 */ 00320 #if !defined(PORT_IRQ_HANDLER) 00321 #define PORT_IRQ_HANDLER(id) __attribute__((naked)) void id(void) 00322 #endif /* !defined(PORT_IRQ_HANDLER) */ 00323 00324 /** 00325 * @brief Fast IRQ handler function declaration. 00326 * @note @p id can be a function name or a vector number depending on the 00327 * port implementation. 00328 */ 00329 #if !defined(PORT_FAST_IRQ_HANDLER) 00330 #define PORT_FAST_IRQ_HANDLER(id) \ 00331 __attribute__((interrupt("FIQ"))) void id(void) 00332 #endif /* !defined(PORT_FAST_IRQ_HANDLER) */ 00333 00334 /** 00335 * @brief Port-related initialization code. 00336 * @note This function is empty in this port. 00337 */ 00338 #define port_init() 00339 00340 /** 00341 * @brief Kernel-lock action. 00342 * @details Usually this function just disables interrupts but may perform 00343 * more actions. 00344 * @note In this port it disables the IRQ sources and keeps FIQ sources 00345 * enabled. 00346 */ 00347 #ifdef THUMB 00348 #define port_lock() { \ 00349 asm volatile ("bl _port_lock_thumb" : : : "r3", "lr", "memory"); \ 00350 } 00351 #else /* !THUMB */ 00352 #define port_lock() asm volatile ("msr CPSR_c, #0x9F" : : : "memory") 00353 #endif /* !THUMB */ 00354 00355 /** 00356 * @brief Kernel-unlock action. 00357 * @details Usually this function just enables interrupts but may perform 00358 * more actions. 00359 * @note In this port it enables both the IRQ and FIQ sources. 00360 */ 00361 #ifdef THUMB 00362 #define port_unlock() { \ 00363 asm volatile ("bl _port_unlock_thumb" : : : "r3", "lr", "memory"); \ 00364 } 00365 #else /* !THUMB */ 00366 #define port_unlock() asm volatile ("msr CPSR_c, #0x1F" : : : "memory") 00367 #endif /* !THUMB */ 00368 00369 /** 00370 * @brief Kernel-lock action from an interrupt handler. 00371 * @details This function is invoked before invoking I-class APIs from 00372 * interrupt handlers. The implementation is architecture dependent, 00373 * in its simplest form it is void. 00374 * @note Empty in this port. 00375 */ 00376 #define port_lock_from_isr() 00377 00378 /** 00379 * @brief Kernel-unlock action from an interrupt handler. 00380 * @details This function is invoked after invoking I-class APIs from interrupt 00381 * handlers. The implementation is architecture dependent, in its 00382 * simplest form it is void. 00383 * @note Empty in this port. 00384 */ 00385 #define port_unlock_from_isr() 00386 00387 /** 00388 * @brief Disables all the interrupt sources. 00389 * @note Of course non-maskable interrupt sources are not included. 00390 * @note In this port it disables both the IRQ and FIQ sources. 00391 * @note Implements a workaround for spurious interrupts taken from the NXP 00392 * LPC214x datasheet. 00393 */ 00394 #ifdef THUMB 00395 #define port_disable() { \ 00396 asm volatile ("bl _port_disable_thumb" : : : "r3", "lr", "memory"); \ 00397 } 00398 #else /* !THUMB */ 00399 #define port_disable() { \ 00400 asm volatile ("mrs r3, CPSR \n\t" \ 00401 "orr r3, #0x80 \n\t" \ 00402 "msr CPSR_c, r3 \n\t" \ 00403 "orr r3, #0x40 \n\t" \ 00404 "msr CPSR_c, r3" : : : "r3", "memory"); \ 00405 } 00406 #endif /* !THUMB */ 00407 00408 /** 00409 * @brief Disables the interrupt sources below kernel-level priority. 00410 * @note Interrupt sources above kernel level remains enabled. 00411 * @note In this port it disables the IRQ sources and enables the 00412 * FIQ sources. 00413 */ 00414 #ifdef THUMB 00415 #define port_suspend() { \ 00416 asm volatile ("bl _port_suspend_thumb" : : : "r3", "lr", "memory"); \ 00417 } 00418 #else /* !THUMB */ 00419 #define port_suspend() asm volatile ("msr CPSR_c, #0x9F" : : : "memory") 00420 #endif /* !THUMB */ 00421 00422 /** 00423 * @brief Enables all the interrupt sources. 00424 * @note In this port it enables both the IRQ and FIQ sources. 00425 */ 00426 #ifdef THUMB 00427 #define port_enable() { \ 00428 asm volatile ("bl _port_enable_thumb" : : : "r3", "lr", "memory"); \ 00429 } 00430 #else /* !THUMB */ 00431 #define port_enable() asm volatile ("msr CPSR_c, #0x1F" : : : "memory") 00432 #endif /* !THUMB */ 00433 00434 /** 00435 * @brief Performs a context switch between two threads. 00436 * @details This is the most critical code in any port, this function 00437 * is responsible for the context switch between 2 threads. 00438 * @note The implementation of this code affects <b>directly</b> the context 00439 * switch performance so optimize here as much as you can. 00440 * @note Implemented as inlined code for performance reasons. 00441 * 00442 * @param[in] ntp the thread to be switched in 00443 * @param[in] otp the thread to be switched out 00444 */ 00445 #ifdef THUMB 00446 #if CH_DBG_ENABLE_STACK_CHECK 00447 #define port_switch(ntp, otp) { \ 00448 register struct intctx *r13 asm ("r13"); \ 00449 if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \ 00450 chDbgPanic("stack overflow"); \ 00451 _port_switch_thumb(ntp, otp); \ 00452 } 00453 #else /* !CH_DBG_ENABLE_STACK_CHECK */ 00454 #define port_switch(ntp, otp) _port_switch_thumb(ntp, otp) 00455 #endif /* !CH_DBG_ENABLE_STACK_CHECK */ 00456 #else /* !THUMB */ 00457 #if CH_DBG_ENABLE_STACK_CHECK 00458 #define port_switch(ntp, otp) { \ 00459 register struct intctx *r13 asm ("r13"); \ 00460 if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \ 00461 chDbgPanic("stack overflow"); \ 00462 _port_switch_arm(ntp, otp); \ 00463 } 00464 #else /* !CH_DBG_ENABLE_STACK_CHECK */ 00465 #define port_switch(ntp, otp) _port_switch_arm(ntp, otp) 00466 #endif /* !CH_DBG_ENABLE_STACK_CHECK */ 00467 #endif /* !THUMB */ 00468 00469 #ifdef __cplusplus 00470 extern "C" { 00471 #endif 00472 void port_halt(void); 00473 #ifdef THUMB 00474 void _port_switch_thumb(Thread *ntp, Thread *otp); 00475 #else /* !THUMB */ 00476 void _port_switch_arm(Thread *ntp, Thread *otp); 00477 #endif /* !THUMB */ 00478 void _port_thread_start(void); 00479 #ifdef __cplusplus 00480 } 00481 #endif 00482 00483 #endif /* _CHCORE_H_ */ 00484 00485 /** @} */