ChibiOS/RT
2.6.0
chcore_v6m.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    GCC/ARMCMx/chcore_v6m.h
00030  * @brief   ARMv6-M architecture port macros and structures.
00031  *
00032  * @addtogroup ARMCMx_V6M_CORE
00033  * @{
00034  */
00035 
00036 #ifndef _CHCORE_V6M_H_
00037 #define _CHCORE_V6M_H_
00038 
00039 /*===========================================================================*/
00040 /* Port constants.                                                           */
00041 /*===========================================================================*/
00042 
00043 /**
00044  * @brief   PendSV priority level.
00045  * @note    This priority is enforced to be equal to @p 0,
00046  *          this handler always has the highest priority that cannot preempt
00047  *          the kernel.
00048  */
00049 #define CORTEX_PRIORITY_PENDSV          0
00050 
00051 /*===========================================================================*/
00052 /* Port macros.                                                              */
00053 /*===========================================================================*/
00054 
00055 /*===========================================================================*/
00056 /* Port configurable parameters.                                             */
00057 /*===========================================================================*/
00058 
00059 /**
00060  * @brief   Stack size for the system idle thread.
00061  * @details This size depends on the idle thread implementation, usually
00062  *          the idle thread should take no more space than those reserved
00063  *          by @p PORT_INT_REQUIRED_STACK.
00064  * @note    In this port it is set to 16 because the idle thread does have
00065  *          a stack frame when compiling without optimizations. You may
00066  *          reduce this value to zero when compiling with optimizations.
00067  */
00068 #if !defined(PORT_IDLE_THREAD_STACK_SIZE)
00069 #define PORT_IDLE_THREAD_STACK_SIZE     16
00070 #endif
00071 
00072 /**
00073  * @brief   Per-thread stack overhead for interrupts servicing.
00074  * @details This constant is used in the calculation of the correct working
00075  *          area size.
00076  * @note    In this port this value is conservatively set to 32 because the
00077  *          function @p chSchDoReschedule() can have a stack frame, especially
00078  *          with compiler optimizations disabled. The value can be reduced
00079  *          when compiler optimizations are enabled.
00080  */
00081 #if !defined(PORT_INT_REQUIRED_STACK)
00082 #define PORT_INT_REQUIRED_STACK         32
00083 #endif
00084 
00085 /**
00086  * @brief   Enables the use of the WFI instruction in the idle thread loop.
00087  */
00088 #if !defined(CORTEX_ENABLE_WFI_IDLE)
00089 #define CORTEX_ENABLE_WFI_IDLE          FALSE
00090 #endif
00091 
00092 /**
00093  * @brief   SYSTICK handler priority.
00094  * @note    The default SYSTICK handler priority is calculated as the priority
00095  *          level in the middle of the numeric priorities range.
00096  */
00097 #if !defined(CORTEX_PRIORITY_SYSTICK)
00098 #define CORTEX_PRIORITY_SYSTICK         (CORTEX_PRIORITY_LEVELS >> 1)
00099 #elif !CORTEX_IS_VALID_PRIORITY(CORTEX_PRIORITY_SYSTICK)
00100 /* If it is externally redefined then better perform a validity check on it.*/
00101 #error "invalid priority level specified for CORTEX_PRIORITY_SYSTICK"
00102 #endif
00103 
00104 /**
00105  * @brief   Alternate preemption method.
00106  * @details Activating this option will make the Kernel use the PendSV
00107  *          handler for preemption instead of the NMI handler.
00108  */
00109 #ifndef CORTEX_ALTERNATE_SWITCH
00110 #define CORTEX_ALTERNATE_SWITCH         FALSE
00111 #endif
00112 
00113 /*===========================================================================*/
00114 /* Port derived parameters.                                                  */
00115 /*===========================================================================*/
00116 
00117 /**
00118  * @brief   Maximum usable priority for normal ISRs.
00119  */
00120 #if CORTEX_ALTERNATE_SWITCH || defined(__DOXYGEN__)
00121 #define CORTEX_MAX_KERNEL_PRIORITY      1
00122 #else
00123 #define CORTEX_MAX_KERNEL_PRIORITY      0
00124 #endif
00125 
00126 /*===========================================================================*/
00127 /* Port exported info.                                                       */
00128 /*===========================================================================*/
00129 
00130 /**
00131  * @brief   Macro defining the specific ARM architecture.
00132  */
00133 #define CH_ARCHITECTURE_ARM_v6M
00134 
00135 /**
00136  * @brief   Name of the implemented architecture.
00137  */
00138 #define CH_ARCHITECTURE_NAME            "ARMv6-M"
00139 
00140 /**
00141  * @brief   Name of the architecture variant.
00142  */
00143 #if (CORTEX_MODEL == CORTEX_M0) || defined(__DOXYGEN__)
00144 #define CH_CORE_VARIANT_NAME            "Cortex-M0"
00145 #elif (CORTEX_MODEL == CORTEX_M1)
00146 #define CH_CORE_VARIANT_NAME            "Cortex-M1"
00147 #endif
00148 
00149 /**
00150  * @brief   Port-specific information string.
00151  */
00152 #if !CORTEX_ALTERNATE_SWITCH || defined(__DOXYGEN__)
00153 #define CH_PORT_INFO                    "Preemption through NMI"
00154 #else
00155 #define CH_PORT_INFO                    "Preemption through PendSV"
00156 #endif
00157 
00158 /*===========================================================================*/
00159 /* Port implementation part.                                                 */
00160 /*===========================================================================*/
00161 
00162 #if !defined(_FROM_ASM_)
00163 
00164 /**
00165  * @brief   Generic ARM register.
00166  */
00167 typedef void *regarm_t;
00168 
00169  /* The documentation of the following declarations is in chconf.h in order
00170     to not have duplicated structure names into the documentation.*/
00171 #if !defined(__DOXYGEN__)
00172 
00173 typedef uint64_t stkalign_t __attribute__ ((aligned (8)));
00174 
00175 struct extctx {
00176   regarm_t      r0;
00177   regarm_t      r1;
00178   regarm_t      r2;
00179   regarm_t      r3;
00180   regarm_t      r12;
00181   regarm_t      lr_thd;
00182   regarm_t      pc;
00183   regarm_t      xpsr;
00184 };
00185 
00186 struct intctx {
00187   regarm_t      r8;
00188   regarm_t      r9;
00189   regarm_t      r10;
00190   regarm_t      r11;
00191   regarm_t      r4;
00192   regarm_t      r5;
00193   regarm_t      r6;
00194   regarm_t      r7;
00195   regarm_t      lr;
00196 };
00197 
00198 #endif /* !defined(__DOXYGEN__) */
00199 
00200 /**
00201  * @brief   Platform dependent part of the @p Thread structure.
00202  * @details In this port the structure just holds a pointer to the @p intctx
00203  *          structure representing the stack pointer at context switch time.
00204  */
00205 struct context {
00206   struct intctx *r13;
00207 };
00208 
00209 /**
00210  * @brief   Platform dependent part of the @p chThdCreateI() API.
00211  * @details This code usually setup the context switching frame represented
00212  *          by an @p intctx structure.
00213  */
00214 #define SETUP_CONTEXT(workspace, wsize, pf, arg) {                          \
00215   tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace +                  \
00216                                      wsize -                                \
00217                                      sizeof(struct intctx));                \
00218   tp->p_ctx.r13->r4 = (void *)(pf);                                         \
00219   tp->p_ctx.r13->r5 = (void *)(arg);                                        \
00220   tp->p_ctx.r13->lr = (void *)(_port_thread_start);                         \
00221 }
00222 
00223 /**
00224  * @brief   Enforces a correct alignment for a stack area size value.
00225  */
00226 #define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
00227 
00228 /**
00229  * @brief   Computes the thread working area global size.
00230  */
00231 #define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) +                         \
00232                                    sizeof(struct intctx) +                  \
00233                                    sizeof(struct extctx) +                  \
00234                                    (n) + (PORT_INT_REQUIRED_STACK))
00235 
00236 /**
00237  * @brief   Static working area allocation.
00238  * @details This macro is used to allocate a static thread working area
00239  *          aligned as both position and size.
00240  */
00241 #define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)]
00242 
00243 /**
00244  * @brief   IRQ prologue code.
00245  * @details This macro must be inserted at the start of all IRQ handlers
00246  *          enabled to invoke system APIs.
00247  */
00248 #define PORT_IRQ_PROLOGUE()                                                 \
00249   regarm_t _saved_lr;                                                       \
00250   asm volatile ("mov     %0, lr" : "=r" (_saved_lr) : : "memory")
00251 
00252 /**
00253  * @brief   IRQ epilogue code.
00254  * @details This macro must be inserted at the end of all IRQ handlers
00255  *          enabled to invoke system APIs.
00256  */
00257 #define PORT_IRQ_EPILOGUE() _port_irq_epilogue(_saved_lr)
00258 
00259 /**
00260  * @brief   IRQ handler function declaration.
00261  * @note    @p id can be a function name or a vector number depending on the
00262  *          port implementation.
00263  */
00264 #define PORT_IRQ_HANDLER(id) void id(void)
00265 
00266 /**
00267  * @brief   Fast IRQ handler function declaration.
00268  * @note    @p id can be a function name or a vector number depending on the
00269  *          port implementation.
00270  */
00271 #define PORT_FAST_IRQ_HANDLER(id) void id(void)
00272 
00273 /**
00274  * @brief   Port-related initialization code.
00275  */
00276 #define port_init() {                                                       \
00277   SCB_AIRCR = AIRCR_VECTKEY | AIRCR_PRIGROUP(0);                            \
00278   nvicSetSystemHandlerPriority(HANDLER_PENDSV,                              \
00279     CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_PENDSV));                          \
00280   nvicSetSystemHandlerPriority(HANDLER_SYSTICK,                             \
00281     CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SYSTICK));                         \
00282 }
00283 
00284 /**
00285  * @brief   Kernel-lock action.
00286  * @details Usually this function just disables interrupts but may perform
00287  *          more actions.
00288  */
00289 #define port_lock() asm volatile ("cpsid   i" : : : "memory")
00290 
00291 /**
00292  * @brief   Kernel-unlock action.
00293  * @details Usually this function just enables interrupts but may perform
00294  *          more actions.
00295  */
00296 #define port_unlock() asm volatile ("cpsie   i" : : : "memory")
00297 
00298 /**
00299  * @brief   Kernel-lock action from an interrupt handler.
00300  * @details This function is invoked before invoking I-class APIs from
00301  *          interrupt handlers. The implementation is architecture dependent,
00302  *          in its simplest form it is void.
00303  * @note    Same as @p port_lock() in this port.
00304  */
00305 #define port_lock_from_isr() port_lock()
00306 
00307 /**
00308  * @brief   Kernel-unlock action from an interrupt handler.
00309  * @details This function is invoked after invoking I-class APIs from interrupt
00310  *          handlers. The implementation is architecture dependent, in its
00311  *          simplest form it is void.
00312  * @note    Same as @p port_lock() in this port.
00313  */
00314 #define port_unlock_from_isr() port_unlock()
00315 
00316 /**
00317  * @brief   Disables all the interrupt sources.
00318  */
00319 #define port_disable() asm volatile ("cpsid   i" : : : "memory")
00320 
00321 /**
00322  * @brief   Disables the interrupt sources below kernel-level priority.
00323  */
00324 #define port_suspend() asm volatile ("cpsid   i" : : : "memory")
00325 
00326 /**
00327  * @brief   Enables all the interrupt sources.
00328  */
00329 #define port_enable() asm volatile ("cpsie   i" : : : "memory")
00330 
00331 /**
00332  * @brief   Enters an architecture-dependent IRQ-waiting mode.
00333  * @details The function is meant to return when an interrupt becomes pending.
00334  *          The simplest implementation is an empty function or macro but this
00335  *          would not take advantage of architecture-specific power saving
00336  *          modes.
00337  * @note    Implemented as an inlined @p WFI instruction.
00338  */
00339 #if CORTEX_ENABLE_WFI_IDLE || defined(__DOXYGEN__)
00340 #define port_wait_for_interrupt() asm volatile ("wfi" : : : "memory")
00341 #else
00342 #define port_wait_for_interrupt()
00343 #endif
00344 
00345 /**
00346  * @brief   Performs a context switch between two threads.
00347  * @details This is the most critical code in any port, this function
00348  *          is responsible for the context switch between 2 threads.
00349  * @note    The implementation of this code affects <b>directly</b> the context
00350  *          switch performance so optimize here as much as you can.
00351  *
00352  * @param[in] ntp       the thread to be switched in
00353  * @param[in] otp       the thread to be switched out
00354  */
00355 #if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
00356 #define port_switch(ntp, otp) _port_switch(ntp, otp)
00357 #else
00358 #define port_switch(ntp, otp) {                                             \
00359   register struct intctx *r13 asm ("r13");                                  \
00360   if ((stkalign_t *)(r13 - 1) < otp->p_stklimit)                            \
00361     chDbgPanic("stack overflow");                                           \
00362   _port_switch(ntp, otp);                                                   \
00363 }
00364 #endif
00365 
00366 #ifdef __cplusplus
00367 extern "C" {
00368 #endif
00369   void port_halt(void);
00370   void _port_irq_epilogue(regarm_t lr);
00371   void _port_switch_from_isr(void);
00372   void _port_exit_from_isr(void);
00373   void _port_switch(Thread *ntp, Thread *otp);
00374   void _port_thread_start(void);
00375 #ifdef __cplusplus
00376 }
00377 #endif
00378 
00379 #endif /* _FROM_ASM_ */
00380 
00381 #endif /* _CHCORE_V6M_H_ */
00382 
00383 /** @} */