ChibiOS/RT
2.6.0
chcore.h
Go to the documentation of this file.
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 /** @} */