qemu/target-sparc/win_helper.c
<<
>>
Prefs
   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 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 "cpu.h"
  21#include "helper.h"
  22#include "trace.h"
  23
  24static inline void memcpy32(target_ulong *dst, const target_ulong *src)
  25{
  26    dst[0] = src[0];
  27    dst[1] = src[1];
  28    dst[2] = src[2];
  29    dst[3] = src[3];
  30    dst[4] = src[4];
  31    dst[5] = src[5];
  32    dst[6] = src[6];
  33    dst[7] = src[7];
  34}
  35
  36void cpu_set_cwp(CPUSPARCState *env, int new_cwp)
  37{
  38    /* put the modified wrap registers at their proper location */
  39    if (env->cwp == env->nwindows - 1) {
  40        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
  41    }
  42    env->cwp = new_cwp;
  43
  44    /* put the wrap registers at their temporary location */
  45    if (new_cwp == env->nwindows - 1) {
  46        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
  47    }
  48    env->regwptr = env->regbase + (new_cwp * 16);
  49}
  50
  51target_ulong cpu_get_psr(CPUSPARCState *env)
  52{
  53    helper_compute_psr(env);
  54
  55#if !defined(TARGET_SPARC64)
  56    return env->version | (env->psr & PSR_ICC) |
  57        (env->psref ? PSR_EF : 0) |
  58        (env->psrpil << 8) |
  59        (env->psrs ? PSR_S : 0) |
  60        (env->psrps ? PSR_PS : 0) |
  61        (env->psret ? PSR_ET : 0) | env->cwp;
  62#else
  63    return env->psr & PSR_ICC;
  64#endif
  65}
  66
  67void cpu_put_psr(CPUSPARCState *env, target_ulong val)
  68{
  69    env->psr = val & PSR_ICC;
  70#if !defined(TARGET_SPARC64)
  71    env->psref = (val & PSR_EF) ? 1 : 0;
  72    env->psrpil = (val & PSR_PIL) >> 8;
  73#endif
  74#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
  75    cpu_check_irqs(env);
  76#endif
  77#if !defined(TARGET_SPARC64)
  78    env->psrs = (val & PSR_S) ? 1 : 0;
  79    env->psrps = (val & PSR_PS) ? 1 : 0;
  80    env->psret = (val & PSR_ET) ? 1 : 0;
  81    cpu_set_cwp(env, val & PSR_CWP);
  82#endif
  83    env->cc_op = CC_OP_FLAGS;
  84}
  85
  86int cpu_cwp_inc(CPUSPARCState *env, int cwp)
  87{
  88    if (unlikely(cwp >= env->nwindows)) {
  89        cwp -= env->nwindows;
  90    }
  91    return cwp;
  92}
  93
  94int cpu_cwp_dec(CPUSPARCState *env, int cwp)
  95{
  96    if (unlikely(cwp < 0)) {
  97        cwp += env->nwindows;
  98    }
  99    return cwp;
 100}
 101
 102#ifndef TARGET_SPARC64
 103void helper_rett(CPUSPARCState *env)
 104{
 105    unsigned int cwp;
 106
 107    if (env->psret == 1) {
 108        helper_raise_exception(env, TT_ILL_INSN);
 109    }
 110
 111    env->psret = 1;
 112    cwp = cpu_cwp_inc(env, env->cwp + 1) ;
 113    if (env->wim & (1 << cwp)) {
 114        helper_raise_exception(env, TT_WIN_UNF);
 115    }
 116    cpu_set_cwp(env, cwp);
 117    env->psrs = env->psrps;
 118}
 119
 120/* XXX: use another pointer for %iN registers to avoid slow wrapping
 121   handling ? */
 122void helper_save(CPUSPARCState *env)
 123{
 124    uint32_t cwp;
 125
 126    cwp = cpu_cwp_dec(env, env->cwp - 1);
 127    if (env->wim & (1 << cwp)) {
 128        helper_raise_exception(env, TT_WIN_OVF);
 129    }
 130    cpu_set_cwp(env, cwp);
 131}
 132
 133void helper_restore(CPUSPARCState *env)
 134{
 135    uint32_t cwp;
 136
 137    cwp = cpu_cwp_inc(env, env->cwp + 1);
 138    if (env->wim & (1 << cwp)) {
 139        helper_raise_exception(env, TT_WIN_UNF);
 140    }
 141    cpu_set_cwp(env, cwp);
 142}
 143
 144void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
 145{
 146    if ((new_psr & PSR_CWP) >= env->nwindows) {
 147        helper_raise_exception(env, TT_ILL_INSN);
 148    } else {
 149        cpu_put_psr(env, new_psr);
 150    }
 151}
 152
 153target_ulong helper_rdpsr(CPUSPARCState *env)
 154{
 155    return cpu_get_psr(env);
 156}
 157
 158#else
 159/* XXX: use another pointer for %iN registers to avoid slow wrapping
 160   handling ? */
 161void helper_save(CPUSPARCState *env)
 162{
 163    uint32_t cwp;
 164
 165    cwp = cpu_cwp_dec(env, env->cwp - 1);
 166    if (env->cansave == 0) {
 167        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
 168                                                (TT_WOTHER |
 169                                                 ((env->wstate & 0x38) >> 1)) :
 170                                                ((env->wstate & 0x7) << 2)));
 171    } else {
 172        if (env->cleanwin - env->canrestore == 0) {
 173            /* XXX Clean windows without trap */
 174            helper_raise_exception(env, TT_CLRWIN);
 175        } else {
 176            env->cansave--;
 177            env->canrestore++;
 178            cpu_set_cwp(env, cwp);
 179        }
 180    }
 181}
 182
 183void helper_restore(CPUSPARCState *env)
 184{
 185    uint32_t cwp;
 186
 187    cwp = cpu_cwp_inc(env, env->cwp + 1);
 188    if (env->canrestore == 0) {
 189        helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
 190                                               (TT_WOTHER |
 191                                                ((env->wstate & 0x38) >> 1)) :
 192                                               ((env->wstate & 0x7) << 2)));
 193    } else {
 194        env->cansave++;
 195        env->canrestore--;
 196        cpu_set_cwp(env, cwp);
 197    }
 198}
 199
 200void helper_flushw(CPUSPARCState *env)
 201{
 202    if (env->cansave != env->nwindows - 2) {
 203        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
 204                                                (TT_WOTHER |
 205                                                 ((env->wstate & 0x38) >> 1)) :
 206                                                ((env->wstate & 0x7) << 2)));
 207    }
 208}
 209
 210void helper_saved(CPUSPARCState *env)
 211{
 212    env->cansave++;
 213    if (env->otherwin == 0) {
 214        env->canrestore--;
 215    } else {
 216        env->otherwin--;
 217    }
 218}
 219
 220void helper_restored(CPUSPARCState *env)
 221{
 222    env->canrestore++;
 223    if (env->cleanwin < env->nwindows - 1) {
 224        env->cleanwin++;
 225    }
 226    if (env->otherwin == 0) {
 227        env->cansave--;
 228    } else {
 229        env->otherwin--;
 230    }
 231}
 232
 233target_ulong cpu_get_ccr(CPUSPARCState *env)
 234{
 235    target_ulong psr;
 236
 237    psr = cpu_get_psr(env);
 238
 239    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
 240}
 241
 242void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
 243{
 244    env->xcc = (val >> 4) << 20;
 245    env->psr = (val & 0xf) << 20;
 246    CC_OP = CC_OP_FLAGS;
 247}
 248
 249target_ulong cpu_get_cwp64(CPUSPARCState *env)
 250{
 251    return env->nwindows - 1 - env->cwp;
 252}
 253
 254void cpu_put_cwp64(CPUSPARCState *env, int cwp)
 255{
 256    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
 257        cwp %= env->nwindows;
 258    }
 259    cpu_set_cwp(env, env->nwindows - 1 - cwp);
 260}
 261
 262target_ulong helper_rdccr(CPUSPARCState *env)
 263{
 264    return cpu_get_ccr(env);
 265}
 266
 267void helper_wrccr(CPUSPARCState *env, target_ulong new_ccr)
 268{
 269    cpu_put_ccr(env, new_ccr);
 270}
 271
 272/* CWP handling is reversed in V9, but we still use the V8 register
 273   order. */
 274target_ulong helper_rdcwp(CPUSPARCState *env)
 275{
 276    return cpu_get_cwp64(env);
 277}
 278
 279void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp)
 280{
 281    cpu_put_cwp64(env, new_cwp);
 282}
 283
 284static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
 285{
 286    switch (pstate) {
 287    default:
 288        trace_win_helper_gregset_error(pstate);
 289        /* pass through to normal set of global registers */
 290    case 0:
 291        return env->bgregs;
 292    case PS_AG:
 293        return env->agregs;
 294    case PS_MG:
 295        return env->mgregs;
 296    case PS_IG:
 297        return env->igregs;
 298    }
 299}
 300
 301void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate)
 302{
 303    uint32_t pstate_regs, new_pstate_regs;
 304    uint64_t *src, *dst;
 305
 306    if (env->def->features & CPU_FEATURE_GL) {
 307        /* PS_AG is not implemented in this case */
 308        new_pstate &= ~PS_AG;
 309    }
 310
 311    pstate_regs = env->pstate & 0xc01;
 312    new_pstate_regs = new_pstate & 0xc01;
 313
 314    if (new_pstate_regs != pstate_regs) {
 315        trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
 316
 317        /* Switch global register bank */
 318        src = get_gregset(env, new_pstate_regs);
 319        dst = get_gregset(env, pstate_regs);
 320        memcpy32(dst, env->gregs);
 321        memcpy32(env->gregs, src);
 322    } else {
 323        trace_win_helper_no_switch_pstate(new_pstate_regs);
 324    }
 325    env->pstate = new_pstate;
 326}
 327
 328void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
 329{
 330    cpu_change_pstate(env, new_state & 0xf3f);
 331
 332#if !defined(CONFIG_USER_ONLY)
 333    if (cpu_interrupts_enabled(env)) {
 334        cpu_check_irqs(env);
 335    }
 336#endif
 337}
 338
 339void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
 340{
 341#if !defined(CONFIG_USER_ONLY)
 342    trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
 343
 344    env->psrpil = new_pil;
 345
 346    if (cpu_interrupts_enabled(env)) {
 347        cpu_check_irqs(env);
 348    }
 349#endif
 350}
 351
 352void helper_done(CPUSPARCState *env)
 353{
 354    trap_state *tsptr = cpu_tsptr(env);
 355
 356    env->pc = tsptr->tnpc;
 357    env->npc = tsptr->tnpc + 4;
 358    cpu_put_ccr(env, tsptr->tstate >> 32);
 359    env->asi = (tsptr->tstate >> 24) & 0xff;
 360    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
 361    cpu_put_cwp64(env, tsptr->tstate & 0xff);
 362    env->tl--;
 363
 364    trace_win_helper_done(env->tl);
 365
 366#if !defined(CONFIG_USER_ONLY)
 367    if (cpu_interrupts_enabled(env)) {
 368        cpu_check_irqs(env);
 369    }
 370#endif
 371}
 372
 373void helper_retry(CPUSPARCState *env)
 374{
 375    trap_state *tsptr = cpu_tsptr(env);
 376
 377    env->pc = tsptr->tpc;
 378    env->npc = tsptr->tnpc;
 379    cpu_put_ccr(env, tsptr->tstate >> 32);
 380    env->asi = (tsptr->tstate >> 24) & 0xff;
 381    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
 382    cpu_put_cwp64(env, tsptr->tstate & 0xff);
 383    env->tl--;
 384
 385    trace_win_helper_retry(env->tl);
 386
 387#if !defined(CONFIG_USER_ONLY)
 388    if (cpu_interrupts_enabled(env)) {
 389        cpu_check_irqs(env);
 390    }
 391#endif
 392}
 393#endif
 394