BeRTOS
|
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 #if CPU_X86_32 00055 #define CPU_SAVED_REGS_CNT 2 00056 #elif CPU_X86_64 00057 #define CPU_SAVED_REGS_CNT 8 00058 #else 00059 #error "unknown CPU" 00060 #endif 00061 #define CPU_STACK_GROWS_UPWARD 0 00062 #define CPU_SP_ON_EMPTY_SLOT 0 00063 00064 #elif CPU_ARM 00065 00066 #define CPU_SAVED_REGS_CNT 8 00067 #define CPU_STACK_GROWS_UPWARD 0 00068 #define CPU_SP_ON_EMPTY_SLOT 0 00069 00070 #elif CPU_CM3 00071 00072 #define CPU_SAVED_REGS_CNT 8 00073 #define CPU_STACK_GROWS_UPWARD 0 00074 #define CPU_SP_ON_EMPTY_SLOT 0 00075 00076 #elif CPU_PPC 00077 00078 #define CPU_SAVED_REGS_CNT 1 00079 #define CPU_STACK_GROWS_UPWARD 0 00080 #define CPU_SP_ON_EMPTY_SLOT 1 00081 00082 #elif CPU_DSP56K 00083 00084 #define CPU_SAVED_REGS_CNT 8 00085 #define CPU_STACK_GROWS_UPWARD 1 00086 #define CPU_SP_ON_EMPTY_SLOT 0 00087 00088 #elif CPU_AVR 00089 00090 #define CPU_SAVED_REGS_CNT 18 00091 #define CPU_STACK_GROWS_UPWARD 0 00092 #define CPU_SP_ON_EMPTY_SLOT 1 00093 00094 #elif CPU_MSP430 00095 00096 #define CPU_SAVED_REGS_CNT 16 00097 #define CPU_STACK_GROWS_UPWARD 1 00098 #define CPU_SP_ON_EMPTY_SLOT 0 00099 00100 #else 00101 #error No CPU_... defined. 00102 #endif 00103 00104 #ifndef CPU_STACK_GROWS_UPWARD 00105 #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1 00106 #endif 00107 00108 #ifndef CPU_SP_ON_EMPTY_SLOT 00109 #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1 00110 #endif 00111 00113 #ifndef CPU_REG_INIT_VALUE 00114 #define CPU_REG_INIT_VALUE(reg) (reg) 00115 #endif 00116 00117 /* 00118 * Support stack handling peculiarities of a few CPUs. 00119 * 00120 * Most processors let their stack grow downward and 00121 * keep SP pointing at the last pushed value. 00122 */ 00123 #if !CPU_STACK_GROWS_UPWARD 00124 #if !CPU_SP_ON_EMPTY_SLOT 00125 /* Most microprocessors (x86, m68k...) */ 00126 #define CPU_PUSH_WORD(sp, data) \ 00127 do { *--(sp) = (data); } while (0) 00128 #define CPU_POP_WORD(sp) \ 00129 (*(sp)++) 00130 #else 00131 /* AVR insanity */ 00132 #define CPU_PUSH_WORD(sp, data) \ 00133 do { *(sp)-- = (data); } while (0) 00134 #define CPU_POP_WORD(sp) \ 00135 (*++(sp)) 00136 #endif 00137 00138 #else /* CPU_STACK_GROWS_UPWARD */ 00139 00140 #if !CPU_SP_ON_EMPTY_SLOT 00141 /* DSP56K and other weirdos */ 00142 #define CPU_PUSH_WORD(sp, data) \ 00143 do { *++(sp) = (cpu_stack_t)(data); } while (0) 00144 #define CPU_POP_WORD(sp) \ 00145 (*(sp)--) 00146 #else 00147 #error I bet you cannot find a CPU like this 00148 #endif 00149 #endif 00150 00151 00152 #if CPU_DSP56K 00153 /* 00154 * DSP56k pushes both PC and SR to the stack in the JSR instruction, but 00155 * RTS discards SR while returning (it does not restore it). So we push 00156 * 0 to fake the same context. 00157 */ 00158 #define CPU_PUSH_CALL_FRAME(sp, func) \ 00159 do { \ 00160 CPU_PUSH_WORD((sp), (func)); \ 00161 CPU_PUSH_WORD((sp), 0x100); \ 00162 } while (0); 00163 00164 #elif CPU_CM3 00165 00166 #if CONFIG_KERN_PREEMPT 00167 INLINE void cm3_preempt_switch_context(cpu_stack_t **new_sp, cpu_stack_t **old_sp) 00168 { 00169 register cpu_stack_t **__new_sp asm ("r0") = new_sp; 00170 register cpu_stack_t **__old_sp asm ("r1") = old_sp; 00171 00172 asm volatile ("svc #0" 00173 : : "r"(__new_sp), "r"(__old_sp) : "memory", "cc"); 00174 } 00175 #define asm_switch_context cm3_preempt_switch_context 00176 00177 #define CPU_CREATE_NEW_STACK(stack) \ 00178 do { \ 00179 size_t i; \ 00180 /* Initialize process stack frame */ \ 00181 CPU_PUSH_WORD((stack), 0x01000000); /* xPSR */ \ 00182 CPU_PUSH_WORD((stack), (cpu_stack_t)proc_entry); /* pc */ \ 00183 CPU_PUSH_WORD((stack), 0); /* lr */ \ 00184 CPU_PUSH_WORD((stack), 0); /* ip */ \ 00185 CPU_PUSH_WORD((stack), 0); /* r3 */ \ 00186 CPU_PUSH_WORD((stack), 0); /* r2 */ \ 00187 CPU_PUSH_WORD((stack), 0); /* r1 */ \ 00188 CPU_PUSH_WORD((stack), 0); /* r0 */ \ 00189 CPU_PUSH_WORD((stack), 0xfffffffd); /* lr_exc */ \ 00190 /* Push a clean set of CPU registers for asm_switch_context() */ \ 00191 for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \ 00192 CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \ 00193 CPU_PUSH_WORD(stack, IRQ_PRIO_DISABLED); \ 00194 } while (0) 00195 00196 #endif /* CONFIG_KERN_PREEMPT */ 00197 00198 #elif CPU_AVR 00199 /* 00200 * On AVR, addresses are pushed into the stack as little-endian, while 00201 * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is 00202 * no natural endianess). 00203 */ 00204 #define CPU_PUSH_CALL_FRAME(sp, func) \ 00205 do { \ 00206 uint16_t funcaddr = (uint16_t)(func); \ 00207 CPU_PUSH_WORD((sp), funcaddr); \ 00208 CPU_PUSH_WORD((sp), funcaddr>>8); \ 00209 } while (0) 00210 00211 /* 00212 * If the kernel is in idle-spinning, the processor executes: 00213 * 00214 * IRQ_ENABLE; 00215 * CPU_IDLE; 00216 * IRQ_DISABLE; 00217 * 00218 * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli". 00219 * We could define CPU_IDLE to expand to none, so the resulting 00220 * asm code would be: 00221 * 00222 * sei; 00223 * cli; 00224 * 00225 * But Atmel datasheet states: 00226 * "When using the SEI instruction to enable interrupts, 00227 * the instruction following SEI will be executed *before* 00228 * any pending interrupts", so "cli" is executed before any 00229 * pending interrupt with the result that IRQs will *NOT* 00230 * be enabled! 00231 * To ensure that IRQ will run a NOP is required. 00232 */ 00233 #define CPU_IDLE NOP 00234 00235 #elif CPU_PPC 00236 00237 #define CPU_PUSH_CALL_FRAME(sp, func) \ 00238 do { \ 00239 CPU_PUSH_WORD((sp), (cpu_stack_t)(func)); /* LR -> 8(SP) */ \ 00240 CPU_PUSH_WORD((sp), 0); /* CR -> 4(SP) */ \ 00241 } while (0) 00242 00243 #endif 00244 00245 #ifndef CPU_PUSH_CALL_FRAME 00246 #define CPU_PUSH_CALL_FRAME(sp, func) \ 00247 CPU_PUSH_WORD((sp), (cpu_stack_t)(func)) 00248 #endif 00249 00259 #ifndef CPU_IDLE 00260 #define CPU_IDLE PAUSE 00261 #endif /* !CPU_IDLE */ 00262 00266 #ifndef CPU_CREATE_NEW_STACK 00267 00268 #define CPU_CREATE_NEW_STACK(stack) \ 00269 do { \ 00270 size_t i; \ 00271 /* Initialize process stack frame */ \ 00272 CPU_PUSH_CALL_FRAME(stack, proc_entry); \ 00273 /* Push a clean set of CPU registers for asm_switch_context() */ \ 00274 for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \ 00275 CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \ 00276 } while (0) 00277 #endif 00278 00279 #endif /* CPU_ATTR_H */