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