source: rtems/cpukit/score/cpu/powerpc/rtems/score/cpu.h @ b4f43549

4.104.114.84.95
Last change on this file since b4f43549 was b4f43549, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/16/05 at 17:05:47

(CPU_STACK_MINIMUM_SIZE, CPU_ALIGNMENT, CPU_HEAP_ALIGNMENT, CPU_PARTITION_ALIGNMENT, CPU_STACK_ALIGNMENT): Add.

  • Property mode set to 100644
File size: 14.7 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/*
65 *  Should be large enough to run all RTEMS tests.  This insures
66 *  that a "reasonable" small application should not have any problems.
67 */
68
69#define CPU_STACK_MINIMUM_SIZE          (1024*8)
70
71/*
72 *  CPU's worst alignment requirement for data types on a byte boundary.  This
73 *  alignment does not take into account the requirements for the stack.
74 */
75
76#define CPU_ALIGNMENT              (PPC_ALIGNMENT)
77
78/*
79 *  This number corresponds to the byte alignment requirement for the
80 *  heap handler.  This alignment requirement may be stricter than that
81 *  for the data types alignment specified by CPU_ALIGNMENT.  It is
82 *  common for the heap to follow the same alignment requirement as
83 *  CPU_ALIGNMENT.  If the CPU_ALIGNMENT is strict enough for the heap,
84 *  then this should be set to CPU_ALIGNMENT.
85 *
86 *  NOTE:  This does not have to be a power of 2.  It does have to
87 *         be greater or equal to than CPU_ALIGNMENT.
88 */
89
90#define CPU_HEAP_ALIGNMENT         (PPC_ALIGNMENT)
91
92/*
93 *  This number corresponds to the byte alignment requirement for memory
94 *  buffers allocated by the partition manager.  This alignment requirement
95 *  may be stricter than that for the data types alignment specified by
96 *  CPU_ALIGNMENT.  It is common for the partition to follow the same
97 *  alignment requirement as CPU_ALIGNMENT.  If the CPU_ALIGNMENT is strict
98 *  enough for the partition, then this should be set to CPU_ALIGNMENT.
99 *
100 *  NOTE:  This does not have to be a power of 2.  It does have to
101 *         be greater or equal to than CPU_ALIGNMENT.
102 */
103
104#define CPU_PARTITION_ALIGNMENT    (PPC_ALIGNMENT)
105
106/*
107 *  This number corresponds to the byte alignment requirement for the
108 *  stack.  This alignment requirement may be stricter than that for the
109 *  data types alignment specified by CPU_ALIGNMENT.  If the CPU_ALIGNMENT
110 *  is strict enough for the stack, then this should be set to 0.
111 *
112 *  NOTE:  This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
113 */
114
115#define CPU_STACK_ALIGNMENT        (PPC_STACK_ALIGNMENT)
116
117
118#ifndef ASM
119/*  The following routine swaps the endian format of an unsigned int.
120 *  It must be static because it is referenced indirectly.
121 *
122 *  This version will work on any processor, but if there is a better
123 *  way for your CPU PLEASE use it.  The most common way to do this is to:
124 *
125 *     swap least significant two bytes with 16-bit rotate
126 *     swap upper and lower 16-bits
127 *     swap most significant two bytes with 16-bit rotate
128 *
129 *  Some CPUs have special instructions which swap a 32-bit quantity in
130 *  a single instruction (e.g. i486).  It is probably best to avoid
131 *  an "endian swapping control bit" in the CPU.  One good reason is
132 *  that interrupts would probably have to be disabled to insure that
133 *  an interrupt does not try to access the same "chunk" with the wrong
134 *  endian.  Another good reason is that on some CPUs, the endian bit
135 *  endianness for ALL fetches -- both code and data -- so the code
136 *  will be fetched incorrectly.
137 */
138 
139static inline uint32_t CPU_swap_u32(
140  uint32_t value
141)
142{
143  uint32_t   swapped;
144 
145  asm volatile("rlwimi %0,%1,8,24,31;"
146               "rlwimi %0,%1,24,16,23;"
147               "rlwimi %0,%1,8,8,15;"
148               "rlwimi %0,%1,24,0,7;" :
149               "=&r" ((swapped)) : "r" ((value)));
150
151  return( swapped );
152}
153
154#define CPU_swap_u16( value ) \
155  (((value&0xff) << 8) | ((value >> 8)&0xff))
156
157#endif /* ASM */
158
159#ifndef ASM
160/*
161 *  Macros to access PowerPC specific additions to the CPU Table
162 */
163
164#define rtems_cpu_configuration_get_clicks_per_usec() \
165   (_CPU_Table.clicks_per_usec)
166
167#define rtems_cpu_configuration_get_exceptions_in_ram() \
168   (_CPU_Table.exceptions_in_RAM)
169
170#endif /* ASM */
171
172#ifndef ASM
173/*
174 *  Simple spin delay in microsecond units for device drivers.
175 *  This is very dependent on the clock speed of the target.
176 */
177
178#define CPU_Get_timebase_low( _value ) \
179    asm volatile( "mftb  %0" : "=r" (_value) )
180
181#define rtems_bsp_delay( _microseconds ) \
182  do { \
183    uint32_t   start, ticks, now; \
184    CPU_Get_timebase_low( start ) ; \
185    ticks = (_microseconds) * rtems_cpu_configuration_get_clicks_per_usec(); \
186    do \
187      CPU_Get_timebase_low( now ) ; \
188    while (now - start < ticks); \
189  } while (0)
190
191#define rtems_bsp_delay_in_bus_cycles( _cycles ) \
192  do { \
193    uint32_t   start, now; \
194    CPU_Get_timebase_low( start ); \
195    do \
196      CPU_Get_timebase_low( now ); \
197    while (now - start < (_cycles)); \
198  } while (0)
199
200#endif /* ASM */
201
202#ifndef ASM
203/*
204 *  Routines to access the decrementer register
205 */
206
207#define PPC_Set_decrementer( _clicks ) \
208  do { \
209    asm volatile( "mtdec %0" : : "r" ((_clicks)) ); \
210  } while (0)
211
212#define PPC_Get_decrementer( _clicks ) \
213    asm volatile( "mfdec  %0" : "=r" (_clicks) )
214
215#endif /* ASM */
216
217#ifndef ASM
218/*
219 *  Routines to access the time base register
220 */
221
222static inline uint64_t PPC_Get_timebase_register( void )
223{
224  uint32_t tbr_low;
225  uint32_t tbr_high;
226  uint32_t tbr_high_old;
227  uint64_t tbr;
228
229  do {
230    asm volatile( "mftbu %0" : "=r" (tbr_high_old));
231    asm volatile( "mftb  %0" : "=r" (tbr_low));
232    asm volatile( "mftbu %0" : "=r" (tbr_high));
233  } while ( tbr_high_old != tbr_high );
234
235  tbr = tbr_high;
236  tbr <<= 32;
237  tbr |= tbr_low;
238  return tbr;
239}
240
241static inline  void PPC_Set_timebase_register (uint64_t tbr)
242{
243  uint32_t tbr_low;
244  uint32_t tbr_high;
245
246  tbr_low = (tbr & 0xffffffff) ;
247  tbr_high = (tbr >> 32) & 0xffffffff;
248  asm volatile( "mtspr 284, %0" : : "r" (tbr_low));
249  asm volatile( "mtspr 285, %0" : : "r" (tbr_high));
250 
251}
252#endif /* ASM */
253
254#ifndef ASM
255/* Context handler macros */
256
257/*
258 *  Initialize the context to a state suitable for starting a
259 *  task after a context restore operation.  Generally, this
260 *  involves:
261 *
262 *     - setting a starting address
263 *     - preparing the stack
264 *     - preparing the stack and frame pointers
265 *     - setting the proper interrupt level in the context
266 *     - initializing the floating point context
267 *
268 *  This routine generally does not set any unnecessary register
269 *  in the context.  The state of the "general data" registers is
270 *  undefined at task start time.
271 */
272
273void _CPU_Context_Initialize(
274  Context_Control  *the_context,
275  uint32_t         *stack_base,
276  uint32_t          size,
277  uint32_t          new_level,
278  void             *entry_point,
279  boolean           is_fp
280);
281
282/*
283 *  This routine is responsible for somehow restarting the currently
284 *  executing task.  If you are lucky, then all that is necessary
285 *  is restoring the context.  Otherwise, there will need to be
286 *  a special assembly routine which does something special in this
287 *  case.  Context_Restore should work most of the time.  It will
288 *  not work if restarting self conflicts with the stack frame
289 *  assumptions of restoring a context.
290 */
291
292#define _CPU_Context_Restart_self( _the_context ) \
293   _CPU_Context_restore( (_the_context) );
294
295/*
296 *  The purpose of this macro is to allow the initial pointer into
297 *  a floating point context area (used to save the floating point
298 *  context) to be at an arbitrary place in the floating point
299 *  context area.
300 *
301 *  This is necessary because some FP units are designed to have
302 *  their context saved as a stack which grows into lower addresses.
303 *  Other FP units can be saved by simply moving registers into offsets
304 *  from the base of the context area.  Finally some FP units provide
305 *  a "dump context" instruction which could fill in from high to low
306 *  or low to high based on the whim of the CPU designers.
307 */
308
309#define _CPU_Context_Fp_start( _base, _offset ) \
310   ( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
311
312/*
313 *  This routine initializes the FP context area passed to it to.
314 *  There are a few standard ways in which to initialize the
315 *  floating point context.  The code included for this macro assumes
316 *  that this is a CPU in which a "initial" FP context was saved into
317 *  _CPU_Null_fp_context and it simply copies it to the destination
318 *  context passed to it.
319 *
320 *  Other models include (1) not doing anything, and (2) putting
321 *  a "null FP status word" in the correct place in the FP context.
322 */
323
324#define _CPU_Context_Initialize_fp( _destination ) \
325  { \
326   ((Context_Control_fp *) *((void **) _destination))->fpscr = PPC_INIT_FPSCR; \
327  }
328
329/* end of Context handler macros */
330#endif /* ASM */
331
332#ifndef ASM
333/* Bitfield handler macros */
334
335/*
336 *  This routine sets _output to the bit number of the first bit
337 *  set in _value.  _value is of CPU dependent type Priority_Bit_map_control.
338 *  This type may be either 16 or 32 bits wide although only the 16
339 *  least significant bits will be used.
340 *
341 *  There are a number of variables in using a "find first bit" type
342 *  instruction.
343 *
344 *    (1) What happens when run on a value of zero?
345 *    (2) Bits may be numbered from MSB to LSB or vice-versa.
346 *    (3) The numbering may be zero or one based.
347 *    (4) The "find first bit" instruction may search from MSB or LSB.
348 *
349 *  RTEMS guarantees that (1) will never happen so it is not a concern.
350 *  (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
351 *  _CPU_Priority_Bits_index().  These three form a set of routines
352 *  which must logically operate together.  Bits in the _value are
353 *  set and cleared based on masks built by _CPU_Priority_mask().
354 *  The basic major and minor values calculated by _Priority_Major()
355 *  and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
356 *  to properly range between the values returned by the "find first bit"
357 *  instruction.  This makes it possible for _Priority_Get_highest() to
358 *  calculate the major and directly index into the minor table.
359 *  This mapping is necessary to ensure that 0 (a high priority major/minor)
360 *  is the first bit found.
361 *
362 *  This entire "find first bit" and mapping process depends heavily
363 *  on the manner in which a priority is broken into a major and minor
364 *  components with the major being the 4 MSB of a priority and minor
365 *  the 4 LSB.  Thus (0 << 4) + 0 corresponds to priority 0 -- the highest
366 *  priority.  And (15 << 4) + 14 corresponds to priority 254 -- the next
367 *  to the lowest priority.
368 *
369 *  If your CPU does not have a "find first bit" instruction, then
370 *  there are ways to make do without it.  Here are a handful of ways
371 *  to implement this in software:
372 *
373 *    - a series of 16 bit test instructions
374 *    - a "binary search using if's"
375 *    - _number = 0
376 *      if _value > 0x00ff
377 *        _value >>=8
378 *        _number = 8;
379 *
380 *      if _value > 0x0000f
381 *        _value >=8
382 *        _number += 4
383 *
384 *      _number += bit_set_table[ _value ]
385 *
386 *    where bit_set_table[ 16 ] has values which indicate the first
387 *      bit set
388 */
389
390#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
391  { \
392    asm volatile ("cntlzw %0, %1" : "=r" ((_output)), "=r" ((_value)) : \
393                  "1" ((_value))); \
394  }
395
396/* end of Bitfield handler macros */
397
398/*
399 *  This routine builds the mask which corresponds to the bit fields
400 *  as searched by _CPU_Bitfield_Find_first_bit().  See the discussion
401 *  for that routine.
402 */
403
404#define _CPU_Priority_Mask( _bit_number ) \
405  ( 0x80000000 >> (_bit_number) )
406
407/*
408 *  This routine translates the bit numbers returned by
409 *  _CPU_Bitfield_Find_first_bit() into something suitable for use as
410 *  a major or minor component of a priority.  See the discussion
411 *  for that routine.
412 */
413
414#define _CPU_Priority_bits_index( _priority ) \
415  (_priority)
416
417/* end of Priority handler macros */
418#endif /* ASM */
419
420/* functions */
421
422#ifndef ASM
423
424/*
425 *  _CPU_Initialize
426 *
427 *  This routine performs CPU dependent initialization.
428 */
429
430void _CPU_Initialize(
431  rtems_cpu_table  *cpu_table,
432  void            (*thread_dispatch)
433);
434
435/*
436 *  _CPU_ISR_install_vector
437 *
438 *  This routine installs an interrupt vector.
439 */
440
441void _CPU_ISR_install_vector(
442  uint32_t    vector,
443  proc_ptr    new_handler,
444  proc_ptr   *old_handler
445);
446
447/*
448 *  _CPU_Install_interrupt_stack
449 *
450 *  This routine installs the hardware interrupt stack pointer.
451 *
452 *  NOTE:  It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK
453 *         is TRUE.
454 */
455
456void _CPU_Install_interrupt_stack( void );
457
458/*
459 *  _CPU_Context_switch
460 *
461 *  This routine switches from the run context to the heir context.
462 */
463
464void _CPU_Context_switch(
465  Context_Control  *run,
466  Context_Control  *heir
467);
468
469/*
470 *  _CPU_Context_restore
471 *
472 *  This routine is generallu used only to restart self in an
473 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
474 *
475 *  NOTE: May be unnecessary to reload some registers.
476 */
477
478void _CPU_Context_restore(
479  Context_Control *new_context
480);
481
482/*
483 *  _CPU_Context_save_fp
484 *
485 *  This routine saves the floating point context passed to it.
486 */
487
488void _CPU_Context_save_fp(
489  void **fp_context_ptr
490);
491
492/*
493 *  _CPU_Context_restore_fp
494 *
495 *  This routine restores the floating point context passed to it.
496 */
497
498void _CPU_Context_restore_fp(
499  void **fp_context_ptr
500);
501
502void _CPU_Fatal_error(
503  uint32_t   _error
504);
505
506#endif /* ASM */
507
508#endif /* _RTEMS_SCORE_CPU_H */
Note: See TracBrowser for help on using the repository browser.