Statistics
| Branch: | Revision:

root / target-sparc / win_helper.c @ a8a00822

History | View | Annotate | Download (9.4 kB)

1
/*
2
 * Helpers for CWP and PSTATE handling
3
 *
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include "cpu.h"
21
#include "helper.h"
22
#include "trace.h"
23

    
24
static inline void memcpy32(target_ulong *dst, const target_ulong *src)
25
{
26
    dst[0] = src[0];
27
    dst[1] = src[1];
28
    dst[2] = src[2];
29
    dst[3] = src[3];
30
    dst[4] = src[4];
31
    dst[5] = src[5];
32
    dst[6] = src[6];
33
    dst[7] = src[7];
34
}
35

    
36
void cpu_set_cwp(CPUState *env, int new_cwp)
37
{
38
    /* put the modified wrap registers at their proper location */
39
    if (env->cwp == env->nwindows - 1) {
40
        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
41
    }
42
    env->cwp = new_cwp;
43

    
44
    /* put the wrap registers at their temporary location */
45
    if (new_cwp == env->nwindows - 1) {
46
        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
47
    }
48
    env->regwptr = env->regbase + (new_cwp * 16);
49
}
50

    
51
target_ulong cpu_get_psr(CPUState *env)
52
{
53
    helper_compute_psr(env);
54

    
55
#if !defined(TARGET_SPARC64)
56
    return env->version | (env->psr & PSR_ICC) |
57
        (env->psref ? PSR_EF : 0) |
58
        (env->psrpil << 8) |
59
        (env->psrs ? PSR_S : 0) |
60
        (env->psrps ? PSR_PS : 0) |
61
        (env->psret ? PSR_ET : 0) | env->cwp;
62
#else
63
    return env->psr & PSR_ICC;
64
#endif
65
}
66

    
67
void cpu_put_psr(CPUState *env, target_ulong val)
68
{
69
    env->psr = val & PSR_ICC;
70
#if !defined(TARGET_SPARC64)
71
    env->psref = (val & PSR_EF) ? 1 : 0;
72
    env->psrpil = (val & PSR_PIL) >> 8;
73
#endif
74
#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
75
    cpu_check_irqs(env);
76
#endif
77
#if !defined(TARGET_SPARC64)
78
    env->psrs = (val & PSR_S) ? 1 : 0;
79
    env->psrps = (val & PSR_PS) ? 1 : 0;
80
    env->psret = (val & PSR_ET) ? 1 : 0;
81
    cpu_set_cwp(env, val & PSR_CWP);
82
#endif
83
    env->cc_op = CC_OP_FLAGS;
84
}
85

    
86
int cpu_cwp_inc(CPUState *env, int cwp)
87
{
88
    if (unlikely(cwp >= env->nwindows)) {
89
        cwp -= env->nwindows;
90
    }
91
    return cwp;
92
}
93

    
94
int cpu_cwp_dec(CPUState *env, int cwp)
95
{
96
    if (unlikely(cwp < 0)) {
97
        cwp += env->nwindows;
98
    }
99
    return cwp;
100
}
101

    
102
#ifndef TARGET_SPARC64
103
void helper_rett(CPUState *env)
104
{
105
    unsigned int cwp;
106

    
107
    if (env->psret == 1) {
108
        helper_raise_exception(env, TT_ILL_INSN);
109
    }
110

    
111
    env->psret = 1;
112
    cwp = cpu_cwp_inc(env, env->cwp + 1) ;
113
    if (env->wim & (1 << cwp)) {
114
        helper_raise_exception(env, TT_WIN_UNF);
115
    }
116
    cpu_set_cwp(env, cwp);
117
    env->psrs = env->psrps;
118
}
119

    
120
/* XXX: use another pointer for %iN registers to avoid slow wrapping
121
   handling ? */
122
void helper_save(CPUState *env)
123
{
124
    uint32_t cwp;
125

    
126
    cwp = cpu_cwp_dec(env, env->cwp - 1);
127
    if (env->wim & (1 << cwp)) {
128
        helper_raise_exception(env, TT_WIN_OVF);
129
    }
130
    cpu_set_cwp(env, cwp);
131
}
132

    
133
void helper_restore(CPUState *env)
134
{
135
    uint32_t cwp;
136

    
137
    cwp = cpu_cwp_inc(env, env->cwp + 1);
138
    if (env->wim & (1 << cwp)) {
139
        helper_raise_exception(env, TT_WIN_UNF);
140
    }
141
    cpu_set_cwp(env, cwp);
142
}
143

    
144
void helper_wrpsr(CPUState *env, target_ulong new_psr)
145
{
146
    if ((new_psr & PSR_CWP) >= env->nwindows) {
147
        helper_raise_exception(env, TT_ILL_INSN);
148
    } else {
149
        cpu_put_psr(env, new_psr);
150
    }
151
}
152

    
153
target_ulong helper_rdpsr(CPUState *env)
154
{
155
    return cpu_get_psr(env);
156
}
157

    
158
#else
159
/* XXX: use another pointer for %iN registers to avoid slow wrapping
160
   handling ? */
161
void helper_save(CPUState *env)
162
{
163
    uint32_t cwp;
164

    
165
    cwp = cpu_cwp_dec(env, env->cwp - 1);
166
    if (env->cansave == 0) {
167
        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
168
                                                (TT_WOTHER |
169
                                                 ((env->wstate & 0x38) >> 1)) :
170
                                                ((env->wstate & 0x7) << 2)));
171
    } else {
172
        if (env->cleanwin - env->canrestore == 0) {
173
            /* XXX Clean windows without trap */
174
            helper_raise_exception(env, TT_CLRWIN);
175
        } else {
176
            env->cansave--;
177
            env->canrestore++;
178
            cpu_set_cwp(env, cwp);
179
        }
180
    }
181
}
182

    
183
void helper_restore(CPUState *env)
184
{
185
    uint32_t cwp;
186

    
187
    cwp = cpu_cwp_inc(env, env->cwp + 1);
188
    if (env->canrestore == 0) {
189
        helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
190
                                               (TT_WOTHER |
191
                                                ((env->wstate & 0x38) >> 1)) :
192
                                               ((env->wstate & 0x7) << 2)));
193
    } else {
194
        env->cansave++;
195
        env->canrestore--;
196
        cpu_set_cwp(env, cwp);
197
    }
198
}
199

    
200
void helper_flushw(CPUState *env)
201
{
202
    if (env->cansave != env->nwindows - 2) {
203
        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
204
                                                (TT_WOTHER |
205
                                                 ((env->wstate & 0x38) >> 1)) :
206
                                                ((env->wstate & 0x7) << 2)));
207
    }
208
}
209

    
210
void helper_saved(CPUState *env)
211
{
212
    env->cansave++;
213
    if (env->otherwin == 0) {
214
        env->canrestore--;
215
    } else {
216
        env->otherwin--;
217
    }
218
}
219

    
220
void helper_restored(CPUState *env)
221
{
222
    env->canrestore++;
223
    if (env->cleanwin < env->nwindows - 1) {
224
        env->cleanwin++;
225
    }
226
    if (env->otherwin == 0) {
227
        env->cansave--;
228
    } else {
229
        env->otherwin--;
230
    }
231
}
232

    
233
target_ulong cpu_get_ccr(CPUState *env)
234
{
235
    target_ulong psr;
236

    
237
    psr = cpu_get_psr(env);
238

    
239
    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
240
}
241

    
242
void cpu_put_ccr(CPUState *env, target_ulong val)
243
{
244
    env->xcc = (val >> 4) << 20;
245
    env->psr = (val & 0xf) << 20;
246
    CC_OP = CC_OP_FLAGS;
247
}
248

    
249
target_ulong cpu_get_cwp64(CPUState *env)
250
{
251
    return env->nwindows - 1 - env->cwp;
252
}
253

    
254
void cpu_put_cwp64(CPUState *env, int cwp)
255
{
256
    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
257
        cwp %= env->nwindows;
258
    }
259
    cpu_set_cwp(env, env->nwindows - 1 - cwp);
260
}
261

    
262
target_ulong helper_rdccr(CPUState *env)
263
{
264
    return cpu_get_ccr(env);
265
}
266

    
267
void helper_wrccr(CPUState *env, target_ulong new_ccr)
268
{
269
    cpu_put_ccr(env, new_ccr);
270
}
271

    
272
/* CWP handling is reversed in V9, but we still use the V8 register
273
   order. */
274
target_ulong helper_rdcwp(CPUState *env)
275
{
276
    return cpu_get_cwp64(env);
277
}
278

    
279
void helper_wrcwp(CPUState *env, target_ulong new_cwp)
280
{
281
    cpu_put_cwp64(env, new_cwp);
282
}
283

    
284
static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
285
{
286
    switch (pstate) {
287
    default:
288
        trace_win_helper_gregset_error(pstate);
289
        /* pass through to normal set of global registers */
290
    case 0:
291
        return env->bgregs;
292
    case PS_AG:
293
        return env->agregs;
294
    case PS_MG:
295
        return env->mgregs;
296
    case PS_IG:
297
        return env->igregs;
298
    }
299
}
300

    
301
void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
302
{
303
    uint32_t pstate_regs, new_pstate_regs;
304
    uint64_t *src, *dst;
305

    
306
    if (env->def->features & CPU_FEATURE_GL) {
307
        /* PS_AG is not implemented in this case */
308
        new_pstate &= ~PS_AG;
309
    }
310

    
311
    pstate_regs = env->pstate & 0xc01;
312
    new_pstate_regs = new_pstate & 0xc01;
313

    
314
    if (new_pstate_regs != pstate_regs) {
315
        trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
316

    
317
        /* Switch global register bank */
318
        src = get_gregset(env, new_pstate_regs);
319
        dst = get_gregset(env, pstate_regs);
320
        memcpy32(dst, env->gregs);
321
        memcpy32(env->gregs, src);
322
    } else {
323
        trace_win_helper_no_switch_pstate(new_pstate_regs);
324
    }
325
    env->pstate = new_pstate;
326
}
327

    
328
void helper_wrpstate(CPUState *env, target_ulong new_state)
329
{
330
    cpu_change_pstate(env, new_state & 0xf3f);
331

    
332
#if !defined(CONFIG_USER_ONLY)
333
    if (cpu_interrupts_enabled(env)) {
334
        cpu_check_irqs(env);
335
    }
336
#endif
337
}
338

    
339
void helper_wrpil(CPUState *env, target_ulong new_pil)
340
{
341
#if !defined(CONFIG_USER_ONLY)
342
    trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
343

    
344
    env->psrpil = new_pil;
345

    
346
    if (cpu_interrupts_enabled(env)) {
347
        cpu_check_irqs(env);
348
    }
349
#endif
350
}
351

    
352
void helper_done(CPUState *env)
353
{
354
    trap_state *tsptr = cpu_tsptr(env);
355

    
356
    env->pc = tsptr->tnpc;
357
    env->npc = tsptr->tnpc + 4;
358
    cpu_put_ccr(env, tsptr->tstate >> 32);
359
    env->asi = (tsptr->tstate >> 24) & 0xff;
360
    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
361
    cpu_put_cwp64(env, tsptr->tstate & 0xff);
362
    env->tl--;
363

    
364
    trace_win_helper_done(env->tl);
365

    
366
#if !defined(CONFIG_USER_ONLY)
367
    if (cpu_interrupts_enabled(env)) {
368
        cpu_check_irqs(env);
369
    }
370
#endif
371
}
372

    
373
void helper_retry(CPUState *env)
374
{
375
    trap_state *tsptr = cpu_tsptr(env);
376

    
377
    env->pc = tsptr->tpc;
378
    env->npc = tsptr->tnpc;
379
    cpu_put_ccr(env, tsptr->tstate >> 32);
380
    env->asi = (tsptr->tstate >> 24) & 0xff;
381
    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
382
    cpu_put_cwp64(env, tsptr->tstate & 0xff);
383
    env->tl--;
384

    
385
    trace_win_helper_retry(env->tl);
386

    
387
#if !defined(CONFIG_USER_ONLY)
388
    if (cpu_interrupts_enabled(env)) {
389
        cpu_check_irqs(env);
390
    }
391
#endif
392
}
393
#endif