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" 21070af384SBlue Swirl #include "helper.h" 22070af384SBlue Swirl 23070af384SBlue Swirl //#define DEBUG_PSTATE 24070af384SBlue Swirl 25070af384SBlue Swirl #ifdef DEBUG_PSTATE 26070af384SBlue Swirl #define DPRINTF_PSTATE(fmt, ...) \ 27070af384SBlue Swirl do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0) 28070af384SBlue Swirl #else 29070af384SBlue Swirl #define DPRINTF_PSTATE(fmt, ...) do {} while (0) 30070af384SBlue Swirl #endif 31070af384SBlue Swirl 32070af384SBlue Swirl static inline void memcpy32(target_ulong *dst, const target_ulong *src) 33070af384SBlue Swirl { 34070af384SBlue Swirl dst[0] = src[0]; 35070af384SBlue Swirl dst[1] = src[1]; 36070af384SBlue Swirl dst[2] = src[2]; 37070af384SBlue Swirl dst[3] = src[3]; 38070af384SBlue Swirl dst[4] = src[4]; 39070af384SBlue Swirl dst[5] = src[5]; 40070af384SBlue Swirl dst[6] = src[6]; 41070af384SBlue Swirl dst[7] = src[7]; 42070af384SBlue Swirl } 43070af384SBlue Swirl 44063c3675SBlue Swirl void cpu_set_cwp(CPUState *env, int new_cwp) 45070af384SBlue Swirl { 46070af384SBlue Swirl /* put the modified wrap registers at their proper location */ 47070af384SBlue Swirl if (env->cwp == env->nwindows - 1) { 48070af384SBlue Swirl memcpy32(env->regbase, env->regbase + env->nwindows * 16); 49070af384SBlue Swirl } 50070af384SBlue Swirl env->cwp = new_cwp; 51070af384SBlue Swirl 52070af384SBlue Swirl /* put the wrap registers at their temporary location */ 53070af384SBlue Swirl if (new_cwp == env->nwindows - 1) { 54070af384SBlue Swirl memcpy32(env->regbase + env->nwindows * 16, env->regbase); 55070af384SBlue Swirl } 56070af384SBlue Swirl env->regwptr = env->regbase + (new_cwp * 16); 57070af384SBlue Swirl } 58070af384SBlue Swirl 59063c3675SBlue Swirl target_ulong cpu_get_psr(CPUState *env) 60070af384SBlue Swirl { 61070af384SBlue Swirl helper_compute_psr(env); 62070af384SBlue Swirl 63070af384SBlue Swirl #if !defined(TARGET_SPARC64) 64070af384SBlue Swirl return env->version | (env->psr & PSR_ICC) | 65070af384SBlue Swirl (env->psref ? PSR_EF : 0) | 66070af384SBlue Swirl (env->psrpil << 8) | 67070af384SBlue Swirl (env->psrs ? PSR_S : 0) | 68070af384SBlue Swirl (env->psrps ? PSR_PS : 0) | 69070af384SBlue Swirl (env->psret ? PSR_ET : 0) | env->cwp; 70070af384SBlue Swirl #else 71070af384SBlue Swirl return env->psr & PSR_ICC; 72070af384SBlue Swirl #endif 73070af384SBlue Swirl } 74070af384SBlue Swirl 75063c3675SBlue Swirl void cpu_put_psr(CPUState *env, target_ulong val) 76070af384SBlue Swirl { 77070af384SBlue Swirl env->psr = val & PSR_ICC; 78070af384SBlue Swirl #if !defined(TARGET_SPARC64) 79070af384SBlue Swirl env->psref = (val & PSR_EF) ? 1 : 0; 80070af384SBlue Swirl env->psrpil = (val & PSR_PIL) >> 8; 81070af384SBlue Swirl #endif 82070af384SBlue Swirl #if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) 83070af384SBlue Swirl cpu_check_irqs(env); 84070af384SBlue Swirl #endif 85070af384SBlue Swirl #if !defined(TARGET_SPARC64) 86070af384SBlue Swirl env->psrs = (val & PSR_S) ? 1 : 0; 87070af384SBlue Swirl env->psrps = (val & PSR_PS) ? 1 : 0; 88070af384SBlue Swirl env->psret = (val & PSR_ET) ? 1 : 0; 89063c3675SBlue Swirl cpu_set_cwp(env, val & PSR_CWP); 90070af384SBlue Swirl #endif 91070af384SBlue Swirl env->cc_op = CC_OP_FLAGS; 92070af384SBlue Swirl } 93070af384SBlue Swirl 94063c3675SBlue Swirl int cpu_cwp_inc(CPUState *env, int cwp) 95070af384SBlue Swirl { 96070af384SBlue Swirl if (unlikely(cwp >= env->nwindows)) { 97070af384SBlue Swirl cwp -= env->nwindows; 98070af384SBlue Swirl } 99070af384SBlue Swirl return cwp; 100070af384SBlue Swirl } 101070af384SBlue Swirl 102063c3675SBlue Swirl int cpu_cwp_dec(CPUState *env, int cwp) 103070af384SBlue Swirl { 104070af384SBlue Swirl if (unlikely(cwp < 0)) { 105070af384SBlue Swirl cwp += env->nwindows; 106070af384SBlue Swirl } 107070af384SBlue Swirl return cwp; 108070af384SBlue Swirl } 109070af384SBlue Swirl 110070af384SBlue Swirl #ifndef TARGET_SPARC64 111063c3675SBlue Swirl void helper_rett(CPUState *env) 112070af384SBlue Swirl { 113070af384SBlue Swirl unsigned int cwp; 114070af384SBlue Swirl 115070af384SBlue Swirl if (env->psret == 1) { 116070af384SBlue Swirl helper_raise_exception(env, TT_ILL_INSN); 117070af384SBlue Swirl } 118070af384SBlue Swirl 119070af384SBlue Swirl env->psret = 1; 120063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1) ; 121070af384SBlue Swirl if (env->wim & (1 << cwp)) { 122070af384SBlue Swirl helper_raise_exception(env, TT_WIN_UNF); 123070af384SBlue Swirl } 124063c3675SBlue Swirl cpu_set_cwp(env, cwp); 125070af384SBlue Swirl env->psrs = env->psrps; 126070af384SBlue Swirl } 127070af384SBlue Swirl 128070af384SBlue Swirl /* XXX: use another pointer for %iN registers to avoid slow wrapping 129070af384SBlue Swirl handling ? */ 130063c3675SBlue Swirl void helper_save(CPUState *env) 131070af384SBlue Swirl { 132070af384SBlue Swirl uint32_t cwp; 133070af384SBlue Swirl 134063c3675SBlue Swirl cwp = cpu_cwp_dec(env, env->cwp - 1); 135070af384SBlue Swirl if (env->wim & (1 << cwp)) { 136070af384SBlue Swirl helper_raise_exception(env, TT_WIN_OVF); 137070af384SBlue Swirl } 138063c3675SBlue Swirl cpu_set_cwp(env, cwp); 139070af384SBlue Swirl } 140070af384SBlue Swirl 141063c3675SBlue Swirl void helper_restore(CPUState *env) 142070af384SBlue Swirl { 143070af384SBlue Swirl uint32_t cwp; 144070af384SBlue Swirl 145063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1); 146070af384SBlue Swirl if (env->wim & (1 << cwp)) { 147070af384SBlue Swirl helper_raise_exception(env, TT_WIN_UNF); 148070af384SBlue Swirl } 149063c3675SBlue Swirl cpu_set_cwp(env, cwp); 150070af384SBlue Swirl } 151070af384SBlue Swirl 152063c3675SBlue Swirl void helper_wrpsr(CPUState *env, target_ulong new_psr) 153070af384SBlue Swirl { 154070af384SBlue Swirl if ((new_psr & PSR_CWP) >= env->nwindows) { 155070af384SBlue Swirl helper_raise_exception(env, TT_ILL_INSN); 156070af384SBlue Swirl } else { 157070af384SBlue Swirl cpu_put_psr(env, new_psr); 158070af384SBlue Swirl } 159070af384SBlue Swirl } 160070af384SBlue Swirl 161063c3675SBlue Swirl target_ulong helper_rdpsr(CPUState *env) 162070af384SBlue Swirl { 163063c3675SBlue Swirl return cpu_get_psr(env); 164070af384SBlue Swirl } 165070af384SBlue Swirl 166070af384SBlue Swirl #else 167070af384SBlue Swirl /* XXX: use another pointer for %iN registers to avoid slow wrapping 168070af384SBlue Swirl handling ? */ 169063c3675SBlue Swirl void helper_save(CPUState *env) 170070af384SBlue Swirl { 171070af384SBlue Swirl uint32_t cwp; 172070af384SBlue Swirl 173063c3675SBlue Swirl cwp = cpu_cwp_dec(env, env->cwp - 1); 174070af384SBlue Swirl if (env->cansave == 0) { 175070af384SBlue Swirl helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? 176070af384SBlue Swirl (TT_WOTHER | 177070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 178070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 179070af384SBlue Swirl } else { 180070af384SBlue Swirl if (env->cleanwin - env->canrestore == 0) { 181070af384SBlue Swirl /* XXX Clean windows without trap */ 182070af384SBlue Swirl helper_raise_exception(env, TT_CLRWIN); 183070af384SBlue Swirl } else { 184070af384SBlue Swirl env->cansave--; 185070af384SBlue Swirl env->canrestore++; 186063c3675SBlue Swirl cpu_set_cwp(env, cwp); 187070af384SBlue Swirl } 188070af384SBlue Swirl } 189070af384SBlue Swirl } 190070af384SBlue Swirl 191063c3675SBlue Swirl void helper_restore(CPUState *env) 192070af384SBlue Swirl { 193070af384SBlue Swirl uint32_t cwp; 194070af384SBlue Swirl 195063c3675SBlue Swirl cwp = cpu_cwp_inc(env, env->cwp + 1); 196070af384SBlue Swirl if (env->canrestore == 0) { 197070af384SBlue Swirl helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ? 198070af384SBlue Swirl (TT_WOTHER | 199070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 200070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 201070af384SBlue Swirl } else { 202070af384SBlue Swirl env->cansave++; 203070af384SBlue Swirl env->canrestore--; 204063c3675SBlue Swirl cpu_set_cwp(env, cwp); 205070af384SBlue Swirl } 206070af384SBlue Swirl } 207070af384SBlue Swirl 208063c3675SBlue Swirl void helper_flushw(CPUState *env) 209070af384SBlue Swirl { 210070af384SBlue Swirl if (env->cansave != env->nwindows - 2) { 211070af384SBlue Swirl helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? 212070af384SBlue Swirl (TT_WOTHER | 213070af384SBlue Swirl ((env->wstate & 0x38) >> 1)) : 214070af384SBlue Swirl ((env->wstate & 0x7) << 2))); 215070af384SBlue Swirl } 216070af384SBlue Swirl } 217070af384SBlue Swirl 218063c3675SBlue Swirl void helper_saved(CPUState *env) 219070af384SBlue Swirl { 220070af384SBlue Swirl env->cansave++; 221070af384SBlue Swirl if (env->otherwin == 0) { 222070af384SBlue Swirl env->canrestore--; 223070af384SBlue Swirl } else { 224070af384SBlue Swirl env->otherwin--; 225070af384SBlue Swirl } 226070af384SBlue Swirl } 227070af384SBlue Swirl 228063c3675SBlue Swirl void helper_restored(CPUState *env) 229070af384SBlue Swirl { 230070af384SBlue Swirl env->canrestore++; 231070af384SBlue Swirl if (env->cleanwin < env->nwindows - 1) { 232070af384SBlue Swirl env->cleanwin++; 233070af384SBlue Swirl } 234070af384SBlue Swirl if (env->otherwin == 0) { 235070af384SBlue Swirl env->cansave--; 236070af384SBlue Swirl } else { 237070af384SBlue Swirl env->otherwin--; 238070af384SBlue Swirl } 239070af384SBlue Swirl } 240070af384SBlue Swirl 241063c3675SBlue Swirl target_ulong cpu_get_ccr(CPUState *env) 242070af384SBlue Swirl { 243070af384SBlue Swirl target_ulong psr; 244070af384SBlue Swirl 245063c3675SBlue Swirl psr = cpu_get_psr(env); 246070af384SBlue Swirl 247070af384SBlue Swirl return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); 248070af384SBlue Swirl } 249070af384SBlue Swirl 250063c3675SBlue Swirl void cpu_put_ccr(CPUState *env, target_ulong val) 251070af384SBlue Swirl { 252070af384SBlue Swirl env->xcc = (val >> 4) << 20; 253070af384SBlue Swirl env->psr = (val & 0xf) << 20; 254070af384SBlue Swirl CC_OP = CC_OP_FLAGS; 255070af384SBlue Swirl } 256070af384SBlue Swirl 257063c3675SBlue Swirl target_ulong cpu_get_cwp64(CPUState *env) 258070af384SBlue Swirl { 259070af384SBlue Swirl return env->nwindows - 1 - env->cwp; 260070af384SBlue Swirl } 261070af384SBlue Swirl 262063c3675SBlue Swirl void cpu_put_cwp64(CPUState *env, int cwp) 263070af384SBlue Swirl { 264070af384SBlue Swirl if (unlikely(cwp >= env->nwindows || cwp < 0)) { 265070af384SBlue Swirl cwp %= env->nwindows; 266070af384SBlue Swirl } 267063c3675SBlue Swirl cpu_set_cwp(env, env->nwindows - 1 - cwp); 268070af384SBlue Swirl } 269070af384SBlue Swirl 270063c3675SBlue Swirl target_ulong helper_rdccr(CPUState *env) 271070af384SBlue Swirl { 272063c3675SBlue Swirl return cpu_get_ccr(env); 273070af384SBlue Swirl } 274070af384SBlue Swirl 275063c3675SBlue Swirl void helper_wrccr(CPUState *env, target_ulong new_ccr) 276070af384SBlue Swirl { 277063c3675SBlue Swirl cpu_put_ccr(env, new_ccr); 278070af384SBlue Swirl } 279070af384SBlue Swirl 280070af384SBlue Swirl /* CWP handling is reversed in V9, but we still use the V8 register 281070af384SBlue Swirl order. */ 282063c3675SBlue Swirl target_ulong helper_rdcwp(CPUState *env) 283070af384SBlue Swirl { 284063c3675SBlue Swirl return cpu_get_cwp64(env); 285070af384SBlue Swirl } 286070af384SBlue Swirl 287063c3675SBlue Swirl void helper_wrcwp(CPUState *env, target_ulong new_cwp) 288070af384SBlue Swirl { 289063c3675SBlue Swirl cpu_put_cwp64(env, new_cwp); 290070af384SBlue Swirl } 291070af384SBlue Swirl 292063c3675SBlue Swirl static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate) 293070af384SBlue Swirl { 294070af384SBlue Swirl switch (pstate) { 295070af384SBlue Swirl default: 296070af384SBlue Swirl DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n", 297070af384SBlue Swirl pstate, 298070af384SBlue Swirl (pstate & PS_IG) ? " IG" : "", 299070af384SBlue Swirl (pstate & PS_MG) ? " MG" : "", 300070af384SBlue Swirl (pstate & PS_AG) ? " AG" : ""); 301070af384SBlue Swirl /* pass through to normal set of global registers */ 302070af384SBlue Swirl case 0: 303070af384SBlue Swirl return env->bgregs; 304070af384SBlue Swirl case PS_AG: 305070af384SBlue Swirl return env->agregs; 306070af384SBlue Swirl case PS_MG: 307070af384SBlue Swirl return env->mgregs; 308070af384SBlue Swirl case PS_IG: 309070af384SBlue Swirl return env->igregs; 310070af384SBlue Swirl } 311070af384SBlue Swirl } 312070af384SBlue Swirl 313063c3675SBlue Swirl void cpu_change_pstate(CPUState *env, uint32_t new_pstate) 314070af384SBlue Swirl { 315070af384SBlue Swirl uint32_t pstate_regs, new_pstate_regs; 316070af384SBlue Swirl uint64_t *src, *dst; 317070af384SBlue Swirl 318070af384SBlue Swirl if (env->def->features & CPU_FEATURE_GL) { 319070af384SBlue Swirl /* PS_AG is not implemented in this case */ 320070af384SBlue Swirl new_pstate &= ~PS_AG; 321070af384SBlue Swirl } 322070af384SBlue Swirl 323070af384SBlue Swirl pstate_regs = env->pstate & 0xc01; 324070af384SBlue Swirl new_pstate_regs = new_pstate & 0xc01; 325070af384SBlue Swirl 326070af384SBlue Swirl if (new_pstate_regs != pstate_regs) { 327070af384SBlue Swirl DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n", 328070af384SBlue Swirl pstate_regs, new_pstate_regs); 329070af384SBlue Swirl /* Switch global register bank */ 330063c3675SBlue Swirl src = get_gregset(env, new_pstate_regs); 331063c3675SBlue Swirl dst = get_gregset(env, pstate_regs); 332070af384SBlue Swirl memcpy32(dst, env->gregs); 333070af384SBlue Swirl memcpy32(env->gregs, src); 334070af384SBlue Swirl } else { 335070af384SBlue Swirl DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n", 336070af384SBlue Swirl new_pstate_regs); 337070af384SBlue Swirl } 338070af384SBlue Swirl env->pstate = new_pstate; 339070af384SBlue Swirl } 340070af384SBlue Swirl 341063c3675SBlue Swirl void helper_wrpstate(CPUState *env, target_ulong new_state) 342070af384SBlue Swirl { 343063c3675SBlue Swirl cpu_change_pstate(env, new_state & 0xf3f); 344070af384SBlue Swirl 345070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 346070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 347070af384SBlue Swirl cpu_check_irqs(env); 348070af384SBlue Swirl } 349070af384SBlue Swirl #endif 350070af384SBlue Swirl } 351070af384SBlue Swirl 352063c3675SBlue Swirl void helper_wrpil(CPUState *env, target_ulong new_pil) 353070af384SBlue Swirl { 354070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 355070af384SBlue Swirl DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n", 356070af384SBlue Swirl env->psrpil, (uint32_t)new_pil); 357070af384SBlue Swirl 358070af384SBlue Swirl env->psrpil = new_pil; 359070af384SBlue Swirl 360070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 361070af384SBlue Swirl cpu_check_irqs(env); 362070af384SBlue Swirl } 363070af384SBlue Swirl #endif 364070af384SBlue Swirl } 365070af384SBlue Swirl 366063c3675SBlue Swirl void helper_done(CPUState *env) 367070af384SBlue Swirl { 368070af384SBlue Swirl trap_state *tsptr = cpu_tsptr(env); 369070af384SBlue Swirl 370070af384SBlue Swirl env->pc = tsptr->tnpc; 371070af384SBlue Swirl env->npc = tsptr->tnpc + 4; 372063c3675SBlue Swirl cpu_put_ccr(env, tsptr->tstate >> 32); 373070af384SBlue Swirl env->asi = (tsptr->tstate >> 24) & 0xff; 374063c3675SBlue Swirl cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); 375063c3675SBlue Swirl cpu_put_cwp64(env, tsptr->tstate & 0xff); 376070af384SBlue Swirl env->tl--; 377070af384SBlue Swirl 378070af384SBlue Swirl DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl); 379070af384SBlue Swirl 380070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 381070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 382070af384SBlue Swirl cpu_check_irqs(env); 383070af384SBlue Swirl } 384070af384SBlue Swirl #endif 385070af384SBlue Swirl } 386070af384SBlue Swirl 387063c3675SBlue Swirl void helper_retry(CPUState *env) 388070af384SBlue Swirl { 389070af384SBlue Swirl trap_state *tsptr = cpu_tsptr(env); 390070af384SBlue Swirl 391070af384SBlue Swirl env->pc = tsptr->tpc; 392070af384SBlue Swirl env->npc = tsptr->tnpc; 393063c3675SBlue Swirl cpu_put_ccr(env, tsptr->tstate >> 32); 394070af384SBlue Swirl env->asi = (tsptr->tstate >> 24) & 0xff; 395063c3675SBlue Swirl cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); 396063c3675SBlue Swirl cpu_put_cwp64(env, tsptr->tstate & 0xff); 397070af384SBlue Swirl env->tl--; 398070af384SBlue Swirl 399070af384SBlue Swirl DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl); 400070af384SBlue Swirl 401070af384SBlue Swirl #if !defined(CONFIG_USER_ONLY) 402070af384SBlue Swirl if (cpu_interrupts_enabled(env)) { 403070af384SBlue Swirl cpu_check_irqs(env); 404070af384SBlue Swirl } 405070af384SBlue Swirl #endif 406070af384SBlue Swirl } 407070af384SBlue Swirl #endif 408