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