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