BeRTOS
cpu/irq.h
Go to the documentation of this file.
00001 
00041 #ifndef CPU_IRQ_H
00042 #define CPU_IRQ_H
00043 
00044 #include "detect.h"
00045 #include "types.h"
00046 
00047 #include <kern/proc.h> /* proc_needPreempt() / proc_preempt() */
00048 
00049 #include <cfg/compiler.h> /* for uintXX_t */
00050 #include "cfg/cfg_proc.h" /* CONFIG_KERN_PREEMPT */
00051 
00052 #if CPU_I196
00053     #define IRQ_DISABLE             disable_interrupt()
00054     #define IRQ_ENABLE              enable_interrupt()
00055 #elif CPU_X86
00056 
00057     /* Get IRQ_* definitions from the hosting environment. */
00058     #include <cfg/os.h>
00059     #if OS_EMBEDDED
00060         #define IRQ_DISABLE             FIXME
00061         #define IRQ_ENABLE              FIXME
00062         #define IRQ_SAVE_DISABLE(x)     FIXME
00063         #define IRQ_RESTORE(x)          FIXME
00064     #endif /* OS_EMBEDDED */
00065 
00066 #elif CPU_CM3
00067     /* Cortex-M3 */
00068 
00069     /*
00070      * Interrupt priority.
00071      *
00072      * NOTE: 0 means that an interrupt is not affected by the global IRQ
00073      * priority settings.
00074      */
00075     #define IRQ_PRIO            0x80
00076     #define IRQ_PRIO_MIN        0xf0
00077     #define IRQ_PRIO_MAX        0
00078     /*
00079      * To disable interrupts we just raise the system base priority to a
00080      * number lower than the default IRQ priority. In this way, all the
00081      * "normal" interrupt can't be triggered. High-priority interrupt can
00082      * still happen (at the moment only the soft-interrupt svcall uses a
00083      * priority greater than the default IRQ priority).
00084      *
00085      * To enable interrupts we set the system base priority to 0, that
00086      * means IRQ priority mechanism is disabled, and any interrupt can
00087      * happen.
00088      */
00089     #define IRQ_PRIO_DISABLED   0x40
00090     #define IRQ_PRIO_ENABLED    0
00091 
00092     #ifdef __IAR_SYSTEMS_ICC__
00093         INLINE cpu_flags_t CPU_READ_FLAGS(void)
00094         {
00095             return __get_BASEPRI();
00096         }
00097 
00098         INLINE void CPU_WRITE_FLAGS(cpu_flags_t flags)
00099         {
00100             __set_BASEPRI(flags);
00101         }
00102 
00103         extern uint32_t CPU_READ_IPSR(void);
00104         extern bool irq_running(void);
00105 
00106         #define IRQ_DISABLE CPU_WRITE_FLAGS(IRQ_PRIO_DISABLED)
00107 
00108         #define IRQ_ENABLE  CPU_WRITE_FLAGS(IRQ_PRIO_ENABLED)
00109 
00110         #define IRQ_SAVE_DISABLE(x)                 \
00111         do {                                \
00112             x = CPU_READ_FLAGS();                   \
00113             IRQ_DISABLE;                        \
00114         } while (0)
00115 
00116         #define IRQ_RESTORE(x)                      \
00117         do {                                \
00118             CPU_WRITE_FLAGS(x);                 \
00119         } while (0)
00120     #else /* !__IAR_SYSTEMS_ICC__ */
00121         #define IRQ_DISABLE                     \
00122         ({                              \
00123             register cpu_flags_t reg = IRQ_PRIO_DISABLED;       \
00124             asm volatile (                      \
00125                 "msr basepri, %0"               \
00126                 : : "r"(reg) : "memory", "cc");         \
00127         })
00128 
00129         #define IRQ_ENABLE                      \
00130         ({                              \
00131             register cpu_flags_t reg = IRQ_PRIO_ENABLED;        \
00132             asm volatile (                      \
00133                 "msr basepri, %0"               \
00134                 : : "r"(reg) : "memory", "cc");         \
00135         })
00136 
00137         #define CPU_READ_FLAGS()                    \
00138         ({                              \
00139             register cpu_flags_t reg;               \
00140             asm volatile (                      \
00141                 "mrs %0, basepri"               \
00142                  : "=r"(reg) : : "memory", "cc");       \
00143             reg;                            \
00144         })
00145 
00146         #define IRQ_SAVE_DISABLE(x)                 \
00147         ({                              \
00148             x = CPU_READ_FLAGS();                   \
00149             IRQ_DISABLE;                        \
00150         })
00151 
00152         #define IRQ_RESTORE(x)                      \
00153         ({                              \
00154             asm volatile (                      \
00155                 "msr basepri, %0"               \
00156                 : : "r"(x) : "memory", "cc");           \
00157         })
00158 
00159         INLINE bool irq_running(void)
00160         {
00161             register uint32_t ret;
00162 
00163             /*
00164              * Check if the current stack pointer is the main stack or
00165              * process stack: we use the main stack only in Handler mode,
00166              * so this means we're running inside an ISR.
00167              */
00168             asm volatile (
00169                 "mrs %0, msp\n\t"
00170                 "cmp sp, %0\n\t"
00171                 "ite ne\n\t"
00172                 "movne %0, #0\n\t"
00173                 "moveq %0, #1\n\t" : "=r"(ret) : : "cc");
00174             return ret;
00175         }
00176     #endif /* __IAR_SYSTEMS_ICC__ */
00177 
00178     #define IRQ_ENABLED() (CPU_READ_FLAGS() == IRQ_PRIO_ENABLED)
00179 
00180     #define IRQ_RUNNING() irq_running()
00181 
00182     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00183 
00184         #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00185         void func(void);                    \
00186         INLINE void __isr_##func(void);             \
00187         void func(void)                     \
00188         {                           \
00189             __isr_##func();                 \
00190             if (!proc_needPreempt())            \
00191                 return;                 \
00192             /*
00193              * Set a PendSV request.
00194              *
00195              * The preemption handler will be called immediately
00196              * after this ISR in tail-chaining mode (without the
00197              * overhead of hardware state saving and restoration
00198              * between interrupts).
00199              */                     \
00200             HWREG(NVIC_INT_CTRL) = NVIC_INT_CTRL_PEND_SV;   \
00201         }                           \
00202         INLINE void __isr_##func(void)
00203 
00214         #if CONFIG_KERN_PRI
00215             #define DECLARE_ISR(func) \
00216                 DECLARE_ISR_CONTEXT_SWITCH(func)
00217 
00221             #define ISR_PROTO(func) \
00222                 ISR_PROTO_CONTEXT_SWITCH(func)
00223         #endif /* !CONFIG_KERN_PRI */
00224     #endif
00225 
00226     #ifndef ISR_PROTO
00227         #define ISR_PROTO(func) void func(void)
00228     #endif
00229     #ifndef DECLARE_ISR
00230         #define DECLARE_ISR(func) void func(void)
00231     #endif
00232     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00233         #define DECLARE_ISR_CONTEXT_SWITCH(func) void func(void)
00234     #endif
00235     #ifndef ISR_PROTO_CONTEXT_SWITCH
00236         #define ISR_PROTO_CONTEXT_SWITCH(func) void func(void)
00237     #endif
00238 
00239 #elif CPU_ARM
00240 
00241     #ifdef __IAR_SYSTEMS_ICC__
00242 
00243         #include <inarm.h>
00244 
00245         #if __CPU_MODE__ == 1 /* Thumb */
00246             /* Use stubs */
00247             extern cpu_flags_t get_CPSR(void);
00248             extern void set_CPSR(cpu_flags_t flags);
00249         #else
00250             #define get_CPSR __get_CPSR
00251             #define set_CPSR __set_CPSR
00252         #endif
00253 
00254         #define IRQ_DISABLE __disable_interrupt()
00255         #define IRQ_ENABLE  __enable_interrupt()
00256 
00257         #define IRQ_SAVE_DISABLE(x) \
00258         do { \
00259             (x) = get_CPSR(); \
00260             __disable_interrupt(); \
00261         } while (0)
00262 
00263         #define IRQ_RESTORE(x) \
00264         do { \
00265             set_CPSR(x); \
00266         } while (0)
00267 
00268         #define IRQ_ENABLED() \
00269             ((bool)(get_CPSR() & 0xb0))
00270 
00271     #else /* !__IAR_SYSTEMS_ICC__ */
00272 
00273         #define IRQ_DISABLE                 \
00274         do {                            \
00275             cpu_flags_t sreg;               \
00276             asm volatile (                  \
00277                 "mrs %0, cpsr\n\t"          \
00278                 "orr %0, %0, #0xc0\n\t"         \
00279                 "msr cpsr_c, %0\n\t"            \
00280                 : "=r" (sreg) : : "memory", "cc");  \
00281         } while (0)
00282 
00283         #define IRQ_ENABLE                  \
00284         do {                            \
00285             cpu_flags_t sreg;               \
00286             asm volatile (                  \
00287                 "mrs %0, cpsr\n\t"          \
00288                 "bic %0, %0, #0xc0\n\t"         \
00289                 "msr cpsr_c, %0\n\t"            \
00290                 : "=r" (sreg) : : "memory", "cc");  \
00291         } while (0)
00292 
00293         #define IRQ_SAVE_DISABLE(x)             \
00294         do {                            \
00295             register cpu_flags_t sreg;          \
00296             asm volatile (                  \
00297                 "mrs %0, cpsr\n\t"          \
00298                 "orr %1, %0, #0xc0\n\t"         \
00299                 "msr cpsr_c, %1\n\t"            \
00300                 : "=r" (x), "=r" (sreg)         \
00301                 : : "memory", "cc");            \
00302         } while (0)
00303 
00304         #define IRQ_RESTORE(x)                  \
00305         do {                            \
00306             asm volatile (                  \
00307                 "msr cpsr_c, %0\n\t"            \
00308                 : : "r" (x) : "memory", "cc");      \
00309         } while (0)
00310 
00311         #define CPU_READ_FLAGS()                \
00312         ({                          \
00313             cpu_flags_t sreg;               \
00314             asm volatile (                  \
00315                 "mrs %0, cpsr\n\t"          \
00316                 : "=r" (sreg) : : "memory", "cc");  \
00317             sreg;                       \
00318         })
00319 
00320         #define IRQ_ENABLED() ((CPU_READ_FLAGS() & 0xc0) != 0xc0)
00321 
00322         #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00323             EXTERN_C void asm_irq_switch_context(void);
00324 
00331             #define IRQ_ENTRY() asm volatile ( \
00332                         "sub    lr, lr, #4\n\t" \
00333                         "stmfd  sp!, {r0-r3, ip, lr}\n\t")
00334             #define IRQ_EXIT()  asm volatile ( \
00335                         "b  asm_irq_switch_context\n\t")
00336 
00346             #define ISR_FUNC __attribute__((naked))
00347 
00374             #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00375                 void ISR_FUNC func(void);           \
00376                 static NOINLINE void __isr_##func(void);    \
00377                 void ISR_FUNC func(void)            \
00378                 {                       \
00379                     IRQ_ENTRY();                \
00380                     IRQ_DISABLE;                \
00381                     __isr_##func();             \
00382                     IRQ_EXIT();             \
00383                 }                       \
00384                 static NOINLINE void __isr_##func(void)
00385 
00389             #define ISR_PROTO_CONTEXT_SWITCH(func)  \
00390                 void ISR_FUNC func(void)
00391 
00401             #if CONFIG_KERN_PRI
00402                 #define DECLARE_ISR(func) \
00403                     DECLARE_ISR_CONTEXT_SWITCH(func)
00404 
00405                 #define ISR_PROTO(func) \
00406                     ISR_PROTO_CONTEXT_SWITCH(func)
00407             #endif /* !CONFIG_KERN_PRI */
00408         #endif /* CONFIG_KERN_PREEMPT */
00409 
00410         #ifndef ISR_FUNC
00411             #define ISR_FUNC __attribute__((naked))
00412         #endif
00413         #ifndef DECLARE_ISR
00414             #define DECLARE_ISR(func) \
00415                 void ISR_FUNC func(void);               \
00416                 /*                          \
00417                  * FIXME: avoid the inlining of this function.      \
00418                  *                          \
00419                  * This is terribly inefficient, but it's a     \
00420                  * reliable workaround to avoid gcc blowing     \
00421                  * away the stack (see the bug below):          \
00422                  *                          \
00423                  * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41999    \
00424                  */                         \
00425                 static NOINLINE void __isr_##func(void);        \
00426                 void ISR_FUNC func(void)                \
00427                 {                           \
00428                     asm volatile (                  \
00429                         "sub    lr, lr, #4\n\t"         \
00430                         "stmfd  sp!, {r0-r3, ip, lr}\n\t"); \
00431                     __isr_##func();                 \
00432                     asm volatile (                  \
00433                         "ldmfd sp!, {r0-r3, ip, pc}^\n\t"); \
00434                 }                           \
00435                 static NOINLINE void __isr_##func(void)
00436         #endif
00437         #ifndef DECLARE_ISR_CONTEXT_SWITCH
00438             #define DECLARE_ISR_CONTEXT_SWITCH(func) DECLARE_ISR(func)
00439         #endif
00440         #ifndef ISR_PROTO
00441             #define ISR_PROTO(func) void ISR_FUNC func(void)
00442         #endif
00443         #ifndef ISR_PROTO_CONTEXT_SWITCH
00444             #define ISR_PROTO_CONTEXT_SWITCH(func) ISR_PROTO(func)
00445         #endif
00446 
00447     #endif /* !__IAR_SYSTEMS_ICC_ */
00448 
00449 #elif CPU_PPC
00450 
00451     /* Get IRQ_* definitions from the hosting environment. */
00452     #include <cfg/os.h>
00453     #if OS_EMBEDDED
00454         #define IRQ_DISABLE         FIXME
00455         #define IRQ_ENABLE          FIXME
00456         #define IRQ_SAVE_DISABLE(x) FIXME
00457         #define IRQ_RESTORE(x)      FIXME
00458         #define IRQ_ENABLED()       FIXME
00459     #endif /* OS_EMBEDDED */
00460 
00461 #elif CPU_DSP56K
00462 
00463     #define IRQ_DISABLE             do { asm(bfset #0x0200,SR); asm(nop); } while (0)
00464     #define IRQ_ENABLE              do { asm(bfclr #0x0200,SR); asm(nop); } while (0)
00465 
00466     #define IRQ_SAVE_DISABLE(x)  \
00467         do { (void)x; asm(move SR,x); asm(bfset #0x0200,SR); } while (0)
00468     #define IRQ_RESTORE(x)  \
00469         do { (void)x; asm(move x,SR); } while (0)
00470 
00471     static inline bool irq_running(void)
00472     {
00473         extern void *user_sp;
00474         return !!user_sp;
00475     }
00476     #define IRQ_RUNNING() irq_running()
00477 
00478     static inline bool irq_enabled(void)
00479     {
00480         uint16_t x;
00481         asm(move SR,x);
00482         return !(x & 0x0200);
00483     }
00484     #define IRQ_ENABLED() irq_enabled()
00485 
00486 #elif CPU_AVR
00487 
00488     #define IRQ_DISABLE   asm volatile ("cli" ::)
00489     #define IRQ_ENABLE    asm volatile ("sei" ::)
00490 
00491     #define IRQ_SAVE_DISABLE(x) \
00492     do { \
00493         __asm__ __volatile__( \
00494             "in %0,__SREG__\n\t" \
00495             "cli" \
00496             : "=r" (x) : /* no inputs */ : "cc" \
00497         ); \
00498     } while (0)
00499 
00500     #define IRQ_RESTORE(x) \
00501     do { \
00502         __asm__ __volatile__( \
00503             "out __SREG__,%0" : /* no outputs */ : "r" (x) : "cc" \
00504         ); \
00505     } while (0)
00506 
00507     #define IRQ_ENABLED() \
00508     ({ \
00509         uint8_t sreg; \
00510         __asm__ __volatile__( \
00511             "in %0,__SREG__\n\t" \
00512             : "=r" (sreg)  /* no inputs & no clobbers */ \
00513         ); \
00514         (bool)(sreg & 0x80); \
00515     })
00516     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00517         #define DECLARE_ISR_CONTEXT_SWITCH(vect)        \
00518             INLINE void __isr_##vect(void);         \
00519             ISR(vect)                   \
00520             {                       \
00521                 __isr_##vect();             \
00522                 IRQ_PREEMPT_HANDLER();          \
00523             }                       \
00524             INLINE void __isr_##vect(void)
00525 
00536         #if CONFIG_KERN_PRI
00537             #define DECLARE_ISR(func) \
00538                 DECLARE_ISR_CONTEXT_SWITCH(func)
00539 
00543             #define ISR_PROTO(func) \
00544                 ISR_PROTO_CONTEXT_SWITCH(func)
00545         #endif /* !CONFIG_KERN_PRI */
00546     #endif
00547 
00548     #ifndef ISR_PROTO
00549         #define ISR_PROTO(vect) ISR(vect)
00550     #endif
00551     #ifndef DECLARE_ISR
00552         #define DECLARE_ISR(vect) ISR(vect)
00553     #endif
00554     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00555         #define DECLARE_ISR_CONTEXT_SWITCH(vect) ISR(vect)
00556     #endif
00557     #ifndef ISR_PROTO_CONTEXT_SWITCH
00558         #define ISR_PROTO_CONTEXT_SWITCH(vect) ISR(vect)
00559     #endif
00560 
00561 #elif CPU_MSP430
00562 
00563     /* Get the compiler defined macros */
00564     #include <signal.h>
00565     #define IRQ_DISABLE         dint()
00566     #define IRQ_ENABLE          eint()
00567 
00568 #else
00569     #error No CPU_... defined.
00570 #endif
00571 
00572 #ifdef IRQ_RUNNING
00573 
00574     #define ASSERT_IRQ_CONTEXT()  ASSERT(IRQ_RUNNING())
00575 
00577     #define ASSERT_USER_CONTEXT() ASSERT(!IRQ_RUNNING())
00578 #else
00579     #define IRQ_RUNNING()   false
00580     #define ASSERT_USER_CONTEXT()  do {} while(0)
00581     #define ASSERT_IRQ_CONTEXT()   do {} while(0)
00582 #endif
00583 
00584 #ifdef IRQ_ENABLED
00585 
00586     #define IRQ_ASSERT_ENABLED()  ASSERT(IRQ_ENABLED())
00587 
00589     #define IRQ_ASSERT_DISABLED() ASSERT(!IRQ_ENABLED())
00590 #else
00591     #define IRQ_ASSERT_ENABLED() do {} while(0)
00592     #define IRQ_ASSERT_DISABLED() do {} while(0)
00593 #endif
00594 
00595 
00596 #ifndef IRQ_PREEMPT_HANDLER
00597     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00598 
00601         INLINE void IRQ_PREEMPT_HANDLER(void)
00602         {
00603             if (proc_needPreempt())
00604                 proc_preempt();
00605         }
00606     #else
00607         #define IRQ_PREEMPT_HANDLER() /* Nothing */
00608     #endif
00609 #endif
00610 
00616 #define ATOMIC(CODE) \
00617     do { \
00618         cpu_flags_t __flags; \
00619         IRQ_SAVE_DISABLE(__flags); \
00620         CODE; \
00621         IRQ_RESTORE(__flags); \
00622     } while (0)
00623 
00624 #endif /* CPU_IRQ_H */