source: rtems/cpukit/score/cpu/powerpc/rtems/score/cpu.h @ 6b25a47

4.104.114.84.95
Last change on this file since 6b25a47 was 6b25a47, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/15/05 at 15:25:29

(_CPU_Context_Initialize, _CPU_Context_Restart_self, _CPU_Context_Fp_start, _CPU_Context_Initialize_fp): New.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2 * @file rtems/score/cpu.h
3 */
4
5/*
6 * $Id$
7 */
8 
9#ifndef _RTEMS_SCORE_CPU_H
10#define _RTEMS_SCORE_CPU_H
11
12#include <rtems/score/powerpc.h>              /* pick up machine definitions */
13#ifndef ASM
14#include <rtems/score/types.h>
15#endif
16
17/* conditional compilation parameters */
18
19/*
20 *  Should the calls to _Thread_Enable_dispatch be inlined?
21 *
22 *  If TRUE, then they are inlined.
23 *  If FALSE, then a subroutine call is made.
24 *
25 *  Basically this is an example of the classic trade-off of size
26 *  versus speed.  Inlining the call (TRUE) typically increases the
27 *  size of RTEMS while speeding up the enabling of dispatching.
28 *  [NOTE: In general, the _Thread_Dispatch_disable_level will
29 *  only be 0 or 1 unless you are in an interrupt handler and that
30 *  interrupt handler invokes the executive.]  When not inlined
31 *  something calls _Thread_Enable_dispatch which in turns calls
32 *  _Thread_Dispatch.  If the enable dispatch is inlined, then
33 *  one subroutine call is avoided entirely.]
34 */
35
36#define CPU_INLINE_ENABLE_DISPATCH       FALSE
37
38/*
39 *  Should the body of the search loops in _Thread_queue_Enqueue_priority
40 *  be unrolled one time?  In unrolled each iteration of the loop examines
41 *  two "nodes" on the chain being searched.  Otherwise, only one node
42 *  is examined per iteration.
43 *
44 *  If TRUE, then the loops are unrolled.
45 *  If FALSE, then the loops are not unrolled.
46 *
47 *  The primary factor in making this decision is the cost of disabling
48 *  and enabling interrupts (_ISR_Flash) versus the cost of rest of the
49 *  body of the loop.  On some CPUs, the flash is more expensive than
50 *  one iteration of the loop body.  In this case, it might be desirable
51 *  to unroll the loop.  It is important to note that on some CPUs, this
52 *  code is the longest interrupt disable period in RTEMS.  So it is
53 *  necessary to strike a balance when setting this parameter.
54 */
55
56#define CPU_UNROLL_ENQUEUE_PRIORITY      FALSE
57
58#ifdef _OLD_EXCEPTIONS
59#include <rtems/old-exceptions/cpu.h>
60#else
61#include <rtems/new-exceptions/cpu.h>
62#endif
63
64#ifndef ASM
65/*  The following routine swaps the endian format of an unsigned int.
66 *  It must be static because it is referenced indirectly.
67 *
68 *  This version will work on any processor, but if there is a better
69 *  way for your CPU PLEASE use it.  The most common way to do this is to:
70 *
71 *     swap least significant two bytes with 16-bit rotate
72 *     swap upper and lower 16-bits
73 *     swap most significant two bytes with 16-bit rotate
74 *
75 *  Some CPUs have special instructions which swap a 32-bit quantity in
76 *  a single instruction (e.g. i486).  It is probably best to avoid
77 *  an "endian swapping control bit" in the CPU.  One good reason is
78 *  that interrupts would probably have to be disabled to insure that
79 *  an interrupt does not try to access the same "chunk" with the wrong
80 *  endian.  Another good reason is that on some CPUs, the endian bit
81 *  endianness for ALL fetches -- both code and data -- so the code
82 *  will be fetched incorrectly.
83 */
84 
85static inline uint32_t CPU_swap_u32(
86  uint32_t value
87)
88{
89  uint32_t   swapped;
90 
91  asm volatile("rlwimi %0,%1,8,24,31;"
92               "rlwimi %0,%1,24,16,23;"
93               "rlwimi %0,%1,8,8,15;"
94               "rlwimi %0,%1,24,0,7;" :
95               "=&r" ((swapped)) : "r" ((value)));
96
97  return( swapped );
98}
99
100#define CPU_swap_u16( value ) \
101  (((value&0xff) << 8) | ((value >> 8)&0xff))
102
103#endif /* ASM */
104
105#ifndef ASM
106/*
107 *  Macros to access PowerPC specific additions to the CPU Table
108 */
109
110#define rtems_cpu_configuration_get_clicks_per_usec() \
111   (_CPU_Table.clicks_per_usec)
112
113#define rtems_cpu_configuration_get_exceptions_in_ram() \
114   (_CPU_Table.exceptions_in_RAM)
115
116#endif /* ASM */
117
118#ifndef ASM
119/*
120 *  Simple spin delay in microsecond units for device drivers.
121 *  This is very dependent on the clock speed of the target.
122 */
123
124#define CPU_Get_timebase_low( _value ) \
125    asm volatile( "mftb  %0" : "=r" (_value) )
126
127#define rtems_bsp_delay( _microseconds ) \
128  do { \
129    uint32_t   start, ticks, now; \
130    CPU_Get_timebase_low( start ) ; \
131    ticks = (_microseconds) * rtems_cpu_configuration_get_clicks_per_usec(); \
132    do \
133      CPU_Get_timebase_low( now ) ; \
134    while (now - start < ticks); \
135  } while (0)
136
137#define rtems_bsp_delay_in_bus_cycles( _cycles ) \
138  do { \
139    uint32_t   start, now; \
140    CPU_Get_timebase_low( start ); \
141    do \
142      CPU_Get_timebase_low( now ); \
143    while (now - start < (_cycles)); \
144  } while (0)
145
146#endif /* ASM */
147
148#ifndef ASM
149/*
150 *  Routines to access the decrementer register
151 */
152
153#define PPC_Set_decrementer( _clicks ) \
154  do { \
155    asm volatile( "mtdec %0" : : "r" ((_clicks)) ); \
156  } while (0)
157
158#define PPC_Get_decrementer( _clicks ) \
159    asm volatile( "mfdec  %0" : "=r" (_clicks) )
160
161#endif /* ASM */
162
163#ifndef ASM
164/*
165 *  Routines to access the time base register
166 */
167
168static inline uint64_t PPC_Get_timebase_register( void )
169{
170  uint32_t tbr_low;
171  uint32_t tbr_high;
172  uint32_t tbr_high_old;
173  uint64_t tbr;
174
175  do {
176    asm volatile( "mftbu %0" : "=r" (tbr_high_old));
177    asm volatile( "mftb  %0" : "=r" (tbr_low));
178    asm volatile( "mftbu %0" : "=r" (tbr_high));
179  } while ( tbr_high_old != tbr_high );
180
181  tbr = tbr_high;
182  tbr <<= 32;
183  tbr |= tbr_low;
184  return tbr;
185}
186
187static inline  void PPC_Set_timebase_register (uint64_t tbr)
188{
189  uint32_t tbr_low;
190  uint32_t tbr_high;
191
192  tbr_low = (tbr & 0xffffffff) ;
193  tbr_high = (tbr >> 32) & 0xffffffff;
194  asm volatile( "mtspr 284, %0" : : "r" (tbr_low));
195  asm volatile( "mtspr 285, %0" : : "r" (tbr_high));
196 
197}
198#endif /* ASM */
199
200#ifndef ASM
201/* Context handler macros */
202
203/*
204 *  Initialize the context to a state suitable for starting a
205 *  task after a context restore operation.  Generally, this
206 *  involves:
207 *
208 *     - setting a starting address
209 *     - preparing the stack
210 *     - preparing the stack and frame pointers
211 *     - setting the proper interrupt level in the context
212 *     - initializing the floating point context
213 *
214 *  This routine generally does not set any unnecessary register
215 *  in the context.  The state of the "general data" registers is
216 *  undefined at task start time.
217 */
218
219void _CPU_Context_Initialize(
220  Context_Control  *the_context,
221  uint32_t         *stack_base,
222  uint32_t          size,
223  uint32_t          new_level,
224  void             *entry_point,
225  boolean           is_fp
226);
227
228/*
229 *  This routine is responsible for somehow restarting the currently
230 *  executing task.  If you are lucky, then all that is necessary
231 *  is restoring the context.  Otherwise, there will need to be
232 *  a special assembly routine which does something special in this
233 *  case.  Context_Restore should work most of the time.  It will
234 *  not work if restarting self conflicts with the stack frame
235 *  assumptions of restoring a context.
236 */
237
238#define _CPU_Context_Restart_self( _the_context ) \
239   _CPU_Context_restore( (_the_context) );
240
241/*
242 *  The purpose of this macro is to allow the initial pointer into
243 *  a floating point context area (used to save the floating point
244 *  context) to be at an arbitrary place in the floating point
245 *  context area.
246 *
247 *  This is necessary because some FP units are designed to have
248 *  their context saved as a stack which grows into lower addresses.
249 *  Other FP units can be saved by simply moving registers into offsets
250 *  from the base of the context area.  Finally some FP units provide
251 *  a "dump context" instruction which could fill in from high to low
252 *  or low to high based on the whim of the CPU designers.
253 */
254
255#define _CPU_Context_Fp_start( _base, _offset ) \
256   ( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
257
258/*
259 *  This routine initializes the FP context area passed to it to.
260 *  There are a few standard ways in which to initialize the
261 *  floating point context.  The code included for this macro assumes
262 *  that this is a CPU in which a "initial" FP context was saved into
263 *  _CPU_Null_fp_context and it simply copies it to the destination
264 *  context passed to it.
265 *
266 *  Other models include (1) not doing anything, and (2) putting
267 *  a "null FP status word" in the correct place in the FP context.
268 */
269
270#define _CPU_Context_Initialize_fp( _destination ) \
271  { \
272   ((Context_Control_fp *) *((void **) _destination))->fpscr = PPC_INIT_FPSCR; \
273  }
274
275/* end of Context handler macros */
276#endif /* ASM */
277
278#endif /* _RTEMS_SCORE_CPU_H */
Note: See TracBrowser for help on using the repository browser.