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

Last change on this file since a286d28 was a286d28, checked in by Sebastian Huber <sebastian.huber@…>, on 02/25/22 at 20:11:00

powerpc: Use .machine any for some inline asm

  • Property mode set to 100644
File size: 21.0 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 (
233    ".machine \"push\"\n"
234    ".machine \"any\"\n"
235    "eieio\n"
236    ".machine \"pop\""
237  );
238}
239
240static inline void ppc_data_cache_block_flush(void *addr)
241{
242  __asm__ volatile (
243    "dcbf 0, %0"
244    :
245    : "r" (addr)
246    : "memory"
247  );
248}
249
250static inline void ppc_data_cache_block_flush_2(
251  void *base,
252  uintptr_t offset
253)
254{
255  __asm__ volatile (
256    "dcbf %0, %1"
257    :
258    : "b" (base), "r" (offset)
259    : "memory"
260  );
261}
262
263static inline void ppc_data_cache_block_invalidate(void *addr)
264{
265  __asm__ volatile (
266    "dcbi 0, %0"
267    :
268    : "r" (addr)
269    : "memory"
270  );
271}
272
273static inline void ppc_data_cache_block_invalidate_2(
274  void *base,
275  uintptr_t offset
276)
277{
278  __asm__ volatile (
279    "dcbi %0, %1"
280    :
281    : "b" (base), "r" (offset)
282    : "memory"
283  );
284}
285
286static inline void ppc_data_cache_block_store(const void *addr)
287{
288  __asm__ volatile (
289    "dcbst 0, %0"
290    :
291    : "r" (addr)
292  );
293}
294
295static inline void ppc_data_cache_block_store_2(
296  const void *base,
297  uintptr_t offset
298)
299{
300  __asm__ volatile (
301    "dcbst %0, %1"
302    :
303    : "b" (base), "r" (offset)
304  );
305}
306
307static inline void ppc_data_cache_block_touch(const void *addr)
308{
309  __asm__ volatile (
310    "dcbt 0, %0"
311    :
312    : "r" (addr)
313  );
314}
315
316static inline void ppc_data_cache_block_touch_2(
317  const void *base,
318  uintptr_t offset
319)
320{
321  __asm__ volatile (
322    "dcbt %0, %1"
323    :
324    : "b" (base), "r" (offset)
325  );
326}
327
328static inline void ppc_data_cache_block_touch_for_store(const void *addr)
329{
330  __asm__ volatile (
331    "dcbtst 0, %0"
332    :
333    : "r" (addr)
334  );
335}
336
337static inline void ppc_data_cache_block_touch_for_store_2(
338  const void *base,
339  uintptr_t offset
340)
341{
342  __asm__ volatile (
343    "dcbtst %0, %1"
344    :
345    : "b" (base), "r" (offset)
346  );
347}
348
349static inline void ppc_data_cache_block_clear_to_zero(void *addr)
350{
351  __asm__ volatile (
352    "dcbz 0, %0"
353    :
354    : "r" (addr)
355    : "memory"
356  );
357}
358
359static inline void ppc_data_cache_block_clear_to_zero_2(
360  void *base,
361  uintptr_t offset
362)
363{
364  __asm__ volatile (
365    "dcbz %0, %1"
366    :
367    : "b" (base), "r" (offset)
368    : "memory"
369  );
370}
371
372static inline void ppc_instruction_cache_block_invalidate(void *addr)
373{
374  __asm__ volatile (
375    "icbi 0, %0"
376    :
377    : "r" (addr)
378  );
379}
380
381static inline void ppc_instruction_cache_block_invalidate_2(
382  void *base,
383  uintptr_t offset
384)
385{
386  __asm__ volatile (
387    "icbi %0, %1"
388    :
389    : "b" (base), "r" (offset)
390  );
391}
392
393/**
394 * @brief Enables external exceptions.
395 *
396 * You can use this function to enable the external exceptions and restore the
397 * machine state with ppc_external_exceptions_disable() later.
398 */
399static inline uint32_t ppc_external_exceptions_enable(void)
400{
401  uint32_t current_msr;
402  uint32_t new_msr;
403
404  RTEMS_COMPILER_MEMORY_BARRIER();
405
406  __asm__ volatile (
407    "mfmsr %0;"
408    "ori %1, %0, 0x8000;"
409    "mtmsr %1"
410    : "=r" (current_msr), "=r" (new_msr)
411  );
412
413  return current_msr;
414}
415
416/**
417 * @brief Restores machine state.
418 *
419 * @see ppc_external_exceptions_enable()
420 */
421static inline void ppc_external_exceptions_disable(uint32_t msr)
422{
423  ppc_set_machine_state_register(msr);
424
425  RTEMS_COMPILER_MEMORY_BARRIER();
426}
427
428static inline uint32_t ppc_count_leading_zeros(uint32_t value)
429{
430  uint32_t count;
431
432  __asm__ (
433    "cntlzw %0, %1;"
434    : "=r" (count)
435    : "r" (value)
436  );
437
438  return count;
439}
440
441/*
442 *  Simple spin delay in microsecond units for device drivers.
443 *  This is very dependent on the clock speed of the target.
444 */
445
446#if defined(mpx8xx) || defined(mpc860) || defined(mpc821)
447/* Wonderful bookE doesn't have mftb/mftbu; they only
448 * define the TBRU/TBRL SPRs so we use these. Luckily,
449 * we run in supervisory mode so that should work on
450 * all CPUs. In user mode we'd have a problem...
451 * 2007/11/30, T.S.
452 *
453 * OTOH, PSIM currently lacks support for reading
454 * SPRs 268/269. You need GDB patch sim/2376 to avoid
455 * a crash...
456 * OTOH, the MPC8xx do not allow to read the timebase registers via mfspr.
457 * we NEED a mftb to access the time base.
458 * 2009/10/30 Th. D.
459 */
460#define CPU_Get_timebase_low( _value ) \
461    __asm__ volatile( "mftb  %0" : "=r" (_value) )
462#else
463#define CPU_Get_timebase_low( _value ) \
464    __asm__ volatile( "mfspr %0,268" : "=r" (_value) )
465#endif
466
467/* Must be provided for rtems_bsp_delay to work */
468extern     uint32_t bsp_clicks_per_usec;
469
470#define rtems_bsp_delay( _microseconds ) \
471  do { \
472    uint32_t   start, ticks, now; \
473    CPU_Get_timebase_low( start ) ; \
474    ticks = (_microseconds) * bsp_clicks_per_usec; \
475    do \
476      CPU_Get_timebase_low( now ) ; \
477    while (now - start < ticks); \
478  } while (0)
479
480#define rtems_bsp_delay_in_bus_cycles( _cycles ) \
481  do { \
482    uint32_t   start, now; \
483    CPU_Get_timebase_low( start ); \
484    do \
485      CPU_Get_timebase_low( now ); \
486    while (now - start < (_cycles)); \
487  } while (0)
488
489/*
490 *  Routines to access the decrementer register
491 */
492
493#define PPC_Set_decrementer( _clicks ) \
494  do { \
495    __asm__ volatile( "mtdec %0" : : "r" ((_clicks)) ); \
496  } while (0)
497
498#define PPC_Get_decrementer( _clicks ) \
499    __asm__ volatile( "mfdec  %0" : "=r" (_clicks) )
500
501/*
502 *  Routines to access the time base register
503 */
504
505static inline uint64_t PPC_Get_timebase_register( void )
506{
507  uint32_t tbr_low;
508  uint32_t tbr_high;
509  uint32_t tbr_high_old;
510  uint64_t tbr;
511
512  do {
513#if defined(mpx8xx) || defined(mpc860) || defined(mpc821)
514/* See comment above (CPU_Get_timebase_low) */
515    __asm__ volatile( "mftbu %0" : "=r" (tbr_high_old));
516    __asm__ volatile( "mftb  %0" : "=r" (tbr_low));
517    __asm__ volatile( "mftbu %0" : "=r" (tbr_high));
518#else
519    __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high_old));
520    __asm__ volatile( "mfspr %0, 268" : "=r" (tbr_low));
521    __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high));
522#endif
523  } while ( tbr_high_old != tbr_high );
524
525  tbr = tbr_high;
526  tbr <<= 32;
527  tbr |= tbr_low;
528  return tbr;
529}
530
531static inline  void PPC_Set_timebase_register (uint64_t tbr)
532{
533  uint32_t tbr_low;
534  uint32_t tbr_high;
535
536  tbr_low = (uint32_t) tbr;
537  tbr_high = (uint32_t) (tbr >> 32);
538  __asm__ volatile( "mtspr 284, %0" : : "r" (tbr_low));
539  __asm__ volatile( "mtspr 285, %0" : : "r" (tbr_high));
540
541}
542
543static inline uint32_t ppc_decrementer_register(void)
544{
545  uint32_t dec;
546
547  PPC_Get_decrementer(dec);
548
549  return dec;
550}
551
552static inline void ppc_set_decrementer_register(uint32_t dec)
553{
554  PPC_Set_decrementer(dec);
555}
556
557/**
558 * @brief Preprocessor magic for stringification of @a x.
559 */
560#define PPC_STRINGOF(x) #x
561
562/**
563 * @brief Returns the value of the Special Purpose Register with number @a spr.
564 *
565 * @note This macro uses a GNU C extension.
566 */
567#define PPC_SPECIAL_PURPOSE_REGISTER(spr) \
568  ({ \
569    uint32_t val; \
570    __asm__ volatile (\
571      "mfspr %0, " PPC_STRINGOF(spr) \
572      : "=r" (val) \
573    ); \
574    val;\
575  } )
576
577/**
578 * @brief Sets the Special Purpose Register with number @a spr to the value in
579 * @a val.
580 */
581#define PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val) \
582  do { \
583    __asm__ volatile (\
584      "mtspr " PPC_STRINGOF(spr) ", %0" \
585      : \
586      : "r" (val) \
587    ); \
588  } while (0)
589
590/**
591 * @brief Sets in the Special Purpose Register with number @a spr all bits
592 * which are set in @a bits.
593 *
594 * Interrupts are disabled throughout this operation.
595 */
596#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \
597  do { \
598    ISR_Level level; \
599    uint32_t val; \
600    uint32_t mybits = bits; \
601    _ISR_Local_disable(level); \
602    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
603    val |= mybits; \
604    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
605    _ISR_Local_enable(level); \
606  } while (0)
607
608/**
609 * @brief Sets in the Special Purpose Register with number @a spr all bits
610 * which are set in @a bits.  The previous register value will be masked with
611 * @a mask.
612 *
613 * Interrupts are disabled throughout this operation.
614 */
615#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS_MASKED(spr, bits, mask) \
616  do { \
617    ISR_Level level; \
618    uint32_t val; \
619    uint32_t mybits = bits; \
620    uint32_t mymask = mask; \
621    _ISR_Local_disable(level); \
622    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
623    val &= ~mymask; \
624    val |= mybits; \
625    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
626    _ISR_Local_enable(level); \
627  } while (0)
628
629/**
630 * @brief Clears in the Special Purpose Register with number @a spr all bits
631 * which are set in @a bits.
632 *
633 * Interrupts are disabled throughout this operation.
634 */
635#define PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \
636  do { \
637    ISR_Level level; \
638    uint32_t val; \
639    uint32_t mybits = bits; \
640    _ISR_Local_disable(level); \
641    val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \
642    val &= ~mybits; \
643    PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \
644    _ISR_Local_enable(level); \
645  } while (0)
646
647/**
648 * @brief Returns the value of the Thread Management Register with number @a tmr.
649 *
650 * @note This macro uses a GNU C extension.
651 */
652#define PPC_THREAD_MGMT_REGISTER(tmr) \
653  ({ \
654    uint32_t val; \
655    __asm__ volatile (\
656      "mftmr %0, " PPC_STRINGOF(tmr) \
657      : "=r" (val) \
658    ); \
659    val;\
660  } )
661
662/**
663 * @brief Sets the Thread Management Register with number @a tmr to the value in
664 * @a val.
665 */
666#define PPC_SET_THREAD_MGMT_REGISTER(tmr, val) \
667  do { \
668    __asm__ volatile (\
669      "mttmr " PPC_STRINGOF(tmr) ", %0" \
670      : \
671      : "r" (val) \
672    ); \
673  } while (0)
674
675/**
676 * @brief Returns the value of the Device Control Register with number @a dcr.
677 *
678 * The PowerPC 4XX family has Device Control Registers.
679 *
680 * @note This macro uses a GNU C extension.
681 */
682#define PPC_DEVICE_CONTROL_REGISTER(dcr) \
683  ({ \
684    uint32_t val; \
685    __asm__ volatile (\
686      "mfdcr %0, " PPC_STRINGOF(dcr) \
687      : "=r" (val) \
688    ); \
689    val;\
690  } )
691
692/**
693 * @brief Sets the Device Control Register with number @a dcr to the value in
694 * @a val.
695 *
696 * The PowerPC 4XX family has Device Control Registers.
697 */
698#define PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val) \
699  do { \
700    __asm__ volatile (\
701      "mtdcr " PPC_STRINGOF(dcr) ", %0" \
702      : \
703      : "r" (val) \
704    ); \
705  } while (0)
706
707/**
708 * @brief Sets in the Device Control Register with number @a dcr all bits
709 * which are set in @a bits.
710 *
711 * Interrupts are disabled throughout this operation.
712 */
713#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \
714  do { \
715    ISR_Level level; \
716    uint32_t val; \
717    uint32_t mybits = bits; \
718    _ISR_Local_disable(level); \
719    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
720    val |= mybits; \
721    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
722    _ISR_Local_enable(level); \
723  } while (0)
724
725/**
726 * @brief Sets in the Device Control Register with number @a dcr all bits
727 * which are set in @a bits.  The previous register value will be masked with
728 * @a mask.
729 *
730 * Interrupts are disabled throughout this operation.
731 */
732#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS_MASKED(dcr, bits, mask) \
733  do { \
734    ISR_Level level; \
735    uint32_t val; \
736    uint32_t mybits = bits; \
737    uint32_t mymask = mask; \
738    _ISR_Local_disable(level); \
739    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
740    val &= ~mymask; \
741    val |= mybits; \
742    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
743    _ISR_Local_enable(level); \
744  } while (0)
745
746/**
747 * @brief Clears in the Device Control Register with number @a dcr all bits
748 * which are set in @a bits.
749 *
750 * Interrupts are disabled throughout this operation.
751 */
752#define PPC_CLEAR_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \
753  do { \
754    ISR_Level level; \
755    uint32_t val; \
756    uint32_t mybits = bits; \
757    _ISR_Local_disable(level); \
758    val = PPC_DEVICE_CONTROL_REGISTER(dcr); \
759    val &= ~mybits; \
760    PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \
761    _ISR_Local_enable(level); \
762  } while (0)
763
764static inline uint32_t ppc_time_base(void)
765{
766  uint32_t val;
767
768  CPU_Get_timebase_low(val);
769
770  return val;
771}
772
773static inline void ppc_set_time_base(uint32_t val)
774{
775  PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWL, val);
776}
777
778static inline uint32_t ppc_time_base_upper(void)
779{
780  return PPC_SPECIAL_PURPOSE_REGISTER(TBRU);
781}
782
783static inline void ppc_set_time_base_upper(uint32_t val)
784{
785  PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWU, val);
786}
787
788static inline uint64_t ppc_time_base_64(void)
789{
790  return PPC_Get_timebase_register();
791}
792
793static inline void ppc_set_time_base_64(uint64_t val)
794{
795  PPC_Set_timebase_register(val);
796}
797
798static inline uint32_t ppc_alternate_time_base(void)
799{
800  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBL);
801}
802
803static inline uint32_t ppc_alternate_time_base_upper(void)
804{
805  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBU);
806}
807
808static inline uint64_t ppc_alternate_time_base_64(void)
809{
810  uint32_t atbl;
811  uint32_t atbu_0;
812  uint32_t atbu_1;
813
814  do {
815    atbu_0 = ppc_alternate_time_base_upper();
816    atbl = ppc_alternate_time_base();
817    atbu_1 = ppc_alternate_time_base_upper();
818  } while (atbu_0 != atbu_1);
819
820  return (((uint64_t) atbu_1) << 32) | ((uint64_t) atbl);
821}
822
823static inline uint32_t ppc_processor_id(void)
824{
825  return PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR);
826}
827
828static inline void ppc_set_processor_id(uint32_t val)
829{
830  PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR, val);
831}
832
833static inline uint32_t ppc_fsl_system_version(void)
834{
835  return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_SVR);
836}
837
838static inline uint32_t ppc_fsl_system_version_cid(uint32_t svr)
839{
840  return (svr >> 28) & 0xf;
841}
842
843static inline uint32_t ppc_fsl_system_version_sid(uint32_t svr)
844{
845  return (svr >> 16) & 0xfff;
846}
847
848static inline uint32_t ppc_fsl_system_version_proc(uint32_t svr)
849{
850  return (svr >> 12) & 0xf;
851}
852
853static inline uint32_t ppc_fsl_system_version_mfg(uint32_t svr)
854{
855  return (svr >> 8) & 0xf;
856}
857
858static inline uint32_t ppc_fsl_system_version_mjrev(uint32_t svr)
859{
860  return (svr >> 4) & 0xf;
861}
862
863static inline uint32_t ppc_fsl_system_version_mnrev(uint32_t svr)
864{
865  return (svr >> 0) & 0xf;
866}
867
868static inline void ppc_msync(void)
869{
870  __asm__ volatile (
871    ".machine push\n"
872    ".machine e500\n"
873    "msync\n"
874    ".machine pop"
875    :
876    :
877    : "memory"
878  );
879}
880
881static inline void ppc_tlbre(void)
882{
883  __asm__ volatile (
884    ".machine push\n"
885    ".machine e500\n"
886    "tlbre\n"
887    ".machine pop"
888    :
889    :
890    : "memory"
891  );
892}
893
894static inline void ppc_tlbwe(void)
895{
896  __asm__ volatile (
897    ".machine push\n"
898    ".machine e500\n"
899    "tlbwe\n"
900    ".machine pop"
901    :
902    :
903    : "memory"
904  );
905}
906
907static inline void ppc_tlbsx(void *addr)
908{
909  __asm__ volatile (
910    ".machine push\n"
911    ".machine e500\n"
912    "tlbsx 0, %0\n"
913    ".machine pop"
914    :
915    : "r" (addr)
916    : "memory"
917  );
918}
919
920static inline void ppc_mtivpr(void *prefix)
921{
922  __asm__ volatile (
923    ".machine push\n"
924    ".machine e500\n"
925    "mtivpr %0\n"
926    ".machine pop"
927    :
928    : "r" (prefix)
929  );
930}
931
932#define ppc_mtivor(x, vec) __asm__ volatile ( \
933    ".machine push\n" \
934    ".machine e500\n" \
935    "mtivor" RTEMS_XSTRING(x) " %0\n" \
936    ".machine pop" \
937    : \
938    : "r" (vec) \
939  )
940
941void ppc_code_copy(void *dest, const void *src, size_t n);
942
943/* FIXME: Do not use this function */
944void printBAT(int bat, uint32_t upper, uint32_t lower);
945
946/* FIXME: Do not use this function */
947void ShowBATS(void);
948
949#endif /* ifndef ASM */
950
951#if defined(ASM)
952#include <rtems/asm.h>
953
954.macro LA reg, addr
955#if defined(__powerpc64__)
956        lis     \reg, (\addr)@highest
957        ori     \reg, \reg, (\addr)@higher
958        rldicr  \reg, \reg, 32, 31
959        oris    \reg, \reg, (\addr)@h
960        ori     \reg, \reg, (\addr)@l
961#else
962        lis     \reg, (\addr)@h
963        ori     \reg, \reg, (\addr)@l
964#endif
965.endm
966
967.macro LA32 reg, addr
968        lis     \reg, (\addr)@h
969        ori     \reg, \reg, (\addr)@l
970.endm
971
972.macro LWI reg, value
973        lis \reg, (\value)@h
974        ori     \reg, \reg, (\value)@l
975.endm
976
977.macro LW reg, addr
978        lis     \reg, \addr@ha
979        lwz     \reg, \addr@l(\reg)
980.endm
981
982/*
983 * Tests the bits in reg1 against the bits set in mask.  A match is indicated
984 * by EQ = 0 in CR0.  A mismatch is indicated by EQ = 1 in CR0.  The register
985 * reg2 is used to load the mask.
986 */
987.macro  TSTBITS reg1, reg2, mask
988        LWI     \reg2, \mask
989        and     \reg1, \reg1, \reg2
990        cmplw   \reg1, \reg2
991.endm
992
993.macro  SETBITS reg1, reg2, mask
994        LWI     \reg2, \mask
995        or      \reg1, \reg1, \reg2
996.endm
997
998.macro  CLRBITS reg1, reg2, mask
999        LWI     \reg2, \mask
1000        andc    \reg1, \reg1, \reg2
1001.endm
1002
1003.macro GLOBAL_FUNCTION name
1004        .global \name
1005        .type \name, @function
1006\name:
1007.endm
1008
1009/*
1010 * Obtain interrupt mask
1011 */
1012.macro GET_INTERRUPT_MASK mask
1013        lis     \mask, _PPC_INTERRUPT_DISABLE_MASK@h
1014        ori     \mask, \mask, _PPC_INTERRUPT_DISABLE_MASK@l
1015.endm
1016
1017/*
1018 * Disables all asynchronous exeptions (interrupts) which may cause a context
1019 * switch.
1020 */
1021.macro INTERRUPT_DISABLE level, mask
1022        mfmsr   \level
1023        GET_INTERRUPT_MASK mask=\mask
1024        andc    \mask, \level, \mask
1025        mtmsr   \mask
1026.endm
1027
1028/*
1029 * Restore previous machine state.
1030 */
1031.macro INTERRUPT_ENABLE level
1032        mtmsr   \level
1033.endm
1034
1035.macro SET_SELF_CPU_CONTROL reg_0, reg_1
1036#if defined(RTEMS_SMP)
1037        /* Use Book E Processor ID Register (PIR) */
1038        mfspr   \reg_0, 286
1039        slwi    \reg_0, \reg_0, PER_CPU_CONTROL_SIZE_LOG2
1040#if defined(__powerpc64__)
1041        LA      \reg_1, _Per_CPU_Information
1042        add     \reg_0, \reg_0, \reg_1
1043#else
1044        addis   \reg_0, \reg_0, _Per_CPU_Information@ha
1045        addi    \reg_0, \reg_0, _Per_CPU_Information@l
1046#endif
1047        mtspr   PPC_PER_CPU_CONTROL_REGISTER, \reg_0
1048#endif
1049.endm
1050
1051.macro GET_SELF_CPU_CONTROL reg
1052#if defined(RTEMS_SMP)
1053        mfspr   \reg, PPC_PER_CPU_CONTROL_REGISTER
1054#else
1055        lis     \reg, _Per_CPU_Information@h
1056        ori     \reg, \reg, _Per_CPU_Information@l
1057#endif
1058.endm
1059
1060.macro SHIFT_RIGHT_IMMEDIATE rd, rs, imm
1061#if defined(__powerpc64__)
1062        srdi    \rd, \rs, \imm
1063#else
1064        srwi    \rd, \rs, \imm
1065#endif
1066.endm
1067
1068.macro COMPARE_LOGICAL cr, ra, rb
1069#if defined(__powerpc64__)
1070        cmpld   \cr, \ra, \rb
1071#else
1072        cmplw   \cr, \ra, \rb
1073#endif
1074.endm
1075
1076.macro CLEAR_RIGHT_IMMEDIATE rd, rs, imm
1077#if defined(__powerpc64__)
1078        clrrdi  \rd, \rs, \imm
1079#else
1080        clrrwi  \rd, \rs, \imm
1081#endif
1082.endm
1083
1084#define LINKER_SYMBOL(sym) .extern sym
1085
1086#endif /* ASM */
1087
1088#ifdef __cplusplus
1089}
1090#endif
1091
1092/** @} */
1093
1094#endif /* __LIBCPU_POWERPC_UTILITY_H */
Note: See TracBrowser for help on using the repository browser.