1070af384SBlue Swirl /* 2070af384SBlue Swirl * Helpers for CWP and PSTATE handling 3070af384SBlue Swirl * 4070af384SBlue Swirl * Copyright (c) 2003-2005 Fabrice Bellard 5070af384SBlue Swirl * 6070af384SBlue Swirl * This library is free software; you can redistribute it and/or 7070af384SBlue Swirl * modify it under the terms of the GNU Lesser General Public 8070af384SBlue Swirl * License as published by the Free Software Foundation; either 9070af384SBlue Swirl * version 2 of the License, or (at your option) any later version. 10070af384SBlue Swirl * 11070af384SBlue Swirl * This library is distributed in the hope that it will be useful, 12070af384SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 13070af384SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14070af384SBlue Swirl * Lesser General Public License for more details. 15070af384SBlue Swirl * 16070af384SBlue Swirl * You should have received a copy of the GNU Lesser General Public 17070af384SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18070af384SBlue Swirl */ 19070af384SBlue Swirl 20070af384SBlue Swirl #include "cpu.h" 212ef6175aSRichard Henderson #include "exec/helper-proto.h" 22870be6adSBlue Swirl #include "trace.h" 23070af384SBlue Swirl 24070af384SBlue Swirl static inline void memcpy32(target_ulong *dst, const target_ulong *src) 25070af384SBlue Swirl { 26070af384SBlue Swirl dst[0] = src[0]; 27070af384SBlue Swirl dst[1] = src[1]; 28070af384SBlue Swirl dst[2] = src[2]; 29070af384SBlue Swirl dst[3] = src[3]; 30070af384SBlue Swirl dst[4] = src[4]; 31070af384SBlue Swirl dst[5] = src[5]; 32070af384SBlue Swirl dst[6] = src[6]; 33070af384SBlue Swirl dst[7] = src[7]; 34070af384SBlue Swirl } 35070af384SBlue Swirl 36c5f9864eSAndreas Färber void cpu_set_cwp(CPUSPARCState *env, int new_cwp) 37070af384SBlue Swirl { 38070af384SBlue Swirl /* put the modified wrap registers at their proper location */ 39070af384SBlue Swirl if (env->cwp == env->nwindows - 1) { 40070af384SBlue Swirl memcpy32(env->regbase, env->regbase + env->nwindows * 16); 41070af384SBlue Swirl } 42070af384SBlue Swirl env->cwp = new_cwp; 43070af384SBlue Swirl 44070af384SBlue Swirl /* put the wrap registers at their temporary location */ 45070af384SBlue Swirl if (new_cwp == env->nwindows - 1) { 46070af384SBlue Swirl memcpy32(env->regbase + env->nwindows * 16, env->regbase); 47070af384SBlue Swirl } 48070af384SBlue Swirl env->regwptr = env->regbase + (new_cwp * 16); 49070af384SBlue Swirl } 50070af384SBlue Swirl 51c5f9864eSAndreas Färber target_ulong cpu_get_psr(CPUSPARCState *env) 52070af384SBlue Swirl { 53070af384SBlue Swirl helper_compute_psr(env); 54070af384SBlue Swirl 55070af384SBlue Swirl #if !defined(TARGET_SPARC64) 56070af384SBlue Swirl return env->version | (env->psr & PSR_ICC) | 57070af384SBlue Swirl (env->psref ? PSR_EF : 0) | 58070af384SBlue Swirl (env->psrpil << 8) | 59070af384SBlue Swirl (env->psrs ? PSR_S : 0) | 60070af384SBlue Swirl (env->psrps ? PSR_PS : 0) | 61070af384SBlue Swirl (env->psret ? PSR_ET : 0) | env->cwp; 62070af384SBlue Swirl #else 63070af384SBlue Swirl return env->psr & PSR_ICC; 64070af384SBlue Swirl #endif 65070af384SBlue Swirl } 66070af384SBlue Swirl 674552a09dSPeter Maydell void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val) 68070af384SBlue Swirl { 69070af384SBlue Swirl env->psr = val & PSR_ICC; 70070af384SBlue Swirl #if !defined(TARGET_SPARC64) 71070af384SBlue Swirl env->psref = (val & PSR_EF) ? 1 : 0; 72070af384SBlue Swirl env->psrpil = (val & PSR_PIL) >> 8; 73070af384SBlue Swirl env->psrs = (val & PSR_S) ? 1 : 0; 74070af384SBlue Swirl env->psrps = (val & PSR_PS) ? 1 : 0; 75070af384SBlue Swirl env->psret = (val & PSR_ET) ? 1 : 0; 76070af384SBlue Swirl #endif 77070af384SBlue Swirl env->cc_op = CC_OP_FLAGS; 784552a09dSPeter Maydell #if !defined(TARGET_SPARC64) 794552a09dSPeter Maydell cpu_set_cwp(env, val & PSR_CWP); 804552a09dSPeter Maydell #endif 814552a09dSPeter Maydell } 824552a09dSPeter Maydell 834552a09dSPeter Maydell void cpu_put_psr(CPUSPARCState *env, target_ulong val) 844552a09dSPeter Maydell { 854552a09dSPeter Maydell cpu_put_psr_raw(env, val); 864552a09dSPeter Maydell #if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) 874552a09dSPeter Maydell cpu_check_irqs(env); 884552a09dSPeter Maydell #endif 89070af384SBlue Swirl } 90070af384SBlue Swirl 91c5f9864eSAndreas Färber int cpu_cwp_inc(CPUSPARCState *env, int cwp) 92070af384SBlue Swirl { 93070af384SBlue Swirl if (unlikely(cwp >= env->nwindows)) { 94070af384SBlue Swirl cwp -= env->nwindows; 95070af384SBlue Swirl } 96070af384SBlue Swirl return cwp; 97070af384SBlue Swirl } 98070af384SBlue Swirl 99c5f9864eSAndreas Färber int cpu_cwp_dec(CPUSPARCState *env, int cwp) 100070af384SBlue Swirl { 101070af384SBlue Swirl if (unlikely(cwp < 0)) { 102070af384SBlue Swirl cwp += env->nwindows; 103070af384SBlue Swirl } 104070af384SBlue Swirl return cwp; 105070af384SBlue Swirl } 106070af384SBlue Swirl 107070af384SBlue Swirl #ifndef TARGET_SPARC64 108c5f9864eSAndreas Färber void helper_rett(CPUSPARCState *env) 109070af384SBlue Swirl { 110070af384SBlue Swirl unsigned int cwp; 111070af384SBlue Swirl 112070af384SBlue Swirl if (env->psret == 1) { 113070af384SBlue Swirl helper_raise_exception(env, TT_ILL_INSN); 114070af384SBlue Swirl } 115070af384SBlue Swirl 116070af384SBlue Swirl env->psret = 1; 117063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1) ; 118070af384SBlue Swirl if (env->wim & (1 << cwp)) { 119070af384SBlue Swirl helper_raise_exception(env, TT_WIN_UNF); 120070af384SBlue Swirl } 121063c3675SBlue Swirl cpu_set_cwp(env, cwp); 122070af384SBlue Swirl env->psrs = env->psrps; 123070af384SBlue Swirl } 124070af384SBlue Swirl 125070af384SBlue Swirl /* XXX: use another pointer for %iN registers to avoid slow wrapping 126070af384SBlue Swirl handling ? */ 127c5f9864eSAndreas Färber void helper_save(CPUSPARCState *env) 128070af384SBlue Swirl { 129070af384SBlue Swirl uint32_t cwp; 130070af384SBlue Swirl 131063c3675SBlue Swirl cwp = cpu_cwp_dec(env, env->cwp - 1); 132070af384SBlue Swirl if (env->wim & (1 << cwp)) { 133070af384SBlue Swirl helper_raise_exception(env, TT_WIN_OVF); 134070af384SBlue Swirl } 135063c3675SBlue Swirl cpu_set_cwp(env, cwp); 136070af384SBlue Swirl } 137070af384SBlue Swirl 138c5f9864eSAndreas Färber void helper_restore(CPUSPARCState *env) 139070af384SBlue Swirl { 140070af384SBlue Swirl uint32_t cwp; 141070af384SBlue Swirl 142063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1); 143070af384SBlue Swirl if (env->wim & (1 << cwp)) { 144070af384SBlue Swirl helper_raise_exception(env, TT_WIN_UNF); 145070af384SBlue Swirl } 146063c3675SBlue Swirl cpu_set_cwp(env, cwp); 147070af384SBlue Swirl } 148070af384SBlue Swirl 149c5f9864eSAndreas Färber void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr) 150070af384SBlue Swirl { 151070af384SBlue Swirl if ((new_psr & PSR_CWP) >= env->nwindows) { 152070af384SBlue Swirl helper_raise_exception(env, TT_ILL_INSN); 153070af384SBlue Swirl } else { 154070af384SBlue Swirl cpu_put_psr(env, new_psr); 155070af384SBlue Swirl } 156070af384SBlue Swirl } 157070af384SBlue Swirl 158c5f9864eSAndreas Färber target_ulong helper_rdpsr(CPUSPARCState *env) 159070af384SBlue Swirl { 160063c3675SBlue Swirl return cpu_get_psr(env); 161070af384SBlue Swirl } 162070af384SBlue Swirl 163070af384SBlue Swirl #else 164070af384SBlue Swirl /* XXX: use another pointer for %iN registers to avoid slow wrapping 165070af384SBlue Swirl handling ? */ 166c5f9864eSAndreas Färber void helper_save(CPUSPARCState *env) 167070af384SBlue Swirl { 168070af384SBlue Swirl uint32_t cwp; 169070af384SBlue Swirl 170063c3675SBlue Swirl cwp = cpu_cwp_dec(env, env->cwp - 1); 171070af384SBlue Swirl if (env->cansave == 0) { 172070af384SBlue Swirl helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? 173070af384SBlue Swirl (TT_WOTHER | 174070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 175070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 176070af384SBlue Swirl } else { 177070af384SBlue Swirl if (env->cleanwin - env->canrestore == 0) { 178070af384SBlue Swirl /* XXX Clean windows without trap */ 179070af384SBlue Swirl helper_raise_exception(env, TT_CLRWIN); 180070af384SBlue Swirl } else { 181070af384SBlue Swirl env->cansave--; 182070af384SBlue Swirl env->canrestore++; 183063c3675SBlue Swirl cpu_set_cwp(env, cwp); 184070af384SBlue Swirl } 185070af384SBlue Swirl } 186070af384SBlue Swirl } 187070af384SBlue Swirl 188c5f9864eSAndreas Färber void helper_restore(CPUSPARCState *env) 189070af384SBlue Swirl { 190070af384SBlue Swirl uint32_t cwp; 191070af384SBlue Swirl 192063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1); 193070af384SBlue Swirl if (env->canrestore == 0) { 194070af384SBlue Swirl helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ? 195070af384SBlue Swirl (TT_WOTHER | 196070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 197070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 198070af384SBlue Swirl } else { 199070af384SBlue Swirl env->cansave++; 200070af384SBlue Swirl env->canrestore--; 201063c3675SBlue Swirl cpu_set_cwp(env, cwp); 202070af384SBlue Swirl } 203070af384SBlue Swirl } 204070af384SBlue Swirl 205c5f9864eSAndreas Färber void helper_flushw(CPUSPARCState *env) 206070af384SBlue Swirl { 207070af384SBlue Swirl if (env->cansave != env->nwindows - 2) { 208070af384SBlue Swirl helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? 209070af384SBlue Swirl (TT_WOTHER | 210070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 211070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 212070af384SBlue Swirl } 213070af384SBlue Swirl } 214070af384SBlue Swirl 215c5f9864eSAndreas Färber void helper_saved(CPUSPARCState *env) 216070af384SBlue Swirl { 217070af384SBlue Swirl env->cansave++; 218070af384SBlue Swirl if (env->otherwin == 0) { 219070af384SBlue Swirl env->canrestore--; 220070af384SBlue Swirl } else { 221070af384SBlue Swirl env->otherwin--; 222070af384SBlue Swirl } 223070af384SBlue Swirl } 224070af384SBlue Swirl 225c5f9864eSAndreas Färber void helper_restored(CPUSPARCState *env) 226070af384SBlue Swirl { 227070af384SBlue Swirl env->canrestore++; 228070af384SBlue Swirl if (env->cleanwin < env->nwindows - 1) { 229070af384SBlue Swirl env->cleanwin++; 230070af384SBlue Swirl } 231070af384SBlue Swirl if (env->otherwin == 0) { 232070af384SBlue Swirl env->cansave--; 233070af384SBlue Swirl } else { 234070af384SBlue Swirl env->otherwin--; 235070af384SBlue Swirl } 236070af384SBlue Swirl } 237070af384SBlue Swirl 238c5f9864eSAndreas Färber target_ulong cpu_get_ccr(CPUSPARCState *env) 239070af384SBlue Swirl { 240070af384SBlue Swirl target_ulong psr; 241070af384SBlue Swirl 242063c3675SBlue Swirl psr = cpu_get_psr(env); 243070af384SBlue Swirl 244070af384SBlue Swirl return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); 245070af384SBlue Swirl } 246070af384SBlue Swirl 247c5f9864eSAndreas Färber void cpu_put_ccr(CPUSPARCState *env, target_ulong val) 248070af384SBlue Swirl { 249070af384SBlue Swirl env->xcc = (val >> 4) << 20; 250070af384SBlue Swirl env->psr = (val & 0xf) << 20; 251070af384SBlue Swirl CC_OP = CC_OP_FLAGS; 252070af384SBlue Swirl } 253070af384SBlue Swirl 254c5f9864eSAndreas Färber target_ulong cpu_get_cwp64(CPUSPARCState *env) 255070af384SBlue Swirl { 256070af384SBlue Swirl return env->nwindows - 1 - env->cwp; 257070af384SBlue Swirl } 258070af384SBlue Swirl 259c5f9864eSAndreas Färber void cpu_put_cwp64(CPUSPARCState *env, int cwp) 260070af384SBlue Swirl { 261070af384SBlue Swirl if (unlikely(cwp >= env->nwindows || cwp < 0)) { 262070af384SBlue Swirl cwp %= env->nwindows; 263070af384SBlue Swirl } 264063c3675SBlue Swirl cpu_set_cwp(env, env->nwindows - 1 - cwp); 265070af384SBlue Swirl } 266070af384SBlue Swirl 267c5f9864eSAndreas Färber target_ulong helper_rdccr(CPUSPARCState *env) 268070af384SBlue Swirl { 269063c3675SBlue Swirl return cpu_get_ccr(env); 270070af384SBlue Swirl } 271070af384SBlue Swirl 272c5f9864eSAndreas Färber void helper_wrccr(CPUSPARCState *env, target_ulong new_ccr) 273070af384SBlue Swirl { 274063c3675SBlue Swirl cpu_put_ccr(env, new_ccr); 275070af384SBlue Swirl } 276070af384SBlue Swirl 277070af384SBlue Swirl /* CWP handling is reversed in V9, but we still use the V8 register 278070af384SBlue Swirl order. */ 279c5f9864eSAndreas Färber target_ulong helper_rdcwp(CPUSPARCState *env) 280070af384SBlue Swirl { 281063c3675SBlue Swirl return cpu_get_cwp64(env); 282070af384SBlue Swirl } 283070af384SBlue Swirl 284c5f9864eSAndreas Färber void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp) 285070af384SBlue Swirl { 286063c3675SBlue Swirl cpu_put_cwp64(env, new_cwp); 287070af384SBlue Swirl } 288070af384SBlue Swirl 289c5f9864eSAndreas Färber static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate) 290070af384SBlue Swirl { 291070af384SBlue Swirl switch (pstate) { 292070af384SBlue Swirl default: 293870be6adSBlue Swirl trace_win_helper_gregset_error(pstate); 294070af384SBlue Swirl /* pass through to normal set of global registers */ 295070af384SBlue Swirl case 0: 296070af384SBlue Swirl return env->bgregs; 297070af384SBlue Swirl case PS_AG: 298070af384SBlue Swirl return env->agregs; 299070af384SBlue Swirl case PS_MG: 300070af384SBlue Swirl return env->mgregs; 301070af384SBlue Swirl case PS_IG: 302070af384SBlue Swirl return env->igregs; 303070af384SBlue Swirl } 304070af384SBlue Swirl } 305070af384SBlue Swirl 306c5f9864eSAndreas Färber void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate) 307070af384SBlue Swirl { 308070af384SBlue Swirl uint32_t pstate_regs, new_pstate_regs; 309070af384SBlue Swirl uint64_t *src, *dst; 310070af384SBlue Swirl 311070af384SBlue Swirl if (env->def->features & CPU_FEATURE_GL) { 312070af384SBlue Swirl /* PS_AG is not implemented in this case */ 313070af384SBlue Swirl new_pstate &= ~PS_AG; 314070af384SBlue Swirl } 315070af384SBlue Swirl 316070af384SBlue Swirl pstate_regs = env->pstate & 0xc01; 317070af384SBlue Swirl new_pstate_regs = new_pstate & 0xc01; 318070af384SBlue Swirl 319070af384SBlue Swirl if (new_pstate_regs != pstate_regs) { 320870be6adSBlue Swirl trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs); 321870be6adSBlue Swirl 322070af384SBlue Swirl /* Switch global register bank */ 323063c3675SBlue Swirl src = get_gregset(env, new_pstate_regs); 324063c3675SBlue Swirl dst = get_gregset(env, pstate_regs); 325070af384SBlue Swirl memcpy32(dst, env->gregs); 326070af384SBlue Swirl memcpy32(env->gregs, src); 327070af384SBlue Swirl } else { 328870be6adSBlue Swirl trace_win_helper_no_switch_pstate(new_pstate_regs); 329070af384SBlue Swirl } 330070af384SBlue Swirl env->pstate = new_pstate; 331070af384SBlue Swirl } 332070af384SBlue Swirl 333c5f9864eSAndreas Färber void helper_wrpstate(CPUSPARCState *env, target_ulong new_state) 334070af384SBlue Swirl { 335063c3675SBlue Swirl cpu_change_pstate(env, new_state & 0xf3f); 336070af384SBlue Swirl 337070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 338070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 339070af384SBlue Swirl cpu_check_irqs(env); 340070af384SBlue Swirl } 341070af384SBlue Swirl #endif 342070af384SBlue Swirl } 343070af384SBlue Swirl 344c5f9864eSAndreas Färber void helper_wrpil(CPUSPARCState *env, target_ulong new_pil) 345070af384SBlue Swirl { 346070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 347870be6adSBlue Swirl trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil); 348070af384SBlue Swirl 349070af384SBlue Swirl env->psrpil = new_pil; 350070af384SBlue Swirl 351070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 352070af384SBlue Swirl cpu_check_irqs(env); 353070af384SBlue Swirl } 354070af384SBlue Swirl #endif 355070af384SBlue Swirl } 356070af384SBlue Swirl 357c5f9864eSAndreas Färber void helper_done(CPUSPARCState *env) 358070af384SBlue Swirl { 359070af384SBlue Swirl trap_state *tsptr = cpu_tsptr(env); 360070af384SBlue Swirl 361070af384SBlue Swirl env->pc = tsptr->tnpc; 362070af384SBlue Swirl env->npc = tsptr->tnpc + 4; 363063c3675SBlue Swirl cpu_put_ccr(env, tsptr->tstate >> 32); 364070af384SBlue Swirl env->asi = (tsptr->tstate >> 24) & 0xff; 365063c3675SBlue Swirl cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); 366063c3675SBlue Swirl cpu_put_cwp64(env, tsptr->tstate & 0xff); 367070af384SBlue Swirl env->tl--; 368070af384SBlue Swirl 369870be6adSBlue Swirl trace_win_helper_done(env->tl); 370070af384SBlue Swirl 371070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 372070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 373070af384SBlue Swirl cpu_check_irqs(env); 374070af384SBlue Swirl } 375070af384SBlue Swirl #endif 376070af384SBlue Swirl } 377070af384SBlue Swirl 378c5f9864eSAndreas Färber void helper_retry(CPUSPARCState *env) 379070af384SBlue Swirl { 380070af384SBlue Swirl trap_state *tsptr = cpu_tsptr(env); 381070af384SBlue Swirl 382070af384SBlue Swirl env->pc = tsptr->tpc; 383070af384SBlue Swirl env->npc = tsptr->tnpc; 384063c3675SBlue Swirl cpu_put_ccr(env, tsptr->tstate >> 32); 385070af384SBlue Swirl env->asi = (tsptr->tstate >> 24) & 0xff; 386063c3675SBlue Swirl cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); 387063c3675SBlue Swirl cpu_put_cwp64(env, tsptr->tstate & 0xff); 388070af384SBlue Swirl env->tl--; 389070af384SBlue Swirl 390870be6adSBlue Swirl trace_win_helper_retry(env->tl); 391070af384SBlue Swirl 392070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 393070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 394070af384SBlue Swirl cpu_check_irqs(env); 395070af384SBlue Swirl } 396070af384SBlue Swirl #endif 397070af384SBlue Swirl } 398070af384SBlue Swirl #endif 399