source: rtems/c/src/lib/libcpu/powerpc/mpc6xx/altivec/vec_sup.c @ fbee4ff

4.104.11
Last change on this file since fbee4ff was fbee4ff, checked in by Till Straumann <strauman@…>, on Dec 2, 2009 at 1:33:51 AM

2009-12-01 Till Straumann <strauman@…>

  • Makefile.am, mpc6xx/altivec: new directory implementing support for AltiVec? context saving/restoring.
  • Property mode set to 100644
File size: 5.2 KB
Line 
1/* $Id$ */
2
3/* Altivec support for RTEMS; vector register context management.
4 * This is implemented as a user extension.
5 *
6 * Author: Till Straumann <strauman@slac.stanford.edu>, 2005
7 */
8
9#ifdef __ALTIVEC__
10
11#include <rtems.h>
12#include <libcpu/cpuIdent.h>
13#include <rtems/bspIo.h>
14#include <rtems/error.h>
15#include <rtems/score/cpu.h>
16#include <rtems/powerpc/powerpc.h>
17
18#define STATIC static
19
20#define VEC_ALIGNMENT   16
21
22#define NAM                             "AltiVec Support"
23#define ERRID(a,b,c,d)  (((a)<<24) | ((b)<<16) | ((c)<<8) | (d))
24
25typedef uint32_t _vu32 __attribute__((vector_size(VEC_ALIGNMENT)));
26
27#ifndef MSR_VE
28#define MSR_VE  (1<<(31-6))
29#endif
30
31/* NOTE: These two variables are accessed by assembly code
32 *       which assumes 32-bit data!
33 */
34uint32_t _CPU_altivec_ctxt_off = 0;
35uint32_t _CPU_altivec_psim_cpu = 0;
36
37static inline uint32_t
38mfmsr(void)
39{
40uint32_t v;     
41        _CPU_MSR_GET(v);
42        return v;
43}
44
45static inline void
46mtmsr(uint32_t v)
47{
48        _CPU_MSR_SET(v);
49}
50
51static inline void
52isync(void)
53{
54        asm volatile("isync");
55}
56
57static inline void
58dssall(void)
59{
60        if ( !_CPU_altivec_psim_cpu)
61                asm volatile("dssall");
62}
63
64static inline uint32_t
65set_MSR_VE(void)
66{
67uint32_t rval;
68        rval=mfmsr();
69        if ( ! (MSR_VE & rval ) ) {
70                mtmsr(rval | MSR_VE);
71                isync();
72        }
73        return rval;
74}
75
76static inline void
77clr_MSR_VE(void)
78{
79        dssall();
80        mtmsr(mfmsr() & ~MSR_VE);
81        isync();
82}
83
84static inline void
85rst_MSR_VE(uint32_t old)
86{
87        if ( ! ( MSR_VE & old ) ) {
88                dssall();
89                mtmsr(old);
90                isync();
91        }
92}
93
94
95/* Code to probe the compiler's stack alignment (PowerPC);
96 * The routine determines at run-time if the compiler generated
97 * 8 or 16-byte aligned code.
98 *
99 * Till Straumann <strauman@slac.stanford.edu>, 2005
100 */
101
102static void dummy(void) __attribute__((noinline));
103/* add (empty) asm statement to make sure this isn't optimized away */
104static void dummy(void) { asm volatile(""); }
105
106static unsigned probe_r1(void) __attribute__((noinline));
107static unsigned probe_r1(void)
108{
109unsigned r1;
110        /* call something to enforce creation of a minimal stack frame;
111     * (8 bytes: r1 and lr space for 'dummy' callee). If compiled
112     * with -meabi -mno-altivec gcc allocates 8 bytes, if -mno-eabi
113     * or -maltivec / -mabi=altivec then gcc allocates 16 bytes
114     * according to the sysv / altivec ABI specs.
115     */
116        dummy();
117        /* return stack pointer */
118        asm volatile("mr %0,1":"=r"(r1));
119        return r1;
120}
121
122static unsigned
123probe_ppc_stack_alignment(void)
124{
125unsigned r1;
126        asm volatile("mr %0,1":"=r"(r1));
127        return (r1 - probe_r1()) & ~ 0xf;
128}
129
130STATIC int check_stack_alignment(void)
131{
132int rval = 0;
133        if ( VEC_ALIGNMENT > PPC_STACK_ALIGNMENT ) {
134                printk(NAM": CPU support has unsufficient stack alignment;\n");
135                printk("modify 'cpukit/score/cpu/powerpc/rtems/score/powerpc.h'\n");
136                printk("and choose PPC_ABI_SVR4. I'll enable a workaround for now.\n");
137                rval |= 1;
138        }
139        /* Run-time check; should compile with -mabi=altivec */
140        if ( probe_ppc_stack_alignment() < VEC_ALIGNMENT ) {
141                printk(NAM": run-time stack alignment unsufficient; make sure you compile with -mabi=altivec\n");
142                rval |= 2;
143        }
144        return rval;
145}
146
147
148static uint32_t probe_vrsave(_vu32 *p_v) __attribute__((noinline));
149
150/* Check if this code was compiled with -mvrsave=yes or no
151 * so that we can set the default/init value accordingly.
152 */
153static uint32_t probe_vrsave(_vu32 *p_v)
154{
155_vu32     x;
156uint32_t vrsave;
157        /* Explicitly clobber a volatile vector reg (0) that is
158         * not used to pass return values.
159         * If -mvrsave=yes was used this should cause gcc to
160         * set bit 0 in vrsave. OTOH this bit cannot be set
161         * because v0 is volatile and not used to pass a value
162         * to the caller...
163         */
164        asm volatile("vxor %0, 0, 0; mfvrsave %1":"=v"(x),"=r"(vrsave)::"v0");
165        if ( p_v ) {
166                *p_v = x;
167        }
168        return vrsave;
169}
170
171static int vrsave_yes(void) __attribute__((noinline));
172
173static int vrsave_yes(void)
174{
175uint32_t vrsave_pre;
176        asm volatile("mfvrsave %0":"=r"(vrsave_pre));
177        if ( (vrsave_pre & 0x80000000) ) {
178                printk(NAM": WARNING - unable to determine whether -mvrsave was used; assuming NO\n");
179                return 0;
180        }
181        return probe_vrsave(0) != vrsave_pre;
182}
183
184extern void
185_CPU_altivec_set_vrsave_initval(uint32_t);
186
187
188void
189_CPU_Initialize_altivec(void)
190{
191unsigned          pvr;
192
193        /* I don't like to have to #define the offset of the altivec area
194         * for use by assembly code.
195         * Therefore, we compute it here and store it in memory...
196         */
197        _CPU_altivec_ctxt_off  = (uint32_t) &((Context_Control*)0)->altivec;
198        /*
199         * Add space possibly needed for alignment
200         */
201        _CPU_altivec_ctxt_off += PPC_CACHE_ALIGNMENT - 1;
202
203        if ( ! vrsave_yes() ) {
204                /* They seemed to compile with -mvrsave=no. Hence we
205                 * must set VRSAVE so that all registers are saved/restored
206                 * in case this support was not built with IGNORE_VRSAVE.
207                 */
208                _CPU_altivec_set_vrsave_initval( -1 );
209        }
210
211        if ( check_stack_alignment() & 2 )
212                rtems_fatal_error_occurred(ERRID('V','E','C','1'));
213
214        pvr                   = get_ppc_cpu_type();
215        /* psim has altivec but lacks the streaming instructions :-( */
216        _CPU_altivec_psim_cpu = (PPC_PSIM == pvr);
217
218        if ( ! ppc_cpu_has_altivec() ) {
219                printk(NAM": This CPU seems not to have AltiVec\n");
220                rtems_panic("Unable to initialize AltiVec Support\n");
221        }
222
223        if ( ! (mfmsr() & MSR_VE) ) {
224                printk(NAM": Warning: BSP should set MSR_VE early; doing it now...\n");
225                set_MSR_VE();   
226        }
227}
228#endif
Note: See TracBrowser for help on using the repository browser.