source: rtems/bsps/powerpc/include/libcpu/powerpc-utility.h @ 3fe2155

5
Last change on this file since 3fe2155 was 3fe2155, checked in by Sebastian Huber <sebastian.huber@…>, on 02/01/19 at 09:00:36

Remove superfluous <rtems/system.h> includes

  • Property mode set to 100644
File size: 19.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSBSPsPowerPCShared
5 *
6 * @brief General purpose assembler macros, linker command file support and
7 * some inline functions for direct register access.
8 */
9
10/*
11 * Copyright (c) 2008-2015 embedded brains GmbH.
12 *
13 *  embedded brains GmbH
14 *  Dornierstr. 4
15 *  82178 Puchheim
16 *  Germany
17 *  <rtems@embedded-brains.de>
18 *
19 * access function for Device Control Registers inspired by "ppc405common.h"
20 * from Michael Hamel ADInstruments May 2008
21 *
22 * The license and distribution terms for this file may be
23 * found in the file LICENSE in this distribution or at
24 * http://www.rtems.org/license/LICENSE.
25 */
26
27/**
28 * @defgroup RTEMSBSPsPowerPCSharedUtility PowerPC Utility Module
29 *
30 * @ingroup RTEMSBSPsPowerPCShared
31 *
32 * @brief PowerPC Utility Module.
33 *
34 * @{
35 */
36
37#ifndef __LIBCPU_POWERPC_UTILITY_H
38#define __LIBCPU_POWERPC_UTILITY_H
39
40#if !defined(ASM)
41  #include <rtems.h>
42#endif
43
44#include <rtems/score/cpu.h>
45#include <rtems/powerpc/registers.h>
46#include <rtems/powerpc/powerpc.h>
47
48#ifdef __cplusplus
49extern "C" {
50#endif
51
52#if !defined(ASM)
53
54#include <rtems/bspIo.h>
55
56#include <libcpu/cpuIdent.h>
57
58#define LINKER_SYMBOL(sym) extern char sym [];
59
60/**
61 * @brief Read one byte from @a src.
62 */
63static inline uint8_t ppc_read_byte(const volatile void *src)
64{
65  uint8_t value;
66
67  __asm__ volatile (
68    "lbz %0, 0(%1)"
69    : "=r" (value)
70    : "b" (src)
71  );
72
73  return value;
74}
75
76/**
77 * @brief Read one half word from @a src.
78 */
79static inline uint16_t ppc_read_half_word(const volatile void *src)
80{
81  uint16_t value;
82
83  __asm__ volatile (
84    "lhz %0, 0(%1)"
85    : "=r" (value)
86    : "b" (src)
87  );
88
89  return value;
90}
91
92/**
93 * @brief Read one word from @a src.
94 */
95static inline uint32_t ppc_read_word(const volatile void *src)
96{
97  uint32_t value;
98
99  __asm__ volatile (
100    "lwz %0, 0(%1)"
101    : "=r" (value)
102    : "b" (src)
103  );
104
105  return value;
106}
107
108/**
109 * @brief Write one byte @a value to @a dest.
110 */
111static inline void ppc_write_byte(uint8_t value, volatile void *dest)
112{
113  __asm__ volatile (
114    "stb %0, 0(%1)"
115    :
116    : "r" (value), "b" (dest)
117  );
118}
119
120/**
121 * @brief Write one half word @a value to @a dest.
122 */
123static inline void ppc_write_half_word(uint16_t value, volatile void *dest)
124{
125  __asm__ volatile (
126    "sth %0, 0(%1)"
127    :
128    : "r" (value), "b" (dest)
129  );
130}
131
132/**
133 * @brief Write one word @a value to @a dest.
134 */
135static inline void ppc_write_word(uint32_t value, volatile void *dest)
136{
137  __asm__ volatile (
138    "stw %0, 0(%1)" :
139    : "r" (value), "b" (dest)
140  );
141}
142
143
144static inline void *ppc_stack_pointer(void)
145{
146  void *sp;
147
148  __asm__ volatile (
149    "mr %0, 1"
150    : "=r" (sp)
151  );
152
153  return sp;
154}
155
156static inline void ppc_set_stack_pointer(void *sp)
157{
158  __asm__ volatile (
159    "mr 1, %0"
160    :
161    : "r" (sp)
162  );
163}
164
165static inline void *ppc_link_register(void)
166{
167  void *lr;
168
169  __asm__ volatile (
170    "mflr %0"
171    : "=r" (lr)
172  );
173
174  return lr;
175}
176
177static inline void ppc_set_link_register(void *lr)
178{
179  __asm__ volatile (
180    "mtlr %0"
181    :
182    : "r" (lr)
183  );
184}
185
186static inline uint32_t ppc_machine_state_register(void)
187{
188  uint32_t msr;
189
190  __asm__ volatile (
191    "mfmsr %0"
192    : "=r" (msr)
193  );
194
195  return msr;
196}
197
198static inline void ppc_set_machine_state_register(uint32_t msr)
199{
200  __asm__ volatile (
201    "mtmsr %0"
202    :
203    : "r" (msr)
204  );
205}
206
207static inline void ppc_synchronize_data(void)
208{
209  RTEMS_COMPILER_MEMORY_BARRIER();
210
211  __asm__ volatile ("sync");
212}
213
214static inline void ppc_light_weight_synchronize(void)
215{
216  RTEMS_COMPILER_MEMORY_BARRIER();
217
218  __asm__ volatile ("lwsync");
219}
220
221static inline void ppc_synchronize_instructions(void)
222{
223  RTEMS_COMPILER_MEMORY_BARRIER();
224
225  __asm__ volatile ("isync");
226}
227
228static inline void ppc_enforce_in_order_execution_of_io(void)
229{
230  RTEMS_COMPILER_MEMORY_BARRIER();
231
232  __asm__ volatile ("eieio");
233}
234
235static inline void ppc_data_cache_block_flush(void *addr)
236{
237  __asm__ volatile (
238    "dcbf 0, %0"
239    :
240    : "r" (addr)
241    : "memory"
242  );
243}
244
245static inline void ppc_data_cache_block_flush_2(
246  void *base,
247  uintptr_t offset
248)
249{
250  __asm__ volatile (
251    "dcbf %0, %1"
252    :
253    : "b" (base), "r" (offset)
254    : "memory"
255  );
256}
257
258static inline void ppc_data_cache_block_invalidate(void *addr)
259{
260  __asm__ volatile (
261    "dcbi 0, %0"
262    :
263    : "r" (addr)
264    : "memory"
265  );
266}
267
268static inline void ppc_data_cache_block_invalidate_2(
269  void *base,
270  uintptr_t offset
271)
272{
273  __asm__ volatile (
274    "dcbi %0, %1"
275    :
276    : "b" (base), "r" (offset)
277    : "memory"
278  );
279}
280
281static inline void ppc_data_cache_block_store(const void *addr)
282{
283  __asm__ volatile (
284    "dcbst 0, %0"
285    :
286    : "r" (addr)
287  );
288}
289
290static inline void ppc_data_cache_block_store_2(
291  const void *base,
292  uintptr_t offset
293)
294{
295  __asm__ volatile (
296    "dcbst %0, %1"
297    :
298    : "b" (base), "r" (offset)
299  );
300}
301
302static inline void ppc_data_cache_block_touch(const void *addr)
303{
304  __asm__ volatile (
305    "dcbt 0, %0"
306    :
307    : "r" (addr)
308  );
309}
310
311static inline void ppc_data_cache_block_touch_2(
312  const void *base,
313  uintptr_t offset
314)
315{
316  __asm__ volatile (
317    "dcbt %0, %1"
318    :
319    : "b" (base), "r" (offset)
320  );
321}
322
323static inline void ppc_data_cache_block_touch_for_store(const void *addr)
324{
325  __asm__ volatile (
326    "dcbtst 0, %0"
327    :
328    : "r" (addr)
329  );
330}
331
332static inline void ppc_data_cache_block_touch_for_store_2(
333  const void *base,
334  uintptr_t offset
335)
336{
337  __asm__ volatile (
338    "dcbtst %0, %1"
339    :
340    : "b" (base), "r" (offset)
341  );
342}
343
344static inline void ppc_data_cache_block_clear_to_zero(void *addr)
345{
346  __asm__ volatile (
347    "dcbz 0, %0"
348    :
349    : "r" (addr)
350    : "memory"
351  );
352}
353
354static inline void ppc_data_cache_block_clear_to_zero_2(
355  void *base,
356  uintptr_t offset
357)
358{
359  __asm__ volatile (
360    "dcbz %0, %1"
361    :
362    : "b" (base), "r" (offset)
363    : "memory"
364  );
365}
366
367static inline void ppc_instruction_cache_block_invalidate(void *addr)
368{
369  __asm__ volatile (
370    "icbi 0, %0"
371    :
372    : "r" (addr)
373  );
374}
375
376static inline void ppc_instruction_cache_block_invalidate_2(
377  void *base,
378  uintptr_t offset
379)
380{
381  __asm__ volatile (
382    "icbi %0, %1"
383    :
384    : "b" (base), "r" (offset)
385  );
386}
387
388/**
389 * @brief Enables external exceptions.
390 *
391 * You can use this function to enable the external exceptions and restore the
392 * machine state with ppc_external_exceptions_disable() later.
393 */
394static inline uint32_t ppc_external_exceptions_enable(void)
395{
396  uint32_t current_msr;
397  uint32_t new_msr;
398
399  RTEMS_COMPILER_MEMORY_BARRIER();
400
401  __asm__ volatile (
402    "mfmsr %0;"
403    "ori %1, %0, 0x8000;"
404    "mtmsr %1"
405    : "=r" (current_msr), "=r" (new_msr)
406  );
407
408  return current_msr;
409}
410
411/**
412 * @brief Restores machine state.
413 *
414 * @see ppc_external_exceptions_enable()
415 */
416static inline void ppc_external_exceptions_disable(uint32_t msr)
417{
418  ppc_set_machine_state_register(msr);
419
420  RTEMS_COMPILER_MEMORY_BARRIER();
421}
422
423static inline uint32_t ppc_count_leading_zeros(uint32_t value)
424{
425  uint32_t count;
426
427  __asm__ (
428    "cntlzw %0, %1;"
429    : "=r" (count)
430    : "r" (value)
431  );
432
433  return count;
434}
435
436/*
437 *  Simple spin delay in microsecond units for device drivers.
438 *  This is very dependent on the clock speed of the target.
439 */
440
441#if defined(mpx8xx) || defined(mpc860) || defined(mpc821)
442/* Wonderful bookE doesn't have mftb/mftbu; they only
443 * define the TBRU/TBRL SPRs so we use these. Luckily,
444 * we run in supervisory mode so that should work on
445 * all CPUs. In user mode we'd have a problem...
446 * 2007/11/30, T.S.
447 *
448 * OTOH, PSIM currently lacks support for reading
449 * SPRs 268/269. You need GDB patch sim/2376 to avoid
450 * a crash...
451 * OTOH, the MPC8xx do not allow to read the timebase registers via mfspr.
452 * we NEED a mftb to access the time base.
453 * 2009/10/30 Th. D.
454 */
455#define CPU_Get_timebase_low( _value ) \
456    __asm__ volatile( "mftb  %0" : "=r" (_value) )
457#else
458#define CPU_Get_timebase_low( _value ) \
459    __asm__ volatile( "mfspr %0,268" : "=r" (_value) )
460#endif
461
462/* Must be provided for rtems_bsp_delay to work */
463extern     uint32_t bsp_clicks_per_usec;
464
465#define rtems_bsp_delay( _microseconds ) \
466  do { \
467    uint32_t   start, ticks, now; \
468    CPU_Get_timebase_low( start ) ; \
469    ticks = (_microseconds) * bsp_clicks_per_usec; \
470    do \
471      CPU_Get_timebase_low( now ) ; \
472    while (now - start < ticks); \
473  } while (0)
474
475#define rtems_bsp_delay_in_bus_cycles( _cycles ) \
476  do { \
477    uint32_t   start, now; \
478    CPU_Get_timebase_low( start ); \
479    do \
480      CPU_Get_timebase_low( now ); \
481    while (now - start < (_cycles)); \
482  } while (0)
483
484/*
485 *  Routines to access the decrementer register
486 */
487
488#define PPC_Set_decrementer( _clicks ) \
489  do { \
490    __asm__ volatile( "mtdec %0" : : "r" ((_clicks)) ); \
491  } while (0)
492
493#define PPC_Get_decrementer( _clicks ) \
494    __asm__ volatile( "mfdec  %0" : "=r" (_clicks) )
495
496/*
497 *  Routines to access the time base register
498 */
499
500static inline uint64_t PPC_Get_timebase_register( void )
501{
502  uint32_t tbr_low;
503  uint32_t tbr_high;
504  uint32_t tbr_high_old;
505  uint64_t tbr;
506
507  do {
508#if defined(mpx8xx) || defined(mpc860) || defined(mpc821)
509/* See comment above (CPU_Get_timebase_low) */
510    __asm__ volatile( "mftbu %0" : "=r" (tbr_high_old));
511    __asm__ volatile( "mftb  %0" : "=r" (tbr_low));
512    __asm__ volatile( "mftbu %0" : "=r" (tbr_high));
513#else
514    __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high_old));
515    __asm__ volatile( "mfspr %0, 268" : "=r" (tbr_low));
516    __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high));
517#endif
518  } while ( tbr_high_old != tbr_high );
519
520  tbr = tbr_high;
521  tbr <<= 32;
522  tbr |= tbr_low;
523  return tbr;
524}
525
526static inline  void PPC_Set_timebase_register (uint64_t tbr)
527{
528  uint32_t tbr_low;
529  uint32_t tbr_high;
530
531  tbr_low = (uint32_t) tbr;
532  tbr_high = (uint32_t) (tbr >> 32);
533  __asm__ volatile( "mtspr 284, %0" : : "r" (tbr_low));
534  __asm__ volatile( "mtspr 285, %0" : : "r" (tbr_high));
535
536}
537
538static inline uint32_t ppc_decrementer_register(void)
539{
540  uint32_t dec;
541
542  PPC_Get_decrementer(dec);
543
544  return dec;
545}
546
547static inline void ppc_set_decrementer_register(uint32_t dec)
548{
549  PPC_Set_decrementer(dec);
550}
551
552/**
553 * @brief Preprocessor magic for stringification of @a x.
554 */
555#define PPC_STRINGOF(x) #x
556
557/**
558 * @brief Returns the value of the Special Purpose Register with number @a spr.
559 *
560 * @note This macro uses a GNU C extension.
561 */
562#define PPC_SPECIAL_PURPOSE_REGISTER(spr) \
563  ({ \
564    uint32_t val; \
565    __asm__ volatile (\
566      "mfspr %0, " PPC_STRINGOF(spr) \
567      : "=r" (val) \
568    ); \
569    val;\
570  } )
571
572/**
573 * @brief Sets the Special Purpose Register with number @a spr to the value in
574 * @a val.
575 */
576#define PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val) \
577  do { \
578    __asm__ volatile (\
579      "mtspr " PPC_STRINGOF(spr) ", %0" \
580      : \
581      : "r" (val) \
582    ); \
583  } while (0)
584
585/**
586 * @brief Sets in the Special Purpose Register with number @a spr all bits
587 * which are set in @a bits.
588 *
589 * Interrupts are disabled throughout this operation.
590 */
591#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \
592  do { \
593    ISR_Level level; \
594    uint32_t val; \
595    uint32_t mybits = bits; \
596    _ISR_Local_disable(level); \
597    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
598    val |= mybits; \
599    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
600    _ISR_Local_enable(level); \
601  } while (0)
602
603/**
604 * @brief Sets in the Special Purpose Register with number @a spr all bits
605 * which are set in @a bits.  The previous register value will be masked with
606 * @a mask.
607 *
608 * Interrupts are disabled throughout this operation.
609 */
610#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS_MASKED(spr, bits, mask) \
611  do { \
612    ISR_Level level; \
613    uint32_t val; \
614    uint32_t mybits = bits; \
615    uint32_t mymask = mask; \
616    _ISR_Local_disable(level); \
617    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
618    val &= ~mymask; \
619    val |= mybits; \
620    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
621    _ISR_Local_enable(level); \
622  } while (0)
623
624/**
625 * @brief Clears in the Special Purpose Register with number @a spr all bits
626 * which are set in @a bits.
627 *
628 * Interrupts are disabled throughout this operation.
629 */
630#define PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \
631  do { \
632    ISR_Level level; \
633    uint32_t val; \
634    uint32_t mybits = bits; \
635    _ISR_Local_disable(level); \
636    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
637    val &= ~mybits; \
638    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
639    _ISR_Local_enable(level); \
640  } while (0)
641
642/**
643 * @brief Returns the value of the Thread Management Register with number @a tmr.
644 *
645 * @note This macro uses a GNU C extension.
646 */
647#define PPC_THREAD_MGMT_REGISTER(tmr) \
648  ({ \
649    uint32_t val; \
650    __asm__ volatile (\
651      "mftmr %0, " PPC_STRINGOF(tmr) \
652      : "=r" (val) \
653    ); \
654    val;\
655  } )
656
657/**
658 * @brief Sets the Thread Management Register with number @a tmr to the value in
659 * @a val.
660 */
661#define PPC_SET_THREAD_MGMT_REGISTER(tmr, val) \
662  do { \
663    __asm__ volatile (\
664      "mttmr " PPC_STRINGOF(tmr) ", %0" \
665      : \
666      : "r" (val) \
667    ); \
668  } while (0)
669
670/**
671 * @brief Returns the value of the Device Control Register with number @a dcr.
672 *
673 * The PowerPC 4XX family has Device Control Registers.
674 *
675 * @note This macro uses a GNU C extension.
676 */
677#define PPC_DEVICE_CONTROL_REGISTER(dcr) \
678  ({ \
679    uint32_t val; \
680    __asm__ volatile (\
681      "mfdcr %0, " PPC_STRINGOF(dcr) \
682      : "=r" (val) \
683    ); \
684    val;\
685  } )
686
687/**
688 * @brief Sets the Device Control Register with number @a dcr to the value in
689 * @a val.
690 *
691 * The PowerPC 4XX family has Device Control Registers.
692 */
693#define PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val) \
694  do { \
695    __asm__ volatile (\
696      "mtdcr " PPC_STRINGOF(dcr) ", %0" \
697      : \
698      : "r" (val) \
699    ); \
700  } while (0)
701
702/**
703 * @brief Sets in the Device Control Register with number @a dcr all bits
704 * which are set in @a bits.
705 *
706 * Interrupts are disabled throughout this operation.
707 */
708#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \
709  do { \
710    ISR_Level level; \
711    uint32_t val; \
712    uint32_t mybits = bits; \
713    _ISR_Local_disable(level); \
714    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
715    val |= mybits; \
716    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
717    _ISR_Local_enable(level); \
718  } while (0)
719
720/**
721 * @brief Sets in the Device Control Register with number @a dcr all bits
722 * which are set in @a bits.  The previous register value will be masked with
723 * @a mask.
724 *
725 * Interrupts are disabled throughout this operation.
726 */
727#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS_MASKED(dcr, bits, mask) \
728  do { \
729    ISR_Level level; \
730    uint32_t val; \
731    uint32_t mybits = bits; \
732    uint32_t mymask = mask; \
733    _ISR_Local_disable(level); \
734    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
735    val &= ~mymask; \
736    val |= mybits; \
737    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
738    _ISR_Local_enable(level); \
739  } while (0)
740
741/**
742 * @brief Clears in the Device Control Register with number @a dcr all bits
743 * which are set in @a bits.
744 *
745 * Interrupts are disabled throughout this operation.
746 */
747#define PPC_CLEAR_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \
748  do { \
749    ISR_Level level; \
750    uint32_t val; \
751    uint32_t mybits = bits; \
752    _ISR_Local_disable(level); \
753    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
754    val &= ~mybits; \
755    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
756    _ISR_Local_enable(level); \
757  } while (0)
758
759static inline uint32_t ppc_time_base(void)
760{
761  uint32_t val;
762
763  CPU_Get_timebase_low(val);
764
765  return val;
766}
767
768static inline void ppc_set_time_base(uint32_t val)
769{
770  PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWL, val);
771}
772
773static inline uint32_t ppc_time_base_upper(void)
774{
775  return PPC_SPECIAL_PURPOSE_REGISTER(TBRU);
776}
777
778static inline void ppc_set_time_base_upper(uint32_t val)
779{
780  PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWU, val);
781}
782
783static inline uint64_t ppc_time_base_64(void)
784{
785  return PPC_Get_timebase_register();
786}
787
788static inline void ppc_set_time_base_64(uint64_t val)
789{
790  PPC_Set_timebase_register(val);
791}
792
793static inline uint32_t ppc_alternate_time_base(void)
794{
795  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBL);
796}
797
798static inline uint32_t ppc_alternate_time_base_upper(void)
799{
800  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBU);
801}
802
803static inline uint64_t ppc_alternate_time_base_64(void)
804{
805  uint32_t atbl;
806  uint32_t atbu_0;
807  uint32_t atbu_1;
808
809  do {
810    atbu_0 = ppc_alternate_time_base_upper();
811    atbl = ppc_alternate_time_base();
812    atbu_1 = ppc_alternate_time_base_upper();
813  } while (atbu_0 != atbu_1);
814
815  return (((uint64_t) atbu_1) << 32) | ((uint64_t) atbl);
816}
817
818static inline uint32_t ppc_processor_id(void)
819{
820  return PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR);
821}
822
823static inline void ppc_set_processor_id(uint32_t val)
824{
825  PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR, val);
826}
827
828static inline uint32_t ppc_fsl_system_version(void)
829{
830  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_SVR);
831}
832
833static inline uint32_t ppc_fsl_system_version_cid(uint32_t svr)
834{
835  return (svr >> 28) & 0xf;
836}
837
838static inline uint32_t ppc_fsl_system_version_sid(uint32_t svr)
839{
840  return (svr >> 16) & 0xfff;
841}
842
843static inline uint32_t ppc_fsl_system_version_proc(uint32_t svr)
844{
845  return (svr >> 12) & 0xf;
846}
847
848static inline uint32_t ppc_fsl_system_version_mfg(uint32_t svr)
849{
850  return (svr >> 8) & 0xf;
851}
852
853static inline uint32_t ppc_fsl_system_version_mjrev(uint32_t svr)
854{
855  return (svr >> 4) & 0xf;
856}
857
858static inline uint32_t ppc_fsl_system_version_mnrev(uint32_t svr)
859{
860  return (svr >> 0) & 0xf;
861}
862
863void ppc_code_copy(void *dest, const void *src, size_t n);
864
865/* FIXME: Do not use this function */
866void printBAT(int bat, uint32_t upper, uint32_t lower);
867
868/* FIXME: Do not use this function */
869void ShowBATS(void);
870
871#endif /* ifndef ASM */
872
873#if defined(ASM)
874#include <rtems/asm.h>
875
876.macro LA reg, addr
877#if defined(__powerpc64__)
878        lis     \reg, (\addr)@highest
879        ori     \reg, \reg, (\addr)@higher
880        rldicr  \reg, \reg, 32, 31
881        oris    \reg, \reg, (\addr)@h
882        ori     \reg, \reg, (\addr)@l
883#else
884        lis     \reg, (\addr)@h
885        ori     \reg, \reg, (\addr)@l
886#endif
887.endm
888
889.macro LA32 reg, addr
890        lis     \reg, (\addr)@h
891        ori     \reg, \reg, (\addr)@l
892.endm
893
894.macro LWI reg, value
895        lis \reg, (\value)@h
896        ori     \reg, \reg, (\value)@l
897.endm
898
899.macro LW reg, addr
900        lis     \reg, \addr@ha
901        lwz     \reg, \addr@l(\reg)
902.endm
903
904/*
905 * Tests the bits in reg1 against the bits set in mask.  A match is indicated
906 * by EQ = 0 in CR0.  A mismatch is indicated by EQ = 1 in CR0.  The register
907 * reg2 is used to load the mask.
908 */
909.macro  TSTBITS reg1, reg2, mask
910        LWI     \reg2, \mask
911        and     \reg1, \reg1, \reg2
912        cmplw   \reg1, \reg2
913.endm
914
915.macro  SETBITS reg1, reg2, mask
916        LWI     \reg2, \mask
917        or      \reg1, \reg1, \reg2
918.endm
919
920.macro  CLRBITS reg1, reg2, mask
921        LWI     \reg2, \mask
922        andc    \reg1, \reg1, \reg2
923.endm
924
925.macro GLOBAL_FUNCTION name
926        .global \name
927        .type \name, @function
928\name:
929.endm
930
931/*
932 * Obtain interrupt mask
933 */
934.macro GET_INTERRUPT_MASK mask
935        lis     \mask, _PPC_INTERRUPT_DISABLE_MASK@h
936        ori     \mask, \mask, _PPC_INTERRUPT_DISABLE_MASK@l
937.endm
938
939/*
940 * Disables all asynchronous exeptions (interrupts) which may cause a context
941 * switch.
942 */
943.macro INTERRUPT_DISABLE level, mask
944        mfmsr   \level
945        GET_INTERRUPT_MASK mask=\mask
946        andc    \mask, \level, \mask
947        mtmsr   \mask
948.endm
949
950/*
951 * Restore previous machine state.
952 */
953.macro INTERRUPT_ENABLE level
954        mtmsr   \level
955.endm
956
957.macro SET_SELF_CPU_CONTROL reg_0, reg_1
958#if defined(RTEMS_SMP)
959        /* Use Book E Processor ID Register (PIR) */
960        mfspr   \reg_0, 286
961        slwi    \reg_0, \reg_0, PER_CPU_CONTROL_SIZE_LOG2
962#if defined(__powerpc64__)
963        LA      \reg_1, _Per_CPU_Information
964        add     \reg_0, \reg_0, \reg_1
965#else
966        addis   \reg_0, \reg_0, _Per_CPU_Information@ha
967        addi    \reg_0, \reg_0, _Per_CPU_Information@l
968#endif
969        mtspr   PPC_PER_CPU_CONTROL_REGISTER, \reg_0
970#endif
971.endm
972
973.macro GET_SELF_CPU_CONTROL reg
974#if defined(RTEMS_SMP)
975        mfspr   \reg, PPC_PER_CPU_CONTROL_REGISTER
976#else
977        lis     \reg, _Per_CPU_Information@h
978        ori     \reg, \reg, _Per_CPU_Information@l
979#endif
980.endm
981
982.macro SHIFT_RIGHT_IMMEDIATE rd, rs, imm
983#if defined(__powerpc64__)
984        srdi    \rd, \rs, \imm
985#else
986        srwi    \rd, \rs, \imm
987#endif
988.endm
989
990.macro COMPARE_LOGICAL cr, ra, rb
991#if defined(__powerpc64__)
992        cmpld   \cr, \ra, \rb
993#else
994        cmplw   \cr, \ra, \rb
995#endif
996.endm
997
998.macro CLEAR_RIGHT_IMMEDIATE rd, rs, imm
999#if defined(__powerpc64__)
1000        clrrdi  \rd, \rs, \imm
1001#else
1002        clrrwi  \rd, \rs, \imm
1003#endif
1004.endm
1005
1006#define LINKER_SYMBOL(sym) .extern sym
1007
1008#endif /* ASM */
1009
1010#ifdef __cplusplus
1011}
1012#endif
1013
1014/** @} */
1015
1016#endif /* __LIBCPU_POWERPC_UTILITY_H */
Note: See TracBrowser for help on using the repository browser.