source: rtems/c/src/lib/libcpu/powerpc/shared/include/powerpc-utility.h @ 602aee20

4.104.115
Last change on this file since 602aee20 was 602aee20, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 10/10/08 at 15:50:15

shared/include/utility.h: Removed file.

shared/include/powerpc-utility.h: Use constraint "b" for address
base registers in inline assembler statements.
Update for status-checks.h changes.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup powerpc_shared
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
12 * Embedded Brains GmbH
13 * Obere Lagerstr. 30
14 * D-82178 Puchheim
15 * Germany
16 * rtems@embedded-brains.de
17 *
18 * access function for Device Control Registers inspired by "ppc405common.h"
19 * from Michael Hamel ADInstruments May 2008
20 *
21 * The license and distribution terms for this file may be found in the file
22 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
23 */
24
25/**
26 * @defgroup powerpc_shared Shared PowerPC Code
27 */
28
29#ifndef LIBCPU_POWERPC_UTILITY_H
30#define LIBCPU_POWERPC_UTILITY_H
31
32#include <rtems/powerpc/registers.h>
33
34#ifndef ASM
35
36#include <stdint.h>
37
38#include <rtems/bspIo.h>
39#include <rtems/system.h>
40#include <rtems/score/cpu.h>
41
42#include <libcpu/cpuIdent.h>
43
44#define LINKER_SYMBOL( sym) extern char sym []
45
46/**
47 * @brief Read one byte from @a src.
48 */
49static inline uint8_t ppc_read_byte( const volatile void *src)
50{
51        uint8_t value;
52
53        asm volatile (
54                "lbz %0, 0(%1)"
55                : "=r" (value)
56                : "b" (src)
57        );
58
59        return value;
60}
61
62/**
63 * @brief Read one half word from @a src.
64 */
65static inline uint16_t ppc_read_half_word( const volatile void *src)
66{
67        uint16_t value;
68
69        asm volatile (
70                "lhz %0, 0(%1)"
71                : "=r" (value)
72                : "b" (src)
73        );
74
75        return value;
76}
77
78/**
79 * @brief Read one word from @a src.
80 */
81static inline uint32_t ppc_read_word( const volatile void *src)
82{
83        uint32_t value;
84
85        asm volatile (
86                "lwz %0, 0(%1)"
87                : "=r" (value)
88                : "b" (src)
89        );
90
91        return value;
92}
93
94/**
95 * @brief Write one byte @a value to @a dest.
96 */
97static inline void ppc_write_byte( uint8_t value, volatile void *dest)
98{
99        asm volatile (
100                "stb %0, 0(%1)"
101                :
102                : "r" (value), "b" (dest)
103        );
104}
105
106/**
107 * @brief Write one half word @a value to @a dest.
108 */
109static inline void ppc_write_half_word( uint16_t value, volatile void *dest)
110{
111        asm volatile (
112                "sth %0, 0(%1)"
113                :
114                : "r" (value), "b" (dest)
115        );
116}
117
118/**
119 * @brief Write one word @a value to @a dest.
120 */
121static inline void ppc_write_word( uint32_t value, volatile void *dest)
122{
123        asm volatile (
124                "stw %0, 0(%1)" :
125                : "r" (value), "b" (dest)
126        );
127}
128
129
130static inline void *ppc_stack_pointer()
131{
132        void *sp;
133
134        asm volatile (
135                "mr %0, 1"
136                : "=r" (sp)
137        );
138
139        return sp;
140}
141
142static inline void ppc_set_stack_pointer( void *sp)
143{
144        asm volatile (
145                "mr 1, %0"
146                :
147                : "r" (sp)
148        );
149}
150
151static inline void *ppc_link_register()
152{
153        void *lr;
154
155        asm volatile (
156                "mflr %0"
157                : "=r" (lr)
158        );
159
160        return lr;
161}
162
163static inline void ppc_set_link_register( void *lr)
164{
165        asm volatile (
166                "mtlr %0"
167                :
168                : "r" (lr)
169        );
170}
171
172static inline uint32_t ppc_machine_state_register()
173{
174        uint32_t msr;
175
176        asm volatile (
177                "mfmsr %0"
178                : "=r" (msr)
179        );
180
181        return msr;
182}
183
184static inline void ppc_set_machine_state_register( uint32_t msr)
185{
186        asm volatile (
187                "mtmsr %0"
188                :
189                : "r" (msr)
190        );
191}
192
193/**
194 * @brief Enables external exceptions.
195 *
196 * You can use this function to enable the external exceptions and restore the
197 * machine state with ppc_external_exceptions_disable() later.
198 */
199static inline uint32_t ppc_external_exceptions_enable()
200{
201        uint32_t current_msr;
202        uint32_t new_msr;
203
204        RTEMS_COMPILER_MEMORY_BARRIER();
205
206        asm volatile (
207                "mfmsr %0;"
208                "ori %1, %0, 0x8000;"
209                "mtmsr %1"
210                : "=r" (current_msr), "=r" (new_msr)
211        );
212
213        return current_msr;
214}
215
216/**
217 * @brief Restores machine state.
218 *
219 * @see ppc_external_exceptions_enable()
220 */
221static inline void ppc_external_exceptions_disable( uint32_t msr)
222{
223        ppc_set_machine_state_register( msr);
224
225        RTEMS_COMPILER_MEMORY_BARRIER();
226}
227
228static inline uint32_t ppc_decrementer_register()
229{
230        uint32_t dec;
231
232        PPC_Get_decrementer( dec);
233
234        return dec;
235}
236
237static inline void ppc_set_decrementer_register( uint32_t dec)
238{
239        PPC_Set_decrementer( dec);
240}
241
242/**
243 * @brief Preprocessor magic for stringification of @a x.
244 */
245#define PPC_STRINGOF( x) #x
246
247/**
248 * @brief Returns the value of the Special Purpose Register with number @a spr.
249 *
250 * @note This macro uses a GNU C extension.
251 */
252#define PPC_SPECIAL_PURPOSE_REGISTER( spr) \
253        ( { \
254                uint32_t val; \
255                asm volatile ( \
256                        "mfspr %0, " PPC_STRINGOF( spr) \
257                        : "=r" (val) \
258                ); \
259                val;\
260        } )
261
262/**
263 * @brief Sets the Special Purpose Register with number @a spr to the value in
264 * @a val.
265 */
266#define PPC_SET_SPECIAL_PURPOSE_REGISTER( spr, val) \
267        do { \
268                asm volatile ( \
269                        "mtspr " PPC_STRINGOF( spr) ", %0" \
270                        : \
271                        : "r" (val) \
272                ); \
273        } while (0)
274
275/**
276 * @brief Sets in the Special Purpose Register with number @a spr all bits
277 * which are set in @a bits.
278 *
279 * Interrupts are disabled throughout this operation.
280 */
281#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( spr, bits) \
282        do { \
283                rtems_interrupt_level level; \
284                uint32_t val; \
285                uint32_t mybits = bits; \
286                rtems_interrupt_disable( level); \
287                val = PPC_SPECIAL_PURPOSE_REGISTER( spr); \
288                val |= mybits; \
289                PPC_SET_SPECIAL_PURPOSE_REGISTER( spr, val); \
290                rtems_interrupt_enable( level); \
291        } while (0)
292
293/**
294 * @brief Sets in the Special Purpose Register with number @a spr all bits
295 * which are set in @a bits.  The previous register value will be masked with
296 * @a mask.
297 *
298 * Interrupts are disabled throughout this operation.
299 */
300#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS_MASKED( spr, bits, mask) \
301        do { \
302                rtems_interrupt_level level; \
303                uint32_t val; \
304                uint32_t mybits = bits; \
305                uint32_t mymask = mask; \
306                rtems_interrupt_disable( level); \
307                val = PPC_SPECIAL_PURPOSE_REGISTER( spr); \
308                val &= ~mymask; \
309                val |= mybits; \
310                PPC_SET_SPECIAL_PURPOSE_REGISTER( spr, val); \
311                rtems_interrupt_enable( level); \
312        } while (0)
313
314/**
315 * @brief Clears in the Special Purpose Register with number @a spr all bits
316 * which are set in @a bits.
317 *
318 * Interrupts are disabled throughout this operation.
319 */
320#define PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS( spr, bits) \
321        do { \
322                rtems_interrupt_level level; \
323                uint32_t val; \
324                uint32_t mybits = bits; \
325                rtems_interrupt_disable( level); \
326                val = PPC_SPECIAL_PURPOSE_REGISTER( spr); \
327                val &= ~mybits; \
328                PPC_SET_SPECIAL_PURPOSE_REGISTER( spr, val); \
329                rtems_interrupt_enable( level); \
330        } while (0)
331
332/**
333 * @brief Returns the value of the Device Control Register with number @a dcr.
334 *
335 * The PowerPC 4XX family has Device Control Registers.
336 *
337 * @note This macro uses a GNU C extension.
338 */
339#define PPC_DEVICE_CONTROL_REGISTER( dcr) \
340        ( { \
341                uint32_t val; \
342                asm volatile ( \
343                        "mfdcr %0, " PPC_STRINGOF( dcr) \
344                        : "=r" (val) \
345                ); \
346                val;\
347        } )
348
349/**
350 * @brief Sets the Device Control Register with number @a dcr to the value in
351 * @a val.
352 *
353 * The PowerPC 4XX family has Device Control Registers.
354 */
355#define PPC_SET_DEVICE_CONTROL_REGISTER( dcr, val) \
356        do { \
357                asm volatile ( \
358                        "mtdcr " PPC_STRINGOF( dcr) ", %0" \
359                        : \
360                        : "r" (val) \
361                ); \
362        } while (0)
363
364/**
365 * @brief Sets in the Device Control Register with number @a dcr all bits
366 * which are set in @a bits.
367 *
368 * Interrupts are disabled throughout this operation.
369 */
370#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS( dcr, bits) \
371        do { \
372                rtems_interrupt_level level; \
373                uint32_t val; \
374                uint32_t mybits = bits; \
375                rtems_interrupt_disable( level); \
376                val = PPC_DEVICE_CONTROL_REGISTER( dcr); \
377                val |= mybits; \
378                PPC_SET_DEVICE_CONTROL_REGISTER( dcr, val); \
379                rtems_interrupt_enable( level); \
380        } while (0)
381
382/**
383 * @brief Sets in the Device Control Register with number @a dcr all bits
384 * which are set in @a bits.  The previous register value will be masked with
385 * @a mask.
386 *
387 * Interrupts are disabled throughout this operation.
388 */
389#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS_MASKED( dcr, bits, mask) \
390        do { \
391                rtems_interrupt_level level; \
392                uint32_t val; \
393                uint32_t mybits = bits; \
394                uint32_t mymask = mask; \
395                rtems_interrupt_disable( level); \
396                val = PPC_DEVICE_CONTROL_REGISTER( dcr); \
397                val &= ~mymask; \
398                val |= mybits; \
399                PPC_SET_DEVICE_CONTROL_REGISTER( dcr, val); \
400                rtems_interrupt_enable( level); \
401        } while (0)
402
403/**
404 * @brief Clears in the Device Control Register with number @a dcr all bits
405 * which are set in @a bits.
406 *
407 * Interrupts are disabled throughout this operation.
408 */
409#define PPC_CLEAR_DEVICE_CONTROL_REGISTER_BITS( dcr, bits) \
410        do { \
411                rtems_interrupt_level level; \
412                uint32_t val; \
413                uint32_t mybits = bits; \
414                rtems_interrupt_disable( level); \
415                val = PPC_DEVICE_CONTROL_REGISTER( dcr); \
416                val &= ~mybits; \
417                PPC_SET_DEVICE_CONTROL_REGISTER( dcr, val); \
418                rtems_interrupt_enable( level); \
419        } while (0)
420
421static inline uint32_t ppc_time_base()
422{
423        uint32_t val;
424
425        CPU_Get_timebase_low( val);
426
427        return val;
428}
429
430static inline void ppc_set_time_base( uint32_t val)
431{
432        PPC_SET_SPECIAL_PURPOSE_REGISTER( TBWL, val);
433}
434
435static inline uint32_t ppc_time_base_upper()
436{
437        return PPC_SPECIAL_PURPOSE_REGISTER( TBRU);
438}
439
440static inline void ppc_set_time_base_upper( uint32_t val)
441{
442        PPC_SET_SPECIAL_PURPOSE_REGISTER( TBWU, val);
443}
444
445static inline uint64_t ppc_time_base_64()
446{
447        return PPC_Get_timebase_register();
448}
449
450static inline void ppc_set_time_base_64( uint64_t val)
451{
452        PPC_Set_timebase_register( val);
453}
454
455#else /* ASM */
456
457#include <rtems/asm.h>
458
459.macro LA reg, addr
460        lis     \reg, (\addr)@h
461        ori     \reg, \reg, (\addr)@l
462.endm
463
464.macro LWI reg, value
465        lis \reg, (\value)@h
466        ori     \reg, \reg, (\value)@l
467.endm
468
469.macro LW reg, addr
470        lis     \reg, \addr@ha
471        lwz     \reg, \addr@l(\reg)
472.endm
473
474/*
475 * Tests the bits in reg1 against the bits set in mask.  A match is indicated
476 * by EQ = 0 in CR0.  A mismatch is indicated by EQ = 1 in CR0.  The register
477 * reg2 is used to load the mask.
478 */
479.macro  TSTBITS reg1, reg2, mask
480        LWI     \reg2, \mask
481        and     \reg1, \reg1, \reg2
482        cmplw   \reg1, \reg2
483.endm   
484       
485.macro  SETBITS reg1, reg2, mask
486        LWI     \reg2, \mask
487        or      \reg1, \reg1, \reg2
488.endm
489
490.macro  CLRBITS reg1, reg2, mask
491        LWI     \reg2, \mask
492        andc    \reg1, \reg1, \reg2
493.endm
494
495.macro GLOBAL_FUNCTION name
496        .global \name
497        .type \name, @function
498\name:
499.endm
500
501/*
502 * Obtain interrupt mask
503 */
504.macro GET_INTERRUPT_MASK mask
505        mfspr   \mask, sprg0
506.endm
507
508/*
509 * Disables all asynchronous exeptions (interrupts) which may cause a context
510 * switch.
511 */
512.macro INTERRUPT_DISABLE level, mask
513        mfmsr   \level
514        GET_INTERRUPT_MASK mask=\mask
515        andc    \mask, \level, \mask
516        mtmsr   \mask
517.endm
518
519/*
520 * Restore previous machine state.
521 */
522.macro INTERRUPT_ENABLE level
523        mtmsr   \level
524.endm
525
526#define LINKER_SYMBOL( sym) .extern sym
527
528#endif /* ASM */
529
530#endif /* LIBCPU_POWERPC_UTILITY_H */
Note: See TracBrowser for help on using the repository browser.