1 #ifndef CYGONCE_HAL_ARCH_H
2 #define CYGONCE_HAL_ARCH_H
4 //=============================================================================
8 // Architecture specific abstractions
10 //=============================================================================
11 //####ECOSGPLCOPYRIGHTBEGIN####
12 // -------------------------------------------
13 // This file is part of eCos, the Embedded Configurable Operating System.
14 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
15 // Copyright (C) 2004 Gary Thomas
16 // Copyright (C) 2004 Jonathan Larmour <jifl@eCosCentric.com>
18 // eCos is free software; you can redistribute it and/or modify it under
19 // the terms of the GNU General Public License as published by the Free
20 // Software Foundation; either version 2 or (at your option) any later version.
22 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
23 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 // You should have received a copy of the GNU General Public License along
28 // with eCos; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
31 // As a special exception, if other files instantiate templates or use macros
32 // or inline functions from this file, or you compile this file and link it
33 // with other works to produce a work based on this file, this file does not
34 // by itself cause the resulting work to be covered by the GNU General Public
35 // License. However the source code for this file must still be made available
36 // in accordance with section (3) of the GNU General Public License.
38 // This exception does not invalidate any other reasons why a work based on
39 // this file might be covered by the GNU General Public License.
41 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
42 // at http://sources.redhat.com/ecos/ecos-license/
43 // -------------------------------------------
44 //####ECOSGPLCOPYRIGHTEND####
45 //=============================================================================
46 //#####DESCRIPTIONBEGIN####
49 // Contributors: nickg
51 // Purpose: Define architecture abstractions
52 // Usage: #include <cyg/hal/hal_arch.h>
55 //####DESCRIPTIONEND####
57 //=============================================================================
59 #include <pkgconf/hal.h>
60 #include <cyg/infra/cyg_type.h>
62 #include <cyg/hal/ppc_regs.h> // CYGARC_REG_MSR_EE
64 //-----------------------------------------------------------------------------
65 // Processor saved states:
69 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
73 // These are common to all saved states
74 cyg_uint32 d[32]; // Data regs
75 #ifdef CYGHWR_HAL_POWERPC_FPU
76 double f[32]; // Floating point registers
78 cyg_uint32 cr; // Condition Reg
79 cyg_uint32 xer; // XER
80 cyg_uint32 lr; // Link Reg
81 cyg_uint32 ctr; // Count Reg
83 // These are saved for exceptions and interrupts, but may also
84 // be saved in a context switch if thread-aware debugging is enabled.
85 cyg_uint32 msr; // Machine State Reg
86 cyg_uint32 pc; // Program Counter
88 // This marks the limit of state saved during a context switch and
89 // is used to calculate necessary stack allocation for context switches.
90 // It would probably be better to have a union instead...
91 cyg_uint32 context_size[0];
93 // These are only saved for exceptions and interrupts
94 cyg_uint32 vector; // Vector number
96 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
101 //-----------------------------------------------------------------------------
102 // Exception handling function.
103 // This function is defined by the kernel according to this prototype. It is
104 // invoked from the HAL to deal with any CPU exceptions that the HAL does
105 // not want to deal with itself. It usually invokes the kernel's exception
106 // delivery mechanism.
108 externC void cyg_hal_deliver_exception( CYG_WORD code, CYG_ADDRWORD data );
110 //-----------------------------------------------------------------------------
111 // Bit manipulation macros
113 #define HAL_LSBIT_INDEX(index, mask) \
123 #define HAL_MSBIT_INDEX(index, mask) \
124 asm ( "cntlzw %0,%1\n" \
130 //-----------------------------------------------------------------------------
132 #define CYGARC_PPC_STACK_FRAME_SIZE 56 // size of a stack frame
134 //-----------------------------------------------------------------------------
135 // Context Initialization
136 // Initialize the context of a thread.
138 // _sparg_ name of variable containing current sp, will be written with new sp
139 // _thread_ thread object address, passed as argument to entry point
140 // _entry_ entry point address.
141 // _id_ bit pattern used in initializing registers, for debugging.
143 #define HAL_THREAD_INIT_CONTEXT( _sparg_, _thread_, _entry_, _id_ ) \
145 register CYG_WORD _sp_ = (((CYG_WORD)_sparg_) &~15) \
146 - CYGARC_PPC_STACK_FRAME_SIZE; \
147 register HAL_SavedRegisters *_regs_; \
149 ((CYG_WORD *)_sp_)[0] = 0; /* Zero old FP and LR for EABI */ \
150 ((CYG_WORD *)_sp_)[1] = 0; /* to make GDB backtraces sane */ \
151 _regs_ = (HAL_SavedRegisters *)((_sp_) - sizeof(HAL_SavedRegisters)); \
152 for( _i_ = 0; _i_ < 32; _i_++ ) (_regs_)->d[_i_] = (_id_)|_i_; \
153 (_regs_)->d[01] = (CYG_WORD)(_sp_); /* SP = top of stack */ \
154 (_regs_)->d[03] = (CYG_WORD)(_thread_); /* R3 = arg1 = thread ptr */ \
155 (_regs_)->cr = 0; /* CR = 0 */ \
156 (_regs_)->xer = 0; /* XER = 0 */ \
157 (_regs_)->lr = (CYG_WORD)(_entry_); /* LR = entry point */ \
158 (_regs_)->pc = (CYG_WORD)(_entry_); /* set PC for thread dbg */ \
159 (_regs_)->ctr = 0; /* CTR = 0 */ \
160 (_regs_)->msr = CYGARC_REG_MSR_EE; /* MSR = enable irqs */ \
161 _sparg_ = (CYG_ADDRESS)_regs_; \
164 //-----------------------------------------------------------------------------
165 // Context switch macros.
166 // The arguments are pointers to locations where the stack pointer
167 // of the current thread is to be stored, and from where the sp of the
168 // next thread is to be fetched.
170 externC void hal_thread_switch_context( CYG_ADDRESS to, CYG_ADDRESS from );
171 externC void hal_thread_load_context( CYG_ADDRESS to )
172 __attribute__ ((noreturn));
174 #define HAL_THREAD_SWITCH_CONTEXT(_fspptr_,_tspptr_) \
175 hal_thread_switch_context((CYG_ADDRESS)_tspptr_,(CYG_ADDRESS)_fspptr_);
177 #define HAL_THREAD_LOAD_CONTEXT(_tspptr_) \
178 hal_thread_load_context( (CYG_ADDRESS)_tspptr_ );
180 //-----------------------------------------------------------------------------
181 // Execution reorder barrier.
182 // When optimizing the compiler can reorder code. In multithreaded systems
183 // where the order of actions is vital, this can sometimes cause problems.
184 // This macro may be inserted into places where reordering should not happen.
186 #define HAL_REORDER_BARRIER() asm volatile ( "" : : : "memory" )
188 //-----------------------------------------------------------------------------
189 // Breakpoint support
190 // HAL_BREAKPOINT() is a code sequence that will cause a breakpoint to happen
192 // HAL_BREAKINST is the value of the breakpoint instruction and
193 // HAL_BREAKINST_SIZE is its size in bytes.
195 #define HAL_BREAKPOINT(_label_) \
196 asm volatile (" .globl " #_label_ ";" \
201 #define HAL_BREAKINST 0x7d821008
203 #define HAL_BREAKINST_SIZE 4
205 //-----------------------------------------------------------------------------
206 // Thread register state manipulation for GDB support.
208 cyg_uint32 gpr[32]; // General purpose registers
209 double f0[16]; // First sixteen floating point regs
217 #ifdef CYGHWR_HAL_POWERPC_FPU
218 double f16[16]; // Last sixteen floating point regs
219 // Could probably also be inserted in the middle
220 // Adding them at the end minimises the risk of
221 // breaking existing implementations that do not
222 // have floating point registers.
226 // Translate a stack pointer as saved by the thread context macros above into
227 // a pointer to a HAL_SavedRegisters structure.
228 #define HAL_THREAD_GET_SAVED_REGISTERS( _sp_, _regs_ ) \
229 (_regs_) = (HAL_SavedRegisters *)(_sp_)
231 // Copy floating point registers from a HAL_SavedRegisters structure into a
232 // GDB_Registers structure
233 #ifdef CYGHWR_HAL_POWERPC_FPU
234 #define HAL_GET_GDB_FLOATING_POINT_REGISTERS( _gdb_, _regs_ ) \
236 double * _p_ = _gdb_->f0; \
237 double * _q_ = _regs_->f; \
238 for( _i_ = 0; _i_ < 16; _i_++) \
242 for( _i_ = 0; _i_ < 16; _i_++) \
246 #define HAL_GET_GDB_FLOATING_POINT_REGISTERS( _gdb_, _regs_ ) \
251 // Copy a GDB_Registers structure into a HAL_SavedRegisters structure
252 #ifdef CYGHWR_HAL_POWERPC_FPU
253 #define HAL_SET_GDB_FLOATING_POINT_REGISTERS( _regs_, _gdb_) \
255 double * _p_ = _regs_->f; \
256 double * _q_ = _gdb_->f0; \
257 for( _i_ = 0; _i_ < 16; _i_++) \
261 for( _i_ = 0; _i_ < 16; _i_++) \
265 #define HAL_SET_GDB_FLOATING_POINT_REGISTERS( _regs_, _gdb_) \
270 // Copy a set of registers from a HAL_SavedRegisters structure into a
271 // GDB ordered array.
272 #define HAL_GET_GDB_REGISTERS( _aregval_, _regs_ ) \
274 union __gdbreguniontype { \
275 __typeof__(_aregval_) _aregval2_; \
276 GDB_Registers *_gdbr; \
278 __gdbregunion._aregval2_ = (_aregval_); \
279 GDB_Registers *_gdb_ = __gdbregunion._gdbr; \
282 for( _i_ = 0; _i_ < 32; _i_++ ) \
283 _gdb_->gpr[_i_] = (_regs_)->d[_i_]; \
285 _gdb_->pc = (_regs_)->pc; \
286 _gdb_->msr = (_regs_)->msr; \
287 _gdb_->cr = (_regs_)->cr; \
288 _gdb_->lr = (_regs_)->lr; \
289 _gdb_->ctr = (_regs_)->ctr; \
290 _gdb_->xer = (_regs_)->xer; \
291 HAL_GET_GDB_FLOATING_POINT_REGISTERS(_gdb_, _regs_); \
294 // Copy a GDB ordered array into a HAL_SavedRegisters structure.
295 #define HAL_SET_GDB_REGISTERS( _regs_ , _aregval_ ) \
297 union __gdbreguniontype { \
298 __typeof__(_aregval_) _aregval2_; \
299 GDB_Registers *_gdbr; \
301 __gdbregunion._aregval2_ = (_aregval_); \
302 GDB_Registers *_gdb_ = __gdbregunion._gdbr; \
305 for( _i_ = 0; _i_ < 32; _i_++ ) \
306 (_regs_)->d[_i_] = _gdb_->gpr[_i_]; \
308 (_regs_)->pc = _gdb_->pc; \
309 (_regs_)->msr = _gdb_->msr; \
310 (_regs_)->cr = _gdb_->cr; \
311 (_regs_)->lr = _gdb_->lr; \
312 (_regs_)->ctr = _gdb_->ctr; \
313 (_regs_)->xer = _gdb_->xer; \
314 HAL_SET_GDB_FLOATING_POINT_REGISTERS(_regs_, _gdb_); \
317 //-----------------------------------------------------------------------------
342 #ifdef CYGHWR_HAL_POWERPC_FPU
366 #define CYGARC_JMP_BUF_SIZE (sizeof(hal_jmp_buf_t) / sizeof(cyg_uint32))
368 typedef cyg_uint32 hal_jmp_buf[ CYGARC_JMP_BUF_SIZE ];
370 externC int hal_setjmp(hal_jmp_buf env);
371 externC void hal_longjmp(hal_jmp_buf env, int val);
373 //-----------------------------------------------------------------------------
375 // This macro is called in the idle thread loop, and gives the HAL the
376 // chance to insert code. Typical idle thread behaviour might be to halt the
379 externC void hal_idle_thread_action(cyg_uint32 loop_count);
381 #define HAL_IDLE_THREAD_ACTION(_count_) hal_idle_thread_action(_count_)
383 //-----------------------------------------------------------------------------
384 // Minimal and sensible stack sizes: the intention is that applications
385 // will use these to provide a stack size in the first instance prior to
386 // proper analysis. Idle thread stack should be this big.
388 // THESE ARE NOT INTENDED TO BE MICROMETRICALLY ACCURATE FIGURES.
389 // THEY ARE HOWEVER ENOUGH TO START PROGRAMMING.
390 // YOU MUST MAKE YOUR STACKS LARGER IF YOU HAVE LARGE "AUTO" VARIABLES!
392 // This is not a config option because it should not be adjusted except
393 // under "enough rope" sort of disclaimers.
395 // Stack frame overhead per call. The PPC ABI defines regs 13..31 as callee
396 // saved. callee saved variables are irrelevant for us as they would contain
397 // automatic variables, so we only count the caller-saved regs here
398 // So that makes r0..r12 + cr, xer, lr, ctr:
399 #define CYGNUM_HAL_STACK_FRAME_SIZE (4 * 17)
401 // Stack needed for a context switch
402 #define CYGNUM_HAL_STACK_CONTEXT_SIZE \
403 (38*4 /* offsetof(HAL_SavedRegisters, context_size) */)
405 // Interrupt + call to ISR, interrupt_end() and the DSR
406 #define CYGNUM_HAL_STACK_INTERRUPT_SIZE \
407 ((43*4 /* sizeof(HAL_SavedRegisters) */) + 2 * CYGNUM_HAL_STACK_FRAME_SIZE)
409 // We have lots of registers so no particular amount is added in for
410 // typical local variable usage.
412 // We define a minimum stack size as the minimum any thread could ever
413 // legitimately get away with. We can throw asserts if users ask for less
414 // than this. Allow enough for three interrupt sources - clock, serial and
417 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
419 // An interrupt stack which is large enough for all possible interrupt
420 // conditions (and only used for that purpose) exists. "User" stacks
421 // can therefore be much smaller
423 # define CYGNUM_HAL_STACK_SIZE_MINIMUM \
424 (16*CYGNUM_HAL_STACK_FRAME_SIZE + 2*CYGNUM_HAL_STACK_INTERRUPT_SIZE)
428 // No separate interrupt stack exists. Make sure all threads contain
429 // a stack sufficiently large
430 # define CYGNUM_HAL_STACK_SIZE_MINIMUM \
431 (((2+3)*CYGNUM_HAL_STACK_INTERRUPT_SIZE) + \
432 (16*CYGNUM_HAL_STACK_FRAME_SIZE))
435 // Now make a reasonable choice for a typical thread size. Pluck figures
436 // from thin air and say 30 call frames with an average of 16 words of
437 // automatic variables per call frame
438 #define CYGNUM_HAL_STACK_SIZE_TYPICAL \
439 (CYGNUM_HAL_STACK_SIZE_MINIMUM + \
440 30 * (CYGNUM_HAL_STACK_FRAME_SIZE+(16*4)))
442 //--------------------------------------------------------------------------
443 // Macros for switching context between two eCos instances (jump from
444 // code in ROM to code in RAM or vice versa).
446 // Should be defined like for MIPS, saving/restoring R2 - but is it
447 // actually used? I've never seen app code use R2. Something to investigate.
448 #define CYGARC_HAL_SAVE_GP()
449 #define CYGARC_HAL_RESTORE_GP()
451 //-----------------------------------------------------------------------------
452 #endif // CYGONCE_HAL_ARCH_H