BeRTOS
|
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 */