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.1 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 "qemu/osdep.h"
21 #include "qemu/main-loop.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/helper-proto.h"
25 #include "trace.h"
26
cpu_set_cwp(CPUSPARCState * env,int new_cwp)27 void cpu_set_cwp(CPUSPARCState *env, int new_cwp)
28 {
29 /* put the modified wrap registers at their proper location */
30 if (env->cwp == env->nwindows - 1) {
31 memcpy(env->regbase, env->regbase + env->nwindows * 16,
32 sizeof(env->gregs));
33 }
34 env->cwp = new_cwp;
35
36 /* put the wrap registers at their temporary location */
37 if (new_cwp == env->nwindows - 1) {
38 memcpy(env->regbase + env->nwindows * 16, env->regbase,
39 sizeof(env->gregs));
40 }
41 env->regwptr = env->regbase + (new_cwp * 16);
42 }
43
cpu_get_psr(CPUSPARCState * env)44 target_ulong cpu_get_psr(CPUSPARCState *env)
45 {
46 target_ulong icc = 0;
47
48 icc |= ((int32_t)env->cc_N < 0) << PSR_NEG_SHIFT;
49 icc |= ((int32_t)env->cc_V < 0) << PSR_OVF_SHIFT;
50 icc |= ((int32_t)env->icc_Z == 0) << PSR_ZERO_SHIFT;
51 if (TARGET_LONG_BITS == 64) {
52 icc |= extract64(env->icc_C, 32, 1) << PSR_CARRY_SHIFT;
53 } else {
54 icc |= env->icc_C << PSR_CARRY_SHIFT;
55 }
56
57 #if !defined(TARGET_SPARC64)
58 return env->version | icc |
59 (env->psref ? PSR_EF : 0) |
60 (env->psrpil << 8) |
61 (env->psrs ? PSR_S : 0) |
62 (env->psrps ? PSR_PS : 0) |
63 (env->psret ? PSR_ET : 0) | env->cwp;
64 #else
65 return icc;
66 #endif
67 }
68
cpu_put_psr_icc(CPUSPARCState * env,target_ulong val)69 void cpu_put_psr_icc(CPUSPARCState *env, target_ulong val)
70 {
71 if (TARGET_LONG_BITS == 64) {
72 /* Do not clobber xcc.[NV] */
73 env->cc_N = deposit64(env->cc_N, 0, 32, -(val & PSR_NEG));
74 env->cc_V = deposit64(env->cc_V, 0, 32, -(val & PSR_OVF));
75 env->icc_C = -(val & PSR_CARRY);
76 } else {
77 env->cc_N = -(val & PSR_NEG);
78 env->cc_V = -(val & PSR_OVF);
79 env->icc_C = (val >> PSR_CARRY_SHIFT) & 1;
80 }
81 env->icc_Z = ~val & PSR_ZERO;
82 }
83
cpu_put_psr_raw(CPUSPARCState * env,target_ulong val)84 void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
85 {
86 cpu_put_psr_icc(env, val);
87 #if !defined(TARGET_SPARC64)
88 env->psref = (val & PSR_EF) ? 1 : 0;
89 env->psrpil = (val & PSR_PIL) >> 8;
90 env->psrs = (val & PSR_S) ? 1 : 0;
91 env->psrps = (val & PSR_PS) ? 1 : 0;
92 env->psret = (val & PSR_ET) ? 1 : 0;
93 #endif
94 #if !defined(TARGET_SPARC64)
95 cpu_set_cwp(env, val & PSR_CWP);
96 #endif
97 }
98
99 /* Called with BQL held */
cpu_put_psr(CPUSPARCState * env,target_ulong val)100 void cpu_put_psr(CPUSPARCState *env, target_ulong val)
101 {
102 cpu_put_psr_raw(env, val);
103 #if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
104 cpu_check_irqs(env);
105 #endif
106 }
107
cpu_cwp_inc(CPUSPARCState * env,int cwp)108 int cpu_cwp_inc(CPUSPARCState *env, int cwp)
109 {
110 if (unlikely(cwp >= env->nwindows)) {
111 cwp -= env->nwindows;
112 }
113 return cwp;
114 }
115
cpu_cwp_dec(CPUSPARCState * env,int cwp)116 int cpu_cwp_dec(CPUSPARCState *env, int cwp)
117 {
118 if (unlikely(cwp < 0)) {
119 cwp += env->nwindows;
120 }
121 return cwp;
122 }
123
124 #ifndef TARGET_SPARC64
helper_rett(CPUSPARCState * env)125 void helper_rett(CPUSPARCState *env)
126 {
127 unsigned int cwp;
128
129 if (env->psret == 1) {
130 cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
131 }
132
133 env->psret = 1;
134 cwp = cpu_cwp_inc(env, env->cwp + 1) ;
135 if (env->wim & (1 << cwp)) {
136 cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
137 }
138 cpu_set_cwp(env, cwp);
139 env->psrs = env->psrps;
140 }
141
142 /* XXX: use another pointer for %iN registers to avoid slow wrapping
143 handling ? */
helper_save(CPUSPARCState * env)144 void helper_save(CPUSPARCState *env)
145 {
146 uint32_t cwp;
147
148 cwp = cpu_cwp_dec(env, env->cwp - 1);
149 if (env->wim & (1 << cwp)) {
150 cpu_raise_exception_ra(env, TT_WIN_OVF, GETPC());
151 }
152 cpu_set_cwp(env, cwp);
153 }
154
helper_restore(CPUSPARCState * env)155 void helper_restore(CPUSPARCState *env)
156 {
157 uint32_t cwp;
158
159 cwp = cpu_cwp_inc(env, env->cwp + 1);
160 if (env->wim & (1 << cwp)) {
161 cpu_raise_exception_ra(env, TT_WIN_UNF, GETPC());
162 }
163 cpu_set_cwp(env, cwp);
164 }
165
helper_wrpsr(CPUSPARCState * env,target_ulong new_psr)166 void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
167 {
168 if ((new_psr & PSR_CWP) >= env->nwindows) {
169 cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
170 } else {
171 /* cpu_put_psr may trigger interrupts, hence BQL */
172 bql_lock();
173 cpu_put_psr(env, new_psr);
174 bql_unlock();
175 }
176 }
177
helper_rdpsr(CPUSPARCState * env)178 target_ulong helper_rdpsr(CPUSPARCState *env)
179 {
180 return cpu_get_psr(env);
181 }
182
183 #else
184 /* XXX: use another pointer for %iN registers to avoid slow wrapping
185 handling ? */
helper_save(CPUSPARCState * env)186 void helper_save(CPUSPARCState *env)
187 {
188 uint32_t cwp;
189
190 cwp = cpu_cwp_dec(env, env->cwp - 1);
191 if (env->cansave == 0) {
192 int tt = TT_SPILL | (env->otherwin != 0
193 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
194 : ((env->wstate & 0x7) << 2));
195 cpu_raise_exception_ra(env, tt, GETPC());
196 } else {
197 if (env->cleanwin - env->canrestore == 0) {
198 /* XXX Clean windows without trap */
199 cpu_raise_exception_ra(env, TT_CLRWIN, GETPC());
200 } else {
201 env->cansave--;
202 env->canrestore++;
203 cpu_set_cwp(env, cwp);
204 }
205 }
206 }
207
helper_restore(CPUSPARCState * env)208 void helper_restore(CPUSPARCState *env)
209 {
210 uint32_t cwp;
211
212 cwp = cpu_cwp_inc(env, env->cwp + 1);
213 if (env->canrestore == 0) {
214 int tt = TT_FILL | (env->otherwin != 0
215 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
216 : ((env->wstate & 0x7) << 2));
217 cpu_raise_exception_ra(env, tt, GETPC());
218 } else {
219 env->cansave++;
220 env->canrestore--;
221 cpu_set_cwp(env, cwp);
222 }
223 }
224
helper_flushw(CPUSPARCState * env)225 void helper_flushw(CPUSPARCState *env)
226 {
227 if (env->cansave != env->nwindows - 2) {
228 int tt = TT_SPILL | (env->otherwin != 0
229 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1))
230 : ((env->wstate & 0x7) << 2));
231 cpu_raise_exception_ra(env, tt, GETPC());
232 }
233 }
234
helper_saved(CPUSPARCState * env)235 void helper_saved(CPUSPARCState *env)
236 {
237 env->cansave++;
238 if (env->otherwin == 0) {
239 env->canrestore--;
240 } else {
241 env->otherwin--;
242 }
243 }
244
helper_restored(CPUSPARCState * env)245 void helper_restored(CPUSPARCState *env)
246 {
247 env->canrestore++;
248 if (env->cleanwin < env->nwindows - 1) {
249 env->cleanwin++;
250 }
251 if (env->otherwin == 0) {
252 env->cansave--;
253 } else {
254 env->otherwin--;
255 }
256 }
257
cpu_get_ccr(CPUSPARCState * env)258 target_ulong cpu_get_ccr(CPUSPARCState *env)
259 {
260 target_ulong ccr = 0;
261
262 ccr |= (env->icc_C >> 32) & 1;
263 ccr |= ((int32_t)env->cc_V < 0) << 1;
264 ccr |= ((int32_t)env->icc_Z == 0) << 2;
265 ccr |= ((int32_t)env->cc_N < 0) << 3;
266
267 ccr |= env->xcc_C << 4;
268 ccr |= (env->cc_V < 0) << 5;
269 ccr |= (env->xcc_Z == 0) << 6;
270 ccr |= (env->cc_N < 0) << 7;
271
272 return ccr;
273 }
274
cpu_put_ccr(CPUSPARCState * env,target_ulong val)275 void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
276 {
277 env->cc_N = deposit64(-(val & 0x08), 32, 32, -(val & 0x80));
278 env->cc_V = deposit64(-(val & 0x02), 32, 32, -(val & 0x20));
279 env->icc_C = (uint64_t)val << 32;
280 env->xcc_C = (val >> 4) & 1;
281 env->icc_Z = ~val & 0x04;
282 env->xcc_Z = ~val & 0x40;
283 }
284
cpu_get_cwp64(CPUSPARCState * env)285 target_ulong cpu_get_cwp64(CPUSPARCState *env)
286 {
287 return env->nwindows - 1 - env->cwp;
288 }
289
cpu_put_cwp64(CPUSPARCState * env,int cwp)290 void cpu_put_cwp64(CPUSPARCState *env, int cwp)
291 {
292 if (unlikely(cwp >= env->nwindows || cwp < 0)) {
293 cwp %= env->nwindows;
294 }
295 cpu_set_cwp(env, env->nwindows - 1 - cwp);
296 }
297
helper_rdccr(CPUSPARCState * env)298 target_ulong helper_rdccr(CPUSPARCState *env)
299 {
300 return cpu_get_ccr(env);
301 }
302
helper_wrccr(CPUSPARCState * env,target_ulong new_ccr)303 void helper_wrccr(CPUSPARCState *env, target_ulong new_ccr)
304 {
305 cpu_put_ccr(env, new_ccr);
306 }
307
308 /* CWP handling is reversed in V9, but we still use the V8 register
309 order. */
helper_rdcwp(CPUSPARCState * env)310 target_ulong helper_rdcwp(CPUSPARCState *env)
311 {
312 return cpu_get_cwp64(env);
313 }
314
helper_wrcwp(CPUSPARCState * env,target_ulong new_cwp)315 void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp)
316 {
317 cpu_put_cwp64(env, new_cwp);
318 }
319
get_gregset(CPUSPARCState * env,uint32_t pstate)320 static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
321 {
322 if (env->def.features & CPU_FEATURE_GL) {
323 return env->glregs + (env->gl & 7) * 8;
324 }
325
326 switch (pstate) {
327 default:
328 trace_win_helper_gregset_error(pstate);
329 /* fall through to normal set of global registers */
330 case 0:
331 return env->bgregs;
332 case PS_AG:
333 return env->agregs;
334 case PS_MG:
335 return env->mgregs;
336 case PS_IG:
337 return env->igregs;
338 }
339 }
340
get_gl_gregset(CPUSPARCState * env,uint32_t gl)341 static inline uint64_t *get_gl_gregset(CPUSPARCState *env, uint32_t gl)
342 {
343 return env->glregs + (gl & 7) * 8;
344 }
345
346 /* Switch global register bank */
cpu_gl_switch_gregs(CPUSPARCState * env,uint32_t new_gl)347 void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl)
348 {
349 uint64_t *src, *dst;
350 src = get_gl_gregset(env, new_gl);
351 dst = get_gl_gregset(env, env->gl);
352
353 if (src != dst) {
354 memcpy(dst, env->gregs, sizeof(env->gregs));
355 memcpy(env->gregs, src, sizeof(env->gregs));
356 }
357 }
358
helper_wrgl(CPUSPARCState * env,target_ulong new_gl)359 void helper_wrgl(CPUSPARCState *env, target_ulong new_gl)
360 {
361 cpu_gl_switch_gregs(env, new_gl & 7);
362 env->gl = new_gl & 7;
363 }
364
cpu_change_pstate(CPUSPARCState * env,uint32_t new_pstate)365 void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate)
366 {
367 uint32_t pstate_regs, new_pstate_regs;
368 uint64_t *src, *dst;
369
370 if (env->def.features & CPU_FEATURE_GL) {
371 /* PS_AG, IG and MG are not implemented in this case */
372 new_pstate &= ~(PS_AG | PS_IG | PS_MG);
373 env->pstate = new_pstate;
374 return;
375 }
376
377 pstate_regs = env->pstate & 0xc01;
378 new_pstate_regs = new_pstate & 0xc01;
379
380 if (new_pstate_regs != pstate_regs) {
381 trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
382
383 /* Switch global register bank */
384 src = get_gregset(env, new_pstate_regs);
385 dst = get_gregset(env, pstate_regs);
386 memcpy(dst, env->gregs, sizeof(env->gregs));
387 memcpy(env->gregs, src, sizeof(env->gregs));
388 } else {
389 trace_win_helper_no_switch_pstate(new_pstate_regs);
390 }
391 env->pstate = new_pstate;
392 }
393
helper_wrpstate(CPUSPARCState * env,target_ulong new_state)394 void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
395 {
396 cpu_change_pstate(env, new_state & 0xf3f);
397
398 #if !defined(CONFIG_USER_ONLY)
399 if (cpu_interrupts_enabled(env)) {
400 bql_lock();
401 cpu_check_irqs(env);
402 bql_unlock();
403 }
404 #endif
405 }
406
helper_wrpil(CPUSPARCState * env,target_ulong new_pil)407 void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
408 {
409 #if !defined(CONFIG_USER_ONLY)
410 trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
411
412 env->psrpil = new_pil;
413
414 if (cpu_interrupts_enabled(env)) {
415 bql_lock();
416 cpu_check_irqs(env);
417 bql_unlock();
418 }
419 #endif
420 }
421
helper_done(CPUSPARCState * env)422 void helper_done(CPUSPARCState *env)
423 {
424 trap_state *tsptr = cpu_tsptr(env);
425
426 env->pc = tsptr->tnpc;
427 env->npc = tsptr->tnpc + 4;
428 cpu_put_ccr(env, tsptr->tstate >> 32);
429 env->asi = (tsptr->tstate >> 24) & 0xff;
430 cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
431 cpu_put_cwp64(env, tsptr->tstate & 0xff);
432 if (cpu_has_hypervisor(env)) {
433 uint32_t new_gl = (tsptr->tstate >> 40) & 7;
434 env->hpstate = env->htstate[env->tl];
435 cpu_gl_switch_gregs(env, new_gl);
436 env->gl = new_gl;
437 }
438 env->tl--;
439
440 trace_win_helper_done(env->tl);
441
442 #if !defined(CONFIG_USER_ONLY)
443 if (cpu_interrupts_enabled(env)) {
444 bql_lock();
445 cpu_check_irqs(env);
446 bql_unlock();
447 }
448 #endif
449 }
450
helper_retry(CPUSPARCState * env)451 void helper_retry(CPUSPARCState *env)
452 {
453 trap_state *tsptr = cpu_tsptr(env);
454
455 env->pc = tsptr->tpc;
456 env->npc = tsptr->tnpc;
457 cpu_put_ccr(env, tsptr->tstate >> 32);
458 env->asi = (tsptr->tstate >> 24) & 0xff;
459 cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
460 cpu_put_cwp64(env, tsptr->tstate & 0xff);
461 if (cpu_has_hypervisor(env)) {
462 uint32_t new_gl = (tsptr->tstate >> 40) & 7;
463 env->hpstate = env->htstate[env->tl];
464 cpu_gl_switch_gregs(env, new_gl);
465 env->gl = new_gl;
466 }
467 env->tl--;
468
469 trace_win_helper_retry(env->tl);
470
471 #if !defined(CONFIG_USER_ONLY)
472 if (cpu_interrupts_enabled(env)) {
473 bql_lock();
474 cpu_check_irqs(env);
475 bql_unlock();
476 }
477 #endif
478 }
479 #endif
480