frame.h

Go to the documentation of this file.
00001 
00045 #ifndef CPU_FRAME_H
00046 #define CPU_FRAME_H
00047 
00048 #include <cpu/detect.h>
00049 
00050 #include "cfg/cfg_arch.h"      /* ARCH_EMUL */
00051 #include <cfg/compiler.h>      /* for uintXX_t */
00052 
00053 #if CPU_X86
00054 
00055     #define CPU_SAVED_REGS_CNT      7
00056     #define CPU_STACK_GROWS_UPWARD  0
00057     #define CPU_SP_ON_EMPTY_SLOT    0
00058 
00059 #elif CPU_ARM
00060 
00061     #define CPU_SAVED_REGS_CNT     10
00062     #define CPU_STACK_GROWS_UPWARD 0
00063     #define CPU_SP_ON_EMPTY_SLOT   0
00064 
00077     #define CPU_REG_INIT_VALUE(reg) \
00078     ({  int a = 0; \
00079         if(reg == 0) \
00080             a = (int)proc_exit; \
00081         else if(reg == (CPU_SAVED_REGS_CNT - 1)) \
00082             a = 0x13; \
00083         a; \
00084     })
00085 
00086 #elif CPU_PPC
00087 
00088     #define CPU_SAVED_REGS_CNT     1
00089     #define CPU_STACK_GROWS_UPWARD 0
00090     #define CPU_SP_ON_EMPTY_SLOT   1
00091 
00092 #elif CPU_DSP56K
00093 
00094     #define CPU_SAVED_REGS_CNT      8
00095     #define CPU_STACK_GROWS_UPWARD  1
00096     #define CPU_SP_ON_EMPTY_SLOT    0
00097 
00098 #elif CPU_AVR
00099 
00100     #define CPU_SAVED_REGS_CNT     19
00101     #define CPU_STACK_GROWS_UPWARD  0
00102     #define CPU_SP_ON_EMPTY_SLOT    1
00103 
00110     #define CPU_REG_INIT_VALUE(reg) (reg == 0 ? 0x80 : 0)
00111 
00112 #else
00113     #error No CPU_... defined.
00114 #endif
00115 
00116 #ifndef CPU_STACK_GROWS_UPWARD
00117     #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
00118 #endif
00119 
00120 #ifndef CPU_SP_ON_EMPTY_SLOT
00121     #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
00122 #endif
00123 
00125 #ifndef CPU_REG_INIT_VALUE
00126     #define CPU_REG_INIT_VALUE(reg)     0
00127 #endif
00128 
00129 /*
00130  * Support stack handling peculiarities of a few CPUs.
00131  *
00132  * Most processors let their stack grow downward and
00133  * keep SP pointing at the last pushed value.
00134  */
00135 #if !CPU_STACK_GROWS_UPWARD
00136     #if !CPU_SP_ON_EMPTY_SLOT
00137         /* Most microprocessors (x86, m68k...) */
00138         #define CPU_PUSH_WORD(sp, data) \
00139             do { *--(sp) = (data); } while (0)
00140         #define CPU_POP_WORD(sp) \
00141             (*(sp)++)
00142     #else
00143         /* AVR insanity */
00144         #define CPU_PUSH_WORD(sp, data) \
00145             do { *(sp)-- = (data); } while (0)
00146         #define CPU_POP_WORD(sp) \
00147             (*++(sp))
00148     #endif
00149 
00150 #else /* CPU_STACK_GROWS_UPWARD */
00151 
00152     #if !CPU_SP_ON_EMPTY_SLOT
00153         /* DSP56K and other weirdos */
00154         #define CPU_PUSH_WORD(sp, data) \
00155             do { *++(sp) = (cpu_stack_t)(data); } while (0)
00156         #define CPU_POP_WORD(sp) \
00157             (*(sp)--)
00158     #else
00159         #error I bet you cannot find a CPU like this
00160     #endif
00161 #endif
00162 
00163 
00164 #if CPU_DSP56K
00165     /*
00166      * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
00167      * RTS discards SR while returning (it does not restore it). So we push
00168      * 0 to fake the same context.
00169      */
00170     #define CPU_PUSH_CALL_FRAME(sp, func) \
00171         do { \
00172             CPU_PUSH_WORD((sp), (func)); \
00173             CPU_PUSH_WORD((sp), 0x100); \
00174         } while (0);
00175 
00176 #elif CPU_AVR
00177     /*
00178      * On AVR, addresses are pushed into the stack as little-endian, while
00179      * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
00180      * no natural endianess).
00181      */
00182     #define CPU_PUSH_CALL_FRAME(sp, func) \
00183         do { \
00184             uint16_t funcaddr = (uint16_t)(func); \
00185             CPU_PUSH_WORD((sp), funcaddr); \
00186             CPU_PUSH_WORD((sp), funcaddr>>8); \
00187         } while (0)
00188 
00189     /*
00190      * If the kernel is in idle-spinning, the processor executes:
00191      *
00192      * IRQ_ENABLE;
00193      * CPU_IDLE;
00194      * IRQ_DISABLE;
00195      *
00196      * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli".
00197      * We could define CPU_IDLE to expand to none, so the resulting
00198      * asm code would be:
00199      *
00200      * sei;
00201      * cli;
00202      *
00203      * But Atmel datasheet states:
00204      * "When using the SEI instruction to enable interrupts,
00205      * the instruction following SEI will be executed *before*
00206      * any pending interrupts", so "cli" is executed before any
00207      * pending interrupt with the result that IRQs will *NOT*
00208      * be enabled!
00209      * To ensure that IRQ will run a NOP is required.
00210      */
00211     #define CPU_IDLE NOP
00212 
00213 #elif CPU_PPC
00214 
00215     #define CPU_PUSH_CALL_FRAME(sp, func) \
00216         do { \
00217             CPU_PUSH_WORD((sp), (cpu_stack_t)(func)); /* LR -> 8(SP) */ \
00218             CPU_PUSH_WORD((sp), 0);                  /* CR -> 4(SP) */ \
00219         } while (0)
00220 
00221 #else
00222     #define CPU_PUSH_CALL_FRAME(sp, func) \
00223         CPU_PUSH_WORD((sp), (cpu_stack_t)(func))
00224 #endif
00225 
00235 #ifndef CPU_IDLE
00236     #if defined(ARCH_QT) && (ARCH & ARCH_QT)
00237         /* This emulator hook should yield the CPU to the host.  */
00238         EXTERN_C_BEGIN
00239         void emul_idle(void);
00240         EXTERN_C_END
00241         #define CPU_IDLE emul_idle()
00242     #else /* !ARCH_EMUL */
00243         #define CPU_IDLE do { /* nothing */ } while (0)
00244     #endif /* !ARCH_EMUL */
00245 #endif /* !CPU_IDLE */
00246 
00247 #endif /* CPU_ATTR_H */