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 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 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 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 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 */ 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 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 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 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 ? */ 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 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 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 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 ? */ 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 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 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 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 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 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 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 285 target_ulong cpu_get_cwp64(CPUSPARCState *env) 286 { 287 return env->nwindows - 1 - env->cwp; 288 } 289 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 298 target_ulong helper_rdccr(CPUSPARCState *env) 299 { 300 return cpu_get_ccr(env); 301 } 302 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. */ 310 target_ulong helper_rdcwp(CPUSPARCState *env) 311 { 312 return cpu_get_cwp64(env); 313 } 314 315 void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp) 316 { 317 cpu_put_cwp64(env, new_cwp); 318 } 319 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 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 */ 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 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 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 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 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 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 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