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