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