qemu/target/mips/op_helper.c
<<
>>
Prefs
   1/*
   2 *  MIPS emulation helpers for qemu.
   3 *
   4 *  Copyright (c) 2004-2005 Jocelyn Mayer
   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#include "qemu/osdep.h"
  20#include "qemu/main-loop.h"
  21#include "cpu.h"
  22#include "internal.h"
  23#include "qemu/host-utils.h"
  24#include "exec/helper-proto.h"
  25#include "exec/exec-all.h"
  26#include "exec/cpu_ldst.h"
  27#include "sysemu/kvm.h"
  28
  29/*****************************************************************************/
  30/* Exceptions processing helpers */
  31
  32void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
  33                                int error_code)
  34{
  35    do_raise_exception_err(env, exception, error_code, 0);
  36}
  37
  38void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
  39{
  40    do_raise_exception(env, exception, GETPC());
  41}
  42
  43void helper_raise_exception_debug(CPUMIPSState *env)
  44{
  45    do_raise_exception(env, EXCP_DEBUG, 0);
  46}
  47
  48static void raise_exception(CPUMIPSState *env, uint32_t exception)
  49{
  50    do_raise_exception(env, exception, 0);
  51}
  52
  53#if defined(CONFIG_USER_ONLY)
  54#define HELPER_LD(name, insn, type)                                     \
  55static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
  56                             int mem_idx, uintptr_t retaddr)            \
  57{                                                                       \
  58    return (type) cpu_##insn##_data_ra(env, addr, retaddr);             \
  59}
  60#else
  61#define HELPER_LD(name, insn, type)                                     \
  62static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
  63                             int mem_idx, uintptr_t retaddr)            \
  64{                                                                       \
  65    switch (mem_idx)                                                    \
  66    {                                                                   \
  67    case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr);   \
  68    case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr);    \
  69    default:                                                            \
  70    case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr);     \
  71    case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr);    \
  72    }                                                                   \
  73}
  74#endif
  75HELPER_LD(lw, ldl, int32_t)
  76#if defined(TARGET_MIPS64)
  77HELPER_LD(ld, ldq, int64_t)
  78#endif
  79#undef HELPER_LD
  80
  81#if defined(CONFIG_USER_ONLY)
  82#define HELPER_ST(name, insn, type)                                     \
  83static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
  84                             type val, int mem_idx, uintptr_t retaddr)  \
  85{                                                                       \
  86    cpu_##insn##_data_ra(env, addr, val, retaddr);                      \
  87}
  88#else
  89#define HELPER_ST(name, insn, type)                                     \
  90static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
  91                             type val, int mem_idx, uintptr_t retaddr)  \
  92{                                                                       \
  93    switch (mem_idx)                                                    \
  94    {                                                                   \
  95    case 0: cpu_##insn##_kernel_ra(env, addr, val, retaddr); break;     \
  96    case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break;      \
  97    default:                                                            \
  98    case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break;       \
  99    case 3:                                                             \
 100        cpu_##insn##_error_ra(env, addr, val, retaddr);                 \
 101        break;                                                          \
 102    }                                                                   \
 103}
 104#endif
 105HELPER_ST(sb, stb, uint8_t)
 106HELPER_ST(sw, stl, uint32_t)
 107#if defined(TARGET_MIPS64)
 108HELPER_ST(sd, stq, uint64_t)
 109#endif
 110#undef HELPER_ST
 111
 112/* 64 bits arithmetic for 32 bits hosts */
 113static inline uint64_t get_HILO(CPUMIPSState *env)
 114{
 115    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
 116}
 117
 118static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
 119{
 120    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
 121    return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 122}
 123
 124static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
 125{
 126    target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
 127    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 128    return tmp;
 129}
 130
 131/* Multiplication variants of the vr54xx. */
 132target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
 133                         target_ulong arg2)
 134{
 135    return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
 136                                 (int64_t)(int32_t)arg2));
 137}
 138
 139target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
 140                          target_ulong arg2)
 141{
 142    return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
 143                       (uint64_t)(uint32_t)arg2);
 144}
 145
 146target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
 147                         target_ulong arg2)
 148{
 149    return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
 150                       (int64_t)(int32_t)arg2);
 151}
 152
 153target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
 154                           target_ulong arg2)
 155{
 156    return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
 157                       (int64_t)(int32_t)arg2);
 158}
 159
 160target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
 161                          target_ulong arg2)
 162{
 163    return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
 164                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 165}
 166
 167target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
 168                            target_ulong arg2)
 169{
 170    return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
 171                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 172}
 173
 174target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
 175                         target_ulong arg2)
 176{
 177    return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
 178                       (int64_t)(int32_t)arg2);
 179}
 180
 181target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
 182                           target_ulong arg2)
 183{
 184    return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
 185                       (int64_t)(int32_t)arg2);
 186}
 187
 188target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
 189                          target_ulong arg2)
 190{
 191    return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
 192                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 193}
 194
 195target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
 196                            target_ulong arg2)
 197{
 198    return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
 199                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 200}
 201
 202target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
 203                          target_ulong arg2)
 204{
 205    return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
 206}
 207
 208target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
 209                           target_ulong arg2)
 210{
 211    return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
 212                       (uint64_t)(uint32_t)arg2);
 213}
 214
 215target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
 216                           target_ulong arg2)
 217{
 218    return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
 219                       (int64_t)(int32_t)arg2);
 220}
 221
 222target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
 223                            target_ulong arg2)
 224{
 225    return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
 226                       (uint64_t)(uint32_t)arg2);
 227}
 228
 229static inline target_ulong bitswap(target_ulong v)
 230{
 231    v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
 232              ((v & (target_ulong)0x5555555555555555ULL) << 1);
 233    v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
 234              ((v & (target_ulong)0x3333333333333333ULL) << 2);
 235    v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
 236              ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
 237    return v;
 238}
 239
 240#ifdef TARGET_MIPS64
 241target_ulong helper_dbitswap(target_ulong rt)
 242{
 243    return bitswap(rt);
 244}
 245#endif
 246
 247target_ulong helper_bitswap(target_ulong rt)
 248{
 249    return (int32_t)bitswap(rt);
 250}
 251
 252target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
 253                        uint32_t stripe)
 254{
 255    int i;
 256    uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
 257    uint64_t tmp1 = tmp0;
 258    for (i = 0; i <= 46; i++) {
 259        int s;
 260        if (i & 0x8) {
 261            s = shift;
 262        } else {
 263            s = shiftx;
 264        }
 265
 266        if (stripe != 0 && !(i & 0x4)) {
 267            s = ~s;
 268        }
 269        if (s & 0x10) {
 270            if (tmp0 & (1LL << (i + 16))) {
 271                tmp1 |= 1LL << i;
 272            } else {
 273                tmp1 &= ~(1LL << i);
 274            }
 275        }
 276    }
 277
 278    uint64_t tmp2 = tmp1;
 279    for (i = 0; i <= 38; i++) {
 280        int s;
 281        if (i & 0x4) {
 282            s = shift;
 283        } else {
 284            s = shiftx;
 285        }
 286
 287        if (s & 0x8) {
 288            if (tmp1 & (1LL << (i + 8))) {
 289                tmp2 |= 1LL << i;
 290            } else {
 291                tmp2 &= ~(1LL << i);
 292            }
 293        }
 294    }
 295
 296    uint64_t tmp3 = tmp2;
 297    for (i = 0; i <= 34; i++) {
 298        int s;
 299        if (i & 0x2) {
 300            s = shift;
 301        } else {
 302            s = shiftx;
 303        }
 304        if (s & 0x4) {
 305            if (tmp2 & (1LL << (i + 4))) {
 306                tmp3 |= 1LL << i;
 307            } else {
 308                tmp3 &= ~(1LL << i);
 309            }
 310        }
 311    }
 312
 313    uint64_t tmp4 = tmp3;
 314    for (i = 0; i <= 32; i++) {
 315        int s;
 316        if (i & 0x1) {
 317            s = shift;
 318        } else {
 319            s = shiftx;
 320        }
 321        if (s & 0x2) {
 322            if (tmp3 & (1LL << (i + 2))) {
 323                tmp4 |= 1LL << i;
 324            } else {
 325                tmp4 &= ~(1LL << i);
 326            }
 327        }
 328    }
 329
 330    uint64_t tmp5 = tmp4;
 331    for (i = 0; i <= 31; i++) {
 332        int s;
 333        s = shift;
 334        if (s & 0x1) {
 335            if (tmp4 & (1LL << (i + 1))) {
 336                tmp5 |= 1LL << i;
 337            } else {
 338                tmp5 &= ~(1LL << i);
 339            }
 340        }
 341    }
 342
 343    return (int64_t)(int32_t)(uint32_t)tmp5;
 344}
 345
 346#ifndef CONFIG_USER_ONLY
 347
 348static inline hwaddr do_translate_address(CPUMIPSState *env,
 349                                                      target_ulong address,
 350                                                      int rw, uintptr_t retaddr)
 351{
 352    hwaddr lladdr;
 353    CPUState *cs = CPU(mips_env_get_cpu(env));
 354
 355    lladdr = cpu_mips_translate_address(env, address, rw);
 356
 357    if (lladdr == -1LL) {
 358        cpu_loop_exit_restore(cs, retaddr);
 359    } else {
 360        return lladdr;
 361    }
 362}
 363
 364#define HELPER_LD_ATOMIC(name, insn, almask)                                  \
 365target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
 366{                                                                             \
 367    if (arg & almask) {                                                       \
 368        if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
 369            env->CP0_BadVAddr = arg;                                          \
 370        }                                                                     \
 371        do_raise_exception(env, EXCP_AdEL, GETPC());                          \
 372    }                                                                         \
 373    env->lladdr = do_translate_address(env, arg, 0, GETPC());                 \
 374    env->llval = do_##insn(env, arg, mem_idx, GETPC());                       \
 375    return env->llval;                                                        \
 376}
 377HELPER_LD_ATOMIC(ll, lw, 0x3)
 378#ifdef TARGET_MIPS64
 379HELPER_LD_ATOMIC(lld, ld, 0x7)
 380#endif
 381#undef HELPER_LD_ATOMIC
 382
 383#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
 384target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
 385                           target_ulong arg2, int mem_idx)                    \
 386{                                                                             \
 387    target_long tmp;                                                          \
 388                                                                              \
 389    if (arg2 & almask) {                                                      \
 390        if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
 391            env->CP0_BadVAddr = arg2;                                         \
 392        }                                                                     \
 393        do_raise_exception(env, EXCP_AdES, GETPC());                          \
 394    }                                                                         \
 395    if (do_translate_address(env, arg2, 1, GETPC()) == env->lladdr) {         \
 396        tmp = do_##ld_insn(env, arg2, mem_idx, GETPC());                      \
 397        if (tmp == env->llval) {                                              \
 398            do_##st_insn(env, arg2, arg1, mem_idx, GETPC());                  \
 399            return 1;                                                         \
 400        }                                                                     \
 401    }                                                                         \
 402    return 0;                                                                 \
 403}
 404HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
 405#ifdef TARGET_MIPS64
 406HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
 407#endif
 408#undef HELPER_ST_ATOMIC
 409#endif
 410
 411#ifdef TARGET_WORDS_BIGENDIAN
 412#define GET_LMASK(v) ((v) & 3)
 413#define GET_OFFSET(addr, offset) (addr + (offset))
 414#else
 415#define GET_LMASK(v) (((v) & 3) ^ 3)
 416#define GET_OFFSET(addr, offset) (addr - (offset))
 417#endif
 418
 419void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 420                int mem_idx)
 421{
 422    do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
 423
 424    if (GET_LMASK(arg2) <= 2) {
 425        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx,
 426              GETPC());
 427    }
 428
 429    if (GET_LMASK(arg2) <= 1) {
 430        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx,
 431              GETPC());
 432    }
 433
 434    if (GET_LMASK(arg2) == 0) {
 435        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx,
 436              GETPC());
 437    }
 438}
 439
 440void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 441                int mem_idx)
 442{
 443    do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
 444
 445    if (GET_LMASK(arg2) >= 1) {
 446        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
 447              GETPC());
 448    }
 449
 450    if (GET_LMASK(arg2) >= 2) {
 451        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
 452              GETPC());
 453    }
 454
 455    if (GET_LMASK(arg2) == 3) {
 456        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
 457              GETPC());
 458    }
 459}
 460
 461#if defined(TARGET_MIPS64)
 462/* "half" load and stores.  We must do the memory access inline,
 463   or fault handling won't work.  */
 464
 465#ifdef TARGET_WORDS_BIGENDIAN
 466#define GET_LMASK64(v) ((v) & 7)
 467#else
 468#define GET_LMASK64(v) (((v) & 7) ^ 7)
 469#endif
 470
 471void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 472                int mem_idx)
 473{
 474    do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
 475
 476    if (GET_LMASK64(arg2) <= 6) {
 477        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx,
 478              GETPC());
 479    }
 480
 481    if (GET_LMASK64(arg2) <= 5) {
 482        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx,
 483              GETPC());
 484    }
 485
 486    if (GET_LMASK64(arg2) <= 4) {
 487        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx,
 488              GETPC());
 489    }
 490
 491    if (GET_LMASK64(arg2) <= 3) {
 492        do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx,
 493              GETPC());
 494    }
 495
 496    if (GET_LMASK64(arg2) <= 2) {
 497        do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx,
 498              GETPC());
 499    }
 500
 501    if (GET_LMASK64(arg2) <= 1) {
 502        do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx,
 503              GETPC());
 504    }
 505
 506    if (GET_LMASK64(arg2) <= 0) {
 507        do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx,
 508              GETPC());
 509    }
 510}
 511
 512void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 513                int mem_idx)
 514{
 515    do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
 516
 517    if (GET_LMASK64(arg2) >= 1) {
 518        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
 519              GETPC());
 520    }
 521
 522    if (GET_LMASK64(arg2) >= 2) {
 523        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
 524              GETPC());
 525    }
 526
 527    if (GET_LMASK64(arg2) >= 3) {
 528        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
 529              GETPC());
 530    }
 531
 532    if (GET_LMASK64(arg2) >= 4) {
 533        do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx,
 534              GETPC());
 535    }
 536
 537    if (GET_LMASK64(arg2) >= 5) {
 538        do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx,
 539              GETPC());
 540    }
 541
 542    if (GET_LMASK64(arg2) >= 6) {
 543        do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx,
 544              GETPC());
 545    }
 546
 547    if (GET_LMASK64(arg2) == 7) {
 548        do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx,
 549              GETPC());
 550    }
 551}
 552#endif /* TARGET_MIPS64 */
 553
 554static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
 555
 556void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 557                uint32_t mem_idx)
 558{
 559    target_ulong base_reglist = reglist & 0xf;
 560    target_ulong do_r31 = reglist & 0x10;
 561
 562    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 563        target_ulong i;
 564
 565        for (i = 0; i < base_reglist; i++) {
 566            env->active_tc.gpr[multiple_regs[i]] =
 567                (target_long)do_lw(env, addr, mem_idx, GETPC());
 568            addr += 4;
 569        }
 570    }
 571
 572    if (do_r31) {
 573        env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx,
 574                                                    GETPC());
 575    }
 576}
 577
 578void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 579                uint32_t mem_idx)
 580{
 581    target_ulong base_reglist = reglist & 0xf;
 582    target_ulong do_r31 = reglist & 0x10;
 583
 584    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 585        target_ulong i;
 586
 587        for (i = 0; i < base_reglist; i++) {
 588            do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
 589                  GETPC());
 590            addr += 4;
 591        }
 592    }
 593
 594    if (do_r31) {
 595        do_sw(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
 596    }
 597}
 598
 599#if defined(TARGET_MIPS64)
 600void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 601                uint32_t mem_idx)
 602{
 603    target_ulong base_reglist = reglist & 0xf;
 604    target_ulong do_r31 = reglist & 0x10;
 605
 606    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 607        target_ulong i;
 608
 609        for (i = 0; i < base_reglist; i++) {
 610            env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx,
 611                                                         GETPC());
 612            addr += 8;
 613        }
 614    }
 615
 616    if (do_r31) {
 617        env->active_tc.gpr[31] = do_ld(env, addr, mem_idx, GETPC());
 618    }
 619}
 620
 621void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 622                uint32_t mem_idx)
 623{
 624    target_ulong base_reglist = reglist & 0xf;
 625    target_ulong do_r31 = reglist & 0x10;
 626
 627    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 628        target_ulong i;
 629
 630        for (i = 0; i < base_reglist; i++) {
 631            do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
 632                  GETPC());
 633            addr += 8;
 634        }
 635    }
 636
 637    if (do_r31) {
 638        do_sd(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
 639    }
 640}
 641#endif
 642
 643#ifndef CONFIG_USER_ONLY
 644/* SMP helpers.  */
 645static bool mips_vpe_is_wfi(MIPSCPU *c)
 646{
 647    CPUState *cpu = CPU(c);
 648    CPUMIPSState *env = &c->env;
 649
 650    /* If the VPE is halted but otherwise active, it means it's waiting for
 651       an interrupt.  */
 652    return cpu->halted && mips_vpe_active(env);
 653}
 654
 655static bool mips_vp_is_wfi(MIPSCPU *c)
 656{
 657    CPUState *cpu = CPU(c);
 658    CPUMIPSState *env = &c->env;
 659
 660    return cpu->halted && mips_vp_active(env);
 661}
 662
 663static inline void mips_vpe_wake(MIPSCPU *c)
 664{
 665    /* Don't set ->halted = 0 directly, let it be done via cpu_has_work
 666       because there might be other conditions that state that c should
 667       be sleeping.  */
 668    cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
 669}
 670
 671static inline void mips_vpe_sleep(MIPSCPU *cpu)
 672{
 673    CPUState *cs = CPU(cpu);
 674
 675    /* The VPE was shut off, really go to bed.
 676       Reset any old _WAKE requests.  */
 677    cs->halted = 1;
 678    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
 679}
 680
 681static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
 682{
 683    CPUMIPSState *c = &cpu->env;
 684
 685    /* FIXME: TC reschedule.  */
 686    if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
 687        mips_vpe_wake(cpu);
 688    }
 689}
 690
 691static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
 692{
 693    CPUMIPSState *c = &cpu->env;
 694
 695    /* FIXME: TC reschedule.  */
 696    if (!mips_vpe_active(c)) {
 697        mips_vpe_sleep(cpu);
 698    }
 699}
 700
 701/**
 702 * mips_cpu_map_tc:
 703 * @env: CPU from which mapping is performed.
 704 * @tc: Should point to an int with the value of the global TC index.
 705 *
 706 * This function will transform @tc into a local index within the
 707 * returned #CPUMIPSState.
 708 */
 709/* FIXME: This code assumes that all VPEs have the same number of TCs,
 710          which depends on runtime setup. Can probably be fixed by
 711          walking the list of CPUMIPSStates.  */
 712static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
 713{
 714    MIPSCPU *cpu;
 715    CPUState *cs;
 716    CPUState *other_cs;
 717    int vpe_idx;
 718    int tc_idx = *tc;
 719
 720    if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
 721        /* Not allowed to address other CPUs.  */
 722        *tc = env->current_tc;
 723        return env;
 724    }
 725
 726    cs = CPU(mips_env_get_cpu(env));
 727    vpe_idx = tc_idx / cs->nr_threads;
 728    *tc = tc_idx % cs->nr_threads;
 729    other_cs = qemu_get_cpu(vpe_idx);
 730    if (other_cs == NULL) {
 731        return env;
 732    }
 733    cpu = MIPS_CPU(other_cs);
 734    return &cpu->env;
 735}
 736
 737/* The per VPE CP0_Status register shares some fields with the per TC
 738   CP0_TCStatus registers. These fields are wired to the same registers,
 739   so changes to either of them should be reflected on both registers.
 740
 741   Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
 742
 743   These helper call synchronizes the regs for a given cpu.  */
 744
 745/* Called for updates to CP0_Status.  Defined in "cpu.h" for gdbstub.c.  */
 746/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
 747                                     int tc);  */
 748
 749/* Called for updates to CP0_TCStatus.  */
 750static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
 751                             target_ulong v)
 752{
 753    uint32_t status;
 754    uint32_t tcu, tmx, tasid, tksu;
 755    uint32_t mask = ((1U << CP0St_CU3)
 756                       | (1 << CP0St_CU2)
 757                       | (1 << CP0St_CU1)
 758                       | (1 << CP0St_CU0)
 759                       | (1 << CP0St_MX)
 760                       | (3 << CP0St_KSU));
 761
 762    tcu = (v >> CP0TCSt_TCU0) & 0xf;
 763    tmx = (v >> CP0TCSt_TMX) & 0x1;
 764    tasid = v & cpu->CP0_EntryHi_ASID_mask;
 765    tksu = (v >> CP0TCSt_TKSU) & 0x3;
 766
 767    status = tcu << CP0St_CU0;
 768    status |= tmx << CP0St_MX;
 769    status |= tksu << CP0St_KSU;
 770
 771    cpu->CP0_Status &= ~mask;
 772    cpu->CP0_Status |= status;
 773
 774    /* Sync the TASID with EntryHi.  */
 775    cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
 776    cpu->CP0_EntryHi |= tasid;
 777
 778    compute_hflags(cpu);
 779}
 780
 781/* Called for updates to CP0_EntryHi.  */
 782static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
 783{
 784    int32_t *tcst;
 785    uint32_t asid, v = cpu->CP0_EntryHi;
 786
 787    asid = v & cpu->CP0_EntryHi_ASID_mask;
 788
 789    if (tc == cpu->current_tc) {
 790        tcst = &cpu->active_tc.CP0_TCStatus;
 791    } else {
 792        tcst = &cpu->tcs[tc].CP0_TCStatus;
 793    }
 794
 795    *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
 796    *tcst |= asid;
 797}
 798
 799/* CP0 helpers */
 800target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
 801{
 802    return env->mvp->CP0_MVPControl;
 803}
 804
 805target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
 806{
 807    return env->mvp->CP0_MVPConf0;
 808}
 809
 810target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
 811{
 812    return env->mvp->CP0_MVPConf1;
 813}
 814
 815target_ulong helper_mfc0_random(CPUMIPSState *env)
 816{
 817    return (int32_t)cpu_mips_get_random(env);
 818}
 819
 820target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
 821{
 822    return env->active_tc.CP0_TCStatus;
 823}
 824
 825target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
 826{
 827    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 828    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 829
 830    if (other_tc == other->current_tc)
 831        return other->active_tc.CP0_TCStatus;
 832    else
 833        return other->tcs[other_tc].CP0_TCStatus;
 834}
 835
 836target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
 837{
 838    return env->active_tc.CP0_TCBind;
 839}
 840
 841target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
 842{
 843    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 844    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 845
 846    if (other_tc == other->current_tc)
 847        return other->active_tc.CP0_TCBind;
 848    else
 849        return other->tcs[other_tc].CP0_TCBind;
 850}
 851
 852target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
 853{
 854    return env->active_tc.PC;
 855}
 856
 857target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
 858{
 859    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 860    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 861
 862    if (other_tc == other->current_tc)
 863        return other->active_tc.PC;
 864    else
 865        return other->tcs[other_tc].PC;
 866}
 867
 868target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
 869{
 870    return env->active_tc.CP0_TCHalt;
 871}
 872
 873target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
 874{
 875    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 876    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 877
 878    if (other_tc == other->current_tc)
 879        return other->active_tc.CP0_TCHalt;
 880    else
 881        return other->tcs[other_tc].CP0_TCHalt;
 882}
 883
 884target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
 885{
 886    return env->active_tc.CP0_TCContext;
 887}
 888
 889target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
 890{
 891    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 892    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 893
 894    if (other_tc == other->current_tc)
 895        return other->active_tc.CP0_TCContext;
 896    else
 897        return other->tcs[other_tc].CP0_TCContext;
 898}
 899
 900target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
 901{
 902    return env->active_tc.CP0_TCSchedule;
 903}
 904
 905target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
 906{
 907    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 908    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 909
 910    if (other_tc == other->current_tc)
 911        return other->active_tc.CP0_TCSchedule;
 912    else
 913        return other->tcs[other_tc].CP0_TCSchedule;
 914}
 915
 916target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
 917{
 918    return env->active_tc.CP0_TCScheFBack;
 919}
 920
 921target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
 922{
 923    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 924    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 925
 926    if (other_tc == other->current_tc)
 927        return other->active_tc.CP0_TCScheFBack;
 928    else
 929        return other->tcs[other_tc].CP0_TCScheFBack;
 930}
 931
 932target_ulong helper_mfc0_count(CPUMIPSState *env)
 933{
 934    int32_t count;
 935    qemu_mutex_lock_iothread();
 936    count = (int32_t) cpu_mips_get_count(env);
 937    qemu_mutex_unlock_iothread();
 938    return count;
 939}
 940
 941target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
 942{
 943    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 944    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 945
 946    return other->CP0_EntryHi;
 947}
 948
 949target_ulong helper_mftc0_cause(CPUMIPSState *env)
 950{
 951    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 952    int32_t tccause;
 953    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 954
 955    if (other_tc == other->current_tc) {
 956        tccause = other->CP0_Cause;
 957    } else {
 958        tccause = other->CP0_Cause;
 959    }
 960
 961    return tccause;
 962}
 963
 964target_ulong helper_mftc0_status(CPUMIPSState *env)
 965{
 966    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 967    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 968
 969    return other->CP0_Status;
 970}
 971
 972target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
 973{
 974    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
 975}
 976
 977target_ulong helper_mfc0_maar(CPUMIPSState *env)
 978{
 979    return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
 980}
 981
 982target_ulong helper_mfhc0_maar(CPUMIPSState *env)
 983{
 984    return env->CP0_MAAR[env->CP0_MAARI] >> 32;
 985}
 986
 987target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
 988{
 989    return (int32_t)env->CP0_WatchLo[sel];
 990}
 991
 992target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
 993{
 994    return env->CP0_WatchHi[sel];
 995}
 996
 997target_ulong helper_mfc0_debug(CPUMIPSState *env)
 998{
 999    target_ulong t0 = env->CP0_Debug;
1000    if (env->hflags & MIPS_HFLAG_DM)
1001        t0 |= 1 << CP0DB_DM;
1002
1003    return t0;
1004}
1005
1006target_ulong helper_mftc0_debug(CPUMIPSState *env)
1007{
1008    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1009    int32_t tcstatus;
1010    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1011
1012    if (other_tc == other->current_tc)
1013        tcstatus = other->active_tc.CP0_Debug_tcstatus;
1014    else
1015        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
1016
1017    /* XXX: Might be wrong, check with EJTAG spec. */
1018    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1019            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1020}
1021
1022#if defined(TARGET_MIPS64)
1023target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
1024{
1025    return env->active_tc.PC;
1026}
1027
1028target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
1029{
1030    return env->active_tc.CP0_TCHalt;
1031}
1032
1033target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
1034{
1035    return env->active_tc.CP0_TCContext;
1036}
1037
1038target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
1039{
1040    return env->active_tc.CP0_TCSchedule;
1041}
1042
1043target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
1044{
1045    return env->active_tc.CP0_TCScheFBack;
1046}
1047
1048target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
1049{
1050    return env->lladdr >> env->CP0_LLAddr_shift;
1051}
1052
1053target_ulong helper_dmfc0_maar(CPUMIPSState *env)
1054{
1055    return env->CP0_MAAR[env->CP0_MAARI];
1056}
1057
1058target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
1059{
1060    return env->CP0_WatchLo[sel];
1061}
1062#endif /* TARGET_MIPS64 */
1063
1064void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
1065{
1066    uint32_t index_p = env->CP0_Index & 0x80000000;
1067    uint32_t tlb_index = arg1 & 0x7fffffff;
1068    if (tlb_index < env->tlb->nb_tlb) {
1069        if (env->insn_flags & ISA_MIPS32R6) {
1070            index_p |= arg1 & 0x80000000;
1071        }
1072        env->CP0_Index = index_p | tlb_index;
1073    }
1074}
1075
1076void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
1077{
1078    uint32_t mask = 0;
1079    uint32_t newval;
1080
1081    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1082        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1083                (1 << CP0MVPCo_EVP);
1084    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1085        mask |= (1 << CP0MVPCo_STLB);
1086    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1087
1088    // TODO: Enable/disable shared TLB, enable/disable VPEs.
1089
1090    env->mvp->CP0_MVPControl = newval;
1091}
1092
1093void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1094{
1095    uint32_t mask;
1096    uint32_t newval;
1097
1098    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1099           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1100    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1101
1102    /* Yield scheduler intercept not implemented. */
1103    /* Gating storage scheduler intercept not implemented. */
1104
1105    // TODO: Enable/disable TCs.
1106
1107    env->CP0_VPEControl = newval;
1108}
1109
1110void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1111{
1112    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1113    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1114    uint32_t mask;
1115    uint32_t newval;
1116
1117    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1118           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1119    newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
1120
1121    /* TODO: Enable/disable TCs.  */
1122
1123    other->CP0_VPEControl = newval;
1124}
1125
1126target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
1127{
1128    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1129    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1130    /* FIXME: Mask away return zero on read bits.  */
1131    return other->CP0_VPEControl;
1132}
1133
1134target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1135{
1136    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1137    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1138
1139    return other->CP0_VPEConf0;
1140}
1141
1142void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1143{
1144    uint32_t mask = 0;
1145    uint32_t newval;
1146
1147    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1148        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1149            mask |= (0xff << CP0VPEC0_XTC);
1150        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1151    }
1152    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1153
1154    // TODO: TC exclusive handling due to ERL/EXL.
1155
1156    env->CP0_VPEConf0 = newval;
1157}
1158
1159void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1160{
1161    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1162    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1163    uint32_t mask = 0;
1164    uint32_t newval;
1165
1166    mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1167    newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1168
1169    /* TODO: TC exclusive handling due to ERL/EXL.  */
1170    other->CP0_VPEConf0 = newval;
1171}
1172
1173void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1174{
1175    uint32_t mask = 0;
1176    uint32_t newval;
1177
1178    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1179        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1180                (0xff << CP0VPEC1_NCP1);
1181    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1182
1183    /* UDI not implemented. */
1184    /* CP2 not implemented. */
1185
1186    // TODO: Handle FPU (CP1) binding.
1187
1188    env->CP0_VPEConf1 = newval;
1189}
1190
1191void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1192{
1193    /* Yield qualifier inputs not implemented. */
1194    env->CP0_YQMask = 0x00000000;
1195}
1196
1197void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1198{
1199    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1200}
1201
1202#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
1203
1204void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1205{
1206    /* 1k pages not implemented */
1207    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1208    env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
1209                        | (rxi << (CP0EnLo_XI - 30));
1210}
1211
1212#if defined(TARGET_MIPS64)
1213#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
1214
1215void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
1216{
1217    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1218    env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1219}
1220#endif
1221
1222void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1223{
1224    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1225    uint32_t newval;
1226
1227    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1228
1229    env->active_tc.CP0_TCStatus = newval;
1230    sync_c0_tcstatus(env, env->current_tc, newval);
1231}
1232
1233void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1234{
1235    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1236    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1237
1238    if (other_tc == other->current_tc)
1239        other->active_tc.CP0_TCStatus = arg1;
1240    else
1241        other->tcs[other_tc].CP0_TCStatus = arg1;
1242    sync_c0_tcstatus(other, other_tc, arg1);
1243}
1244
1245void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1246{
1247    uint32_t mask = (1 << CP0TCBd_TBE);
1248    uint32_t newval;
1249
1250    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1251        mask |= (1 << CP0TCBd_CurVPE);
1252    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1253    env->active_tc.CP0_TCBind = newval;
1254}
1255
1256void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1257{
1258    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1259    uint32_t mask = (1 << CP0TCBd_TBE);
1260    uint32_t newval;
1261    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1262
1263    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1264        mask |= (1 << CP0TCBd_CurVPE);
1265    if (other_tc == other->current_tc) {
1266        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1267        other->active_tc.CP0_TCBind = newval;
1268    } else {
1269        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1270        other->tcs[other_tc].CP0_TCBind = newval;
1271    }
1272}
1273
1274void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1275{
1276    env->active_tc.PC = arg1;
1277    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1278    env->lladdr = 0ULL;
1279    /* MIPS16 not implemented. */
1280}
1281
1282void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1283{
1284    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1285    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1286
1287    if (other_tc == other->current_tc) {
1288        other->active_tc.PC = arg1;
1289        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1290        other->lladdr = 0ULL;
1291        /* MIPS16 not implemented. */
1292    } else {
1293        other->tcs[other_tc].PC = arg1;
1294        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1295        other->lladdr = 0ULL;
1296        /* MIPS16 not implemented. */
1297    }
1298}
1299
1300void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1301{
1302    MIPSCPU *cpu = mips_env_get_cpu(env);
1303
1304    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1305
1306    // TODO: Halt TC / Restart (if allocated+active) TC.
1307    if (env->active_tc.CP0_TCHalt & 1) {
1308        mips_tc_sleep(cpu, env->current_tc);
1309    } else {
1310        mips_tc_wake(cpu, env->current_tc);
1311    }
1312}
1313
1314void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1315{
1316    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1317    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1318    MIPSCPU *other_cpu = mips_env_get_cpu(other);
1319
1320    // TODO: Halt TC / Restart (if allocated+active) TC.
1321
1322    if (other_tc == other->current_tc)
1323        other->active_tc.CP0_TCHalt = arg1;
1324    else
1325        other->tcs[other_tc].CP0_TCHalt = arg1;
1326
1327    if (arg1 & 1) {
1328        mips_tc_sleep(other_cpu, other_tc);
1329    } else {
1330        mips_tc_wake(other_cpu, other_tc);
1331    }
1332}
1333
1334void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1335{
1336    env->active_tc.CP0_TCContext = arg1;
1337}
1338
1339void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1340{
1341    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1342    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1343
1344    if (other_tc == other->current_tc)
1345        other->active_tc.CP0_TCContext = arg1;
1346    else
1347        other->tcs[other_tc].CP0_TCContext = arg1;
1348}
1349
1350void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1351{
1352    env->active_tc.CP0_TCSchedule = arg1;
1353}
1354
1355void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1356{
1357    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1358    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1359
1360    if (other_tc == other->current_tc)
1361        other->active_tc.CP0_TCSchedule = arg1;
1362    else
1363        other->tcs[other_tc].CP0_TCSchedule = arg1;
1364}
1365
1366void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1367{
1368    env->active_tc.CP0_TCScheFBack = arg1;
1369}
1370
1371void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1372{
1373    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1374    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1375
1376    if (other_tc == other->current_tc)
1377        other->active_tc.CP0_TCScheFBack = arg1;
1378    else
1379        other->tcs[other_tc].CP0_TCScheFBack = arg1;
1380}
1381
1382void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1383{
1384    /* 1k pages not implemented */
1385    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1386    env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
1387                        | (rxi << (CP0EnLo_XI - 30));
1388}
1389
1390#if defined(TARGET_MIPS64)
1391void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
1392{
1393    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1394    env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1395}
1396#endif
1397
1398void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1399{
1400    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1401}
1402
1403void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask)
1404{
1405    uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1406    if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1407        (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1408         mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1409         mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1410        env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1411    }
1412}
1413
1414void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1415{
1416    update_pagemask(env, arg1, &env->CP0_PageMask);
1417}
1418
1419void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1420{
1421    /* SmartMIPS not implemented */
1422    /* 1k pages not implemented */
1423    env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
1424                         (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
1425    compute_hflags(env);
1426    restore_pamask(env);
1427}
1428
1429void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
1430{
1431    CPUState *cs = CPU(mips_env_get_cpu(env));
1432
1433    env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
1434    tlb_flush(cs);
1435}
1436
1437void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
1438{
1439    CPUState *cs = CPU(mips_env_get_cpu(env));
1440
1441    env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
1442    tlb_flush(cs);
1443}
1444
1445void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
1446{
1447    CPUState *cs = CPU(mips_env_get_cpu(env));
1448
1449    env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
1450    tlb_flush(cs);
1451}
1452
1453void helper_mtc0_pwfield(CPUMIPSState *env, target_ulong arg1)
1454{
1455#if defined(TARGET_MIPS64)
1456    uint64_t mask = 0x3F3FFFFFFFULL;
1457    uint32_t old_ptei = (env->CP0_PWField >> CP0PF_PTEI) & 0x3FULL;
1458    uint32_t new_ptei = (arg1 >> CP0PF_PTEI) & 0x3FULL;
1459
1460    if ((env->insn_flags & ISA_MIPS32R6)) {
1461        if (((arg1 >> CP0PF_BDI) & 0x3FULL) < 12) {
1462            mask &= ~(0x3FULL << CP0PF_BDI);
1463        }
1464        if (((arg1 >> CP0PF_GDI) & 0x3FULL) < 12) {
1465            mask &= ~(0x3FULL << CP0PF_GDI);
1466        }
1467        if (((arg1 >> CP0PF_UDI) & 0x3FULL) < 12) {
1468            mask &= ~(0x3FULL << CP0PF_UDI);
1469        }
1470        if (((arg1 >> CP0PF_MDI) & 0x3FULL) < 12) {
1471            mask &= ~(0x3FULL << CP0PF_MDI);
1472        }
1473        if (((arg1 >> CP0PF_PTI) & 0x3FULL) < 12) {
1474            mask &= ~(0x3FULL << CP0PF_PTI);
1475        }
1476    }
1477    env->CP0_PWField = arg1 & mask;
1478
1479    if ((new_ptei >= 32) ||
1480            ((env->insn_flags & ISA_MIPS32R6) &&
1481                    (new_ptei == 0 || new_ptei == 1))) {
1482        env->CP0_PWField = (env->CP0_PWField & ~0x3FULL) |
1483                (old_ptei << CP0PF_PTEI);
1484    }
1485#else
1486    uint32_t mask = 0x3FFFFFFF;
1487    uint32_t old_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F;
1488    uint32_t new_ptew = (arg1 >> CP0PF_PTEW) & 0x3F;
1489
1490    if ((env->insn_flags & ISA_MIPS32R6)) {
1491        if (((arg1 >> CP0PF_GDW) & 0x3F) < 12) {
1492            mask &= ~(0x3F << CP0PF_GDW);
1493        }
1494        if (((arg1 >> CP0PF_UDW) & 0x3F) < 12) {
1495            mask &= ~(0x3F << CP0PF_UDW);
1496        }
1497        if (((arg1 >> CP0PF_MDW) & 0x3F) < 12) {
1498            mask &= ~(0x3F << CP0PF_MDW);
1499        }
1500        if (((arg1 >> CP0PF_PTW) & 0x3F) < 12) {
1501            mask &= ~(0x3F << CP0PF_PTW);
1502        }
1503    }
1504    env->CP0_PWField = arg1 & mask;
1505
1506    if ((new_ptew >= 32) ||
1507            ((env->insn_flags & ISA_MIPS32R6) &&
1508                    (new_ptew == 0 || new_ptew == 1))) {
1509        env->CP0_PWField = (env->CP0_PWField & ~0x3F) |
1510                (old_ptew << CP0PF_PTEW);
1511    }
1512#endif
1513}
1514
1515void helper_mtc0_pwsize(CPUMIPSState *env, target_ulong arg1)
1516{
1517#if defined(TARGET_MIPS64)
1518    env->CP0_PWSize = arg1 & 0x3F7FFFFFFFULL;
1519#else
1520    env->CP0_PWSize = arg1 & 0x3FFFFFFF;
1521#endif
1522}
1523
1524void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1525{
1526    if (env->insn_flags & ISA_MIPS32R6) {
1527        if (arg1 < env->tlb->nb_tlb) {
1528            env->CP0_Wired = arg1;
1529        }
1530    } else {
1531        env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1532    }
1533}
1534
1535void helper_mtc0_pwctl(CPUMIPSState *env, target_ulong arg1)
1536{
1537#if defined(TARGET_MIPS64)
1538    /* PWEn = 0. Hardware page table walking is not implemented. */
1539    env->CP0_PWCtl = (env->CP0_PWCtl & 0x000000C0) | (arg1 & 0x5C00003F);
1540#else
1541    env->CP0_PWCtl = (arg1 & 0x800000FF);
1542#endif
1543}
1544
1545void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1546{
1547    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1548}
1549
1550void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1551{
1552    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1553}
1554
1555void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1556{
1557    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1558}
1559
1560void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1561{
1562    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1563}
1564
1565void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1566{
1567    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1568}
1569
1570void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1571{
1572    uint32_t mask = 0x0000000F;
1573
1574    if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
1575        (env->insn_flags & ISA_MIPS32R6)) {
1576        mask |= (1 << 4);
1577    }
1578    if (env->insn_flags & ISA_MIPS32R6) {
1579        mask |= (1 << 5);
1580    }
1581    if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1582        mask |= (1 << 29);
1583
1584        if (arg1 & (1 << 29)) {
1585            env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1586        } else {
1587            env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1588        }
1589    }
1590
1591    env->CP0_HWREna = arg1 & mask;
1592}
1593
1594void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1595{
1596    qemu_mutex_lock_iothread();
1597    cpu_mips_store_count(env, arg1);
1598    qemu_mutex_unlock_iothread();
1599}
1600
1601void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1602{
1603    target_ulong old, val, mask;
1604    mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
1605    if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1606        mask |= 1 << CP0EnHi_EHINV;
1607    }
1608
1609    /* 1k pages not implemented */
1610#if defined(TARGET_MIPS64)
1611    if (env->insn_flags & ISA_MIPS32R6) {
1612        int entryhi_r = extract64(arg1, 62, 2);
1613        int config0_at = extract32(env->CP0_Config0, 13, 2);
1614        bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1615        if ((entryhi_r == 2) ||
1616            (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1617            /* skip EntryHi.R field if new value is reserved */
1618            mask &= ~(0x3ull << 62);
1619        }
1620    }
1621    mask &= env->SEGMask;
1622#endif
1623    old = env->CP0_EntryHi;
1624    val = (arg1 & mask) | (old & ~mask);
1625    env->CP0_EntryHi = val;
1626    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1627        sync_c0_entryhi(env, env->current_tc);
1628    }
1629    /* If the ASID changes, flush qemu's TLB.  */
1630    if ((old & env->CP0_EntryHi_ASID_mask) !=
1631        (val & env->CP0_EntryHi_ASID_mask)) {
1632        tlb_flush(CPU(mips_env_get_cpu(env)));
1633    }
1634}
1635
1636void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1637{
1638    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1639    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1640
1641    other->CP0_EntryHi = arg1;
1642    sync_c0_entryhi(other, other_tc);
1643}
1644
1645void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1646{
1647    qemu_mutex_lock_iothread();
1648    cpu_mips_store_compare(env, arg1);
1649    qemu_mutex_unlock_iothread();
1650}
1651
1652void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1653{
1654    MIPSCPU *cpu = mips_env_get_cpu(env);
1655    uint32_t val, old;
1656
1657    old = env->CP0_Status;
1658    cpu_mips_store_status(env, arg1);
1659    val = env->CP0_Status;
1660
1661    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1662        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1663                old, old & env->CP0_Cause & CP0Ca_IP_mask,
1664                val, val & env->CP0_Cause & CP0Ca_IP_mask,
1665                env->CP0_Cause);
1666        switch (cpu_mmu_index(env, false)) {
1667        case 3:
1668            qemu_log(", ERL\n");
1669            break;
1670        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1671        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1672        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1673        default:
1674            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1675            break;
1676        }
1677    }
1678}
1679
1680void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1681{
1682    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1683    uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
1684    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1685
1686    other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
1687    sync_c0_status(env, other, other_tc);
1688}
1689
1690void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1691{
1692    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1693}
1694
1695void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1696{
1697    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1698    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1699}
1700
1701void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1702{
1703    qemu_mutex_lock_iothread();
1704    cpu_mips_store_cause(env, arg1);
1705    qemu_mutex_unlock_iothread();
1706}
1707
1708void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1709{
1710    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1711    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1712
1713    cpu_mips_store_cause(other, arg1);
1714}
1715
1716target_ulong helper_mftc0_epc(CPUMIPSState *env)
1717{
1718    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1719    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1720
1721    return other->CP0_EPC;
1722}
1723
1724target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1725{
1726    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1727    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1728
1729    return other->CP0_EBase;
1730}
1731
1732void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1733{
1734    target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1735    if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1736        mask |= ~0x3FFFFFFF;
1737    }
1738    env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
1739}
1740
1741void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1742{
1743    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1744    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1745    target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1746    if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1747        mask |= ~0x3FFFFFFF;
1748    }
1749    other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
1750}
1751
1752target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1753{
1754    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1755    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1756
1757    switch (idx) {
1758    case 0: return other->CP0_Config0;
1759    case 1: return other->CP0_Config1;
1760    case 2: return other->CP0_Config2;
1761    case 3: return other->CP0_Config3;
1762    /* 4 and 5 are reserved.  */
1763    case 6: return other->CP0_Config6;
1764    case 7: return other->CP0_Config7;
1765    default:
1766        break;
1767    }
1768    return 0;
1769}
1770
1771void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1772{
1773    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1774}
1775
1776void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1777{
1778    /* tertiary/secondary caches not implemented */
1779    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1780}
1781
1782void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1783{
1784    if (env->insn_flags & ASE_MICROMIPS) {
1785        env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1786                           (arg1 & (1 << CP0C3_ISA_ON_EXC));
1787    }
1788}
1789
1790void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1791{
1792    env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1793                       (arg1 & env->CP0_Config4_rw_bitmask);
1794}
1795
1796void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1797{
1798    env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1799                       (arg1 & env->CP0_Config5_rw_bitmask);
1800    compute_hflags(env);
1801}
1802
1803void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1804{
1805    target_long mask = env->CP0_LLAddr_rw_bitmask;
1806    arg1 = arg1 << env->CP0_LLAddr_shift;
1807    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1808}
1809
1810#define MTC0_MAAR_MASK(env) \
1811        ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
1812
1813void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
1814{
1815    env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
1816}
1817
1818void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
1819{
1820    env->CP0_MAAR[env->CP0_MAARI] =
1821        (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
1822        (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
1823}
1824
1825void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
1826{
1827    int index = arg1 & 0x3f;
1828    if (index == 0x3f) {
1829        /* Software may write all ones to INDEX to determine the
1830           maximum value supported. */
1831        env->CP0_MAARI = MIPS_MAAR_MAX - 1;
1832    } else if (index < MIPS_MAAR_MAX) {
1833        env->CP0_MAARI = index;
1834    }
1835    /* Other than the all ones, if the
1836       value written is not supported, then INDEX is unchanged
1837       from its previous value. */
1838}
1839
1840void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1841{
1842    /* Watch exceptions for instructions, data loads, data stores
1843       not implemented. */
1844    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1845}
1846
1847void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1848{
1849    int mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
1850    env->CP0_WatchHi[sel] = arg1 & mask;
1851    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1852}
1853
1854void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1855{
1856    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1857    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1858}
1859
1860void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1861{
1862    env->CP0_Framemask = arg1; /* XXX */
1863}
1864
1865void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1866{
1867    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1868    if (arg1 & (1 << CP0DB_DM))
1869        env->hflags |= MIPS_HFLAG_DM;
1870    else
1871        env->hflags &= ~MIPS_HFLAG_DM;
1872}
1873
1874void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1875{
1876    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1877    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1878    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1879
1880    /* XXX: Might be wrong, check with EJTAG spec. */
1881    if (other_tc == other->current_tc)
1882        other->active_tc.CP0_Debug_tcstatus = val;
1883    else
1884        other->tcs[other_tc].CP0_Debug_tcstatus = val;
1885    other->CP0_Debug = (other->CP0_Debug &
1886                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1887                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1888}
1889
1890void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1891{
1892    env->CP0_Performance0 = arg1 & 0x000007ff;
1893}
1894
1895void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
1896{
1897    int32_t wst = arg1 & (1 << CP0EC_WST);
1898    int32_t spr = arg1 & (1 << CP0EC_SPR);
1899    int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
1900
1901    env->CP0_ErrCtl = wst | spr | itc;
1902
1903    if (itc && !wst && !spr) {
1904        env->hflags |= MIPS_HFLAG_ITC_CACHE;
1905    } else {
1906        env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
1907    }
1908}
1909
1910void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1911{
1912    if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
1913        /* If CACHE instruction is configured for ITC tags then make all
1914           CP0.TagLo bits writable. The actual write to ITC Configuration
1915           Tag will take care of the read-only bits. */
1916        env->CP0_TagLo = arg1;
1917    } else {
1918        env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1919    }
1920}
1921
1922void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1923{
1924    env->CP0_DataLo = arg1; /* XXX */
1925}
1926
1927void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1928{
1929    env->CP0_TagHi = arg1; /* XXX */
1930}
1931
1932void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1933{
1934    env->CP0_DataHi = arg1; /* XXX */
1935}
1936
1937/* MIPS MT functions */
1938target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1939{
1940    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1941    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1942
1943    if (other_tc == other->current_tc)
1944        return other->active_tc.gpr[sel];
1945    else
1946        return other->tcs[other_tc].gpr[sel];
1947}
1948
1949target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1950{
1951    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1952    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1953
1954    if (other_tc == other->current_tc)
1955        return other->active_tc.LO[sel];
1956    else
1957        return other->tcs[other_tc].LO[sel];
1958}
1959
1960target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1961{
1962    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1963    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1964
1965    if (other_tc == other->current_tc)
1966        return other->active_tc.HI[sel];
1967    else
1968        return other->tcs[other_tc].HI[sel];
1969}
1970
1971target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1972{
1973    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1974    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1975
1976    if (other_tc == other->current_tc)
1977        return other->active_tc.ACX[sel];
1978    else
1979        return other->tcs[other_tc].ACX[sel];
1980}
1981
1982target_ulong helper_mftdsp(CPUMIPSState *env)
1983{
1984    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1985    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1986
1987    if (other_tc == other->current_tc)
1988        return other->active_tc.DSPControl;
1989    else
1990        return other->tcs[other_tc].DSPControl;
1991}
1992
1993void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1994{
1995    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1996    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1997
1998    if (other_tc == other->current_tc)
1999        other->active_tc.gpr[sel] = arg1;
2000    else
2001        other->tcs[other_tc].gpr[sel] = arg1;
2002}
2003
2004void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
2005{
2006    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
2007    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
2008
2009    if (other_tc == other->current_tc)
2010        other->active_tc.LO[sel] = arg1;
2011    else
2012        other->tcs[other_tc].LO[sel] = arg1;
2013}
2014
2015void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
2016{
2017    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
2018    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
2019
2020    if (other_tc == other->current_tc)
2021        other->active_tc.HI[sel] = arg1;
2022    else
2023        other->tcs[other_tc].HI[sel] = arg1;
2024}
2025
2026void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
2027{
2028    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
2029    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
2030
2031    if (other_tc == other->current_tc)
2032        other->active_tc.ACX[sel] = arg1;
2033    else
2034        other->tcs[other_tc].ACX[sel] = arg1;
2035}
2036
2037void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
2038{
2039    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
2040    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
2041
2042    if (other_tc == other->current_tc)
2043        other->active_tc.DSPControl = arg1;
2044    else
2045        other->tcs[other_tc].DSPControl = arg1;
2046}
2047
2048/* MIPS MT functions */
2049target_ulong helper_dmt(void)
2050{
2051    // TODO
2052     return 0;
2053}
2054
2055target_ulong helper_emt(void)
2056{
2057    // TODO
2058    return 0;
2059}
2060
2061target_ulong helper_dvpe(CPUMIPSState *env)
2062{
2063    CPUState *other_cs = first_cpu;
2064    target_ulong prev = env->mvp->CP0_MVPControl;
2065
2066    CPU_FOREACH(other_cs) {
2067        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2068        /* Turn off all VPEs except the one executing the dvpe.  */
2069        if (&other_cpu->env != env) {
2070            other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
2071            mips_vpe_sleep(other_cpu);
2072        }
2073    }
2074    return prev;
2075}
2076
2077target_ulong helper_evpe(CPUMIPSState *env)
2078{
2079    CPUState *other_cs = first_cpu;
2080    target_ulong prev = env->mvp->CP0_MVPControl;
2081
2082    CPU_FOREACH(other_cs) {
2083        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2084
2085        if (&other_cpu->env != env
2086            /* If the VPE is WFI, don't disturb its sleep.  */
2087            && !mips_vpe_is_wfi(other_cpu)) {
2088            /* Enable the VPE.  */
2089            other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
2090            mips_vpe_wake(other_cpu); /* And wake it up.  */
2091        }
2092    }
2093    return prev;
2094}
2095#endif /* !CONFIG_USER_ONLY */
2096
2097void helper_fork(target_ulong arg1, target_ulong arg2)
2098{
2099    // arg1 = rt, arg2 = rs
2100    // TODO: store to TC register
2101}
2102
2103target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
2104{
2105    target_long arg1 = arg;
2106
2107    if (arg1 < 0) {
2108        /* No scheduling policy implemented. */
2109        if (arg1 != -2) {
2110            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
2111                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
2112                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2113                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
2114                do_raise_exception(env, EXCP_THREAD, GETPC());
2115            }
2116        }
2117    } else if (arg1 == 0) {
2118        if (0 /* TODO: TC underflow */) {
2119            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2120            do_raise_exception(env, EXCP_THREAD, GETPC());
2121        } else {
2122            // TODO: Deallocate TC
2123        }
2124    } else if (arg1 > 0) {
2125        /* Yield qualifier inputs not implemented. */
2126        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2127        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
2128        do_raise_exception(env, EXCP_THREAD, GETPC());
2129    }
2130    return env->CP0_YQMask;
2131}
2132
2133/* R6 Multi-threading */
2134#ifndef CONFIG_USER_ONLY
2135target_ulong helper_dvp(CPUMIPSState *env)
2136{
2137    CPUState *other_cs = first_cpu;
2138    target_ulong prev = env->CP0_VPControl;
2139
2140    if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
2141        CPU_FOREACH(other_cs) {
2142            MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2143            /* Turn off all VPs except the one executing the dvp. */
2144            if (&other_cpu->env != env) {
2145                mips_vpe_sleep(other_cpu);
2146            }
2147        }
2148        env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
2149    }
2150    return prev;
2151}
2152
2153target_ulong helper_evp(CPUMIPSState *env)
2154{
2155    CPUState *other_cs = first_cpu;
2156    target_ulong prev = env->CP0_VPControl;
2157
2158    if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
2159        CPU_FOREACH(other_cs) {
2160            MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2161            if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
2162                /* If the VP is WFI, don't disturb its sleep.
2163                 * Otherwise, wake it up. */
2164                mips_vpe_wake(other_cpu);
2165            }
2166        }
2167        env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
2168    }
2169    return prev;
2170}
2171#endif /* !CONFIG_USER_ONLY */
2172
2173#ifndef CONFIG_USER_ONLY
2174/* TLB management */
2175static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
2176{
2177    /* Discard entries from env->tlb[first] onwards.  */
2178    while (env->tlb->tlb_in_use > first) {
2179        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
2180    }
2181}
2182
2183static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
2184{
2185#if defined(TARGET_MIPS64)
2186    return extract64(entrylo, 6, 54);
2187#else
2188    return extract64(entrylo, 6, 24) | /* PFN */
2189           (extract64(entrylo, 32, 32) << 24); /* PFNX */
2190#endif
2191}
2192
2193static void r4k_fill_tlb(CPUMIPSState *env, int idx)
2194{
2195    r4k_tlb_t *tlb;
2196    uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
2197
2198    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
2199    tlb = &env->tlb->mmu.r4k.tlb[idx];
2200    if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
2201        tlb->EHINV = 1;
2202        return;
2203    }
2204    tlb->EHINV = 0;
2205    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2206#if defined(TARGET_MIPS64)
2207    tlb->VPN &= env->SEGMask;
2208#endif
2209    tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2210    tlb->PageMask = env->CP0_PageMask;
2211    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2212    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
2213    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2214    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2215    tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
2216    tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
2217    tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
2218    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2219    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2220    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2221    tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
2222    tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
2223    tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
2224}
2225
2226void r4k_helper_tlbinv(CPUMIPSState *env)
2227{
2228    int idx;
2229    r4k_tlb_t *tlb;
2230    uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2231
2232    for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2233        tlb = &env->tlb->mmu.r4k.tlb[idx];
2234        if (!tlb->G && tlb->ASID == ASID) {
2235            tlb->EHINV = 1;
2236        }
2237    }
2238    cpu_mips_tlb_flush(env);
2239}
2240
2241void r4k_helper_tlbinvf(CPUMIPSState *env)
2242{
2243    int idx;
2244
2245    for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2246        env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
2247    }
2248    cpu_mips_tlb_flush(env);
2249}
2250
2251void r4k_helper_tlbwi(CPUMIPSState *env)
2252{
2253    r4k_tlb_t *tlb;
2254    int idx;
2255    target_ulong VPN;
2256    uint16_t ASID;
2257    bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
2258
2259    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2260    tlb = &env->tlb->mmu.r4k.tlb[idx];
2261    VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2262#if defined(TARGET_MIPS64)
2263    VPN &= env->SEGMask;
2264#endif
2265    ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2266    EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
2267    G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2268    V0 = (env->CP0_EntryLo0 & 2) != 0;
2269    D0 = (env->CP0_EntryLo0 & 4) != 0;
2270    XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
2271    RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
2272    V1 = (env->CP0_EntryLo1 & 2) != 0;
2273    D1 = (env->CP0_EntryLo1 & 4) != 0;
2274    XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
2275    RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
2276
2277    /* Discard cached TLB entries, unless tlbwi is just upgrading access
2278       permissions on the current entry. */
2279    if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
2280        (!tlb->EHINV && EHINV) ||
2281        (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
2282        (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
2283        (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
2284        (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
2285        r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2286    }
2287
2288    r4k_invalidate_tlb(env, idx, 0);
2289    r4k_fill_tlb(env, idx);
2290}
2291
2292void r4k_helper_tlbwr(CPUMIPSState *env)
2293{
2294    int r = cpu_mips_get_random(env);
2295
2296    r4k_invalidate_tlb(env, r, 1);
2297    r4k_fill_tlb(env, r);
2298}
2299
2300void r4k_helper_tlbp(CPUMIPSState *env)
2301{
2302    r4k_tlb_t *tlb;
2303    target_ulong mask;
2304    target_ulong tag;
2305    target_ulong VPN;
2306    uint16_t ASID;
2307    int i;
2308
2309    ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2310    for (i = 0; i < env->tlb->nb_tlb; i++) {
2311        tlb = &env->tlb->mmu.r4k.tlb[i];
2312        /* 1k pages are not supported. */
2313        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2314        tag = env->CP0_EntryHi & ~mask;
2315        VPN = tlb->VPN & ~mask;
2316#if defined(TARGET_MIPS64)
2317        tag &= env->SEGMask;
2318#endif
2319        /* Check ASID, virtual page number & size */
2320        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
2321            /* TLB match */
2322            env->CP0_Index = i;
2323            break;
2324        }
2325    }
2326    if (i == env->tlb->nb_tlb) {
2327        /* No match.  Discard any shadow entries, if any of them match.  */
2328        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
2329            tlb = &env->tlb->mmu.r4k.tlb[i];
2330            /* 1k pages are not supported. */
2331            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2332            tag = env->CP0_EntryHi & ~mask;
2333            VPN = tlb->VPN & ~mask;
2334#if defined(TARGET_MIPS64)
2335            tag &= env->SEGMask;
2336#endif
2337            /* Check ASID, virtual page number & size */
2338            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2339                r4k_mips_tlb_flush_extra (env, i);
2340                break;
2341            }
2342        }
2343
2344        env->CP0_Index |= 0x80000000;
2345    }
2346}
2347
2348static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
2349{
2350#if defined(TARGET_MIPS64)
2351    return tlb_pfn << 6;
2352#else
2353    return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
2354           (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
2355#endif
2356}
2357
2358void r4k_helper_tlbr(CPUMIPSState *env)
2359{
2360    r4k_tlb_t *tlb;
2361    uint16_t ASID;
2362    int idx;
2363
2364    ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2365    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2366    tlb = &env->tlb->mmu.r4k.tlb[idx];
2367
2368    /* If this will change the current ASID, flush qemu's TLB.  */
2369    if (ASID != tlb->ASID)
2370        cpu_mips_tlb_flush(env);
2371
2372    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2373
2374    if (tlb->EHINV) {
2375        env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2376        env->CP0_PageMask = 0;
2377        env->CP0_EntryLo0 = 0;
2378        env->CP0_EntryLo1 = 0;
2379    } else {
2380        env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2381        env->CP0_PageMask = tlb->PageMask;
2382        env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2383                        ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
2384                        ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2385                        get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
2386        env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2387                        ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
2388                        ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2389                        get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
2390    }
2391}
2392
2393void helper_tlbwi(CPUMIPSState *env)
2394{
2395    env->tlb->helper_tlbwi(env);
2396}
2397
2398void helper_tlbwr(CPUMIPSState *env)
2399{
2400    env->tlb->helper_tlbwr(env);
2401}
2402
2403void helper_tlbp(CPUMIPSState *env)
2404{
2405    env->tlb->helper_tlbp(env);
2406}
2407
2408void helper_tlbr(CPUMIPSState *env)
2409{
2410    env->tlb->helper_tlbr(env);
2411}
2412
2413void helper_tlbinv(CPUMIPSState *env)
2414{
2415    env->tlb->helper_tlbinv(env);
2416}
2417
2418void helper_tlbinvf(CPUMIPSState *env)
2419{
2420    env->tlb->helper_tlbinvf(env);
2421}
2422
2423/* Specials */
2424target_ulong helper_di(CPUMIPSState *env)
2425{
2426    target_ulong t0 = env->CP0_Status;
2427
2428    env->CP0_Status = t0 & ~(1 << CP0St_IE);
2429    return t0;
2430}
2431
2432target_ulong helper_ei(CPUMIPSState *env)
2433{
2434    target_ulong t0 = env->CP0_Status;
2435
2436    env->CP0_Status = t0 | (1 << CP0St_IE);
2437    return t0;
2438}
2439
2440static void debug_pre_eret(CPUMIPSState *env)
2441{
2442    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2443        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2444                env->active_tc.PC, env->CP0_EPC);
2445        if (env->CP0_Status & (1 << CP0St_ERL))
2446            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2447        if (env->hflags & MIPS_HFLAG_DM)
2448            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2449        qemu_log("\n");
2450    }
2451}
2452
2453static void debug_post_eret(CPUMIPSState *env)
2454{
2455    MIPSCPU *cpu = mips_env_get_cpu(env);
2456
2457    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2458        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2459                env->active_tc.PC, env->CP0_EPC);
2460        if (env->CP0_Status & (1 << CP0St_ERL))
2461            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2462        if (env->hflags & MIPS_HFLAG_DM)
2463            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2464        switch (cpu_mmu_index(env, false)) {
2465        case 3:
2466            qemu_log(", ERL\n");
2467            break;
2468        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2469        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2470        case MIPS_HFLAG_KM: qemu_log("\n"); break;
2471        default:
2472            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2473            break;
2474        }
2475    }
2476}
2477
2478static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2479{
2480    env->active_tc.PC = error_pc & ~(target_ulong)1;
2481    if (error_pc & 1) {
2482        env->hflags |= MIPS_HFLAG_M16;
2483    } else {
2484        env->hflags &= ~(MIPS_HFLAG_M16);
2485    }
2486}
2487
2488static inline void exception_return(CPUMIPSState *env)
2489{
2490    debug_pre_eret(env);
2491    if (env->CP0_Status & (1 << CP0St_ERL)) {
2492        set_pc(env, env->CP0_ErrorEPC);
2493        env->CP0_Status &= ~(1 << CP0St_ERL);
2494    } else {
2495        set_pc(env, env->CP0_EPC);
2496        env->CP0_Status &= ~(1 << CP0St_EXL);
2497    }
2498    compute_hflags(env);
2499    debug_post_eret(env);
2500}
2501
2502void helper_eret(CPUMIPSState *env)
2503{
2504    exception_return(env);
2505    env->lladdr = 1;
2506}
2507
2508void helper_eretnc(CPUMIPSState *env)
2509{
2510    exception_return(env);
2511}
2512
2513void helper_deret(CPUMIPSState *env)
2514{
2515    debug_pre_eret(env);
2516
2517    env->hflags &= ~MIPS_HFLAG_DM;
2518    compute_hflags(env);
2519
2520    set_pc(env, env->CP0_DEPC);
2521
2522    debug_post_eret(env);
2523}
2524#endif /* !CONFIG_USER_ONLY */
2525
2526static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
2527{
2528    if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
2529        return;
2530    }
2531    do_raise_exception(env, EXCP_RI, pc);
2532}
2533
2534target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2535{
2536    check_hwrena(env, 0, GETPC());
2537    return env->CP0_EBase & 0x3ff;
2538}
2539
2540target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2541{
2542    check_hwrena(env, 1, GETPC());
2543    return env->SYNCI_Step;
2544}
2545
2546target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2547{
2548    int32_t count;
2549    check_hwrena(env, 2, GETPC());
2550#ifdef CONFIG_USER_ONLY
2551    count = env->CP0_Count;
2552#else
2553    qemu_mutex_lock_iothread();
2554    count = (int32_t)cpu_mips_get_count(env);
2555    qemu_mutex_unlock_iothread();
2556#endif
2557    return count;
2558}
2559
2560target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2561{
2562    check_hwrena(env, 3, GETPC());
2563    return env->CCRes;
2564}
2565
2566target_ulong helper_rdhwr_performance(CPUMIPSState *env)
2567{
2568    check_hwrena(env, 4, GETPC());
2569    return env->CP0_Performance0;
2570}
2571
2572target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
2573{
2574    check_hwrena(env, 5, GETPC());
2575    return (env->CP0_Config5 >> CP0C5_XNP) & 1;
2576}
2577
2578void helper_pmon(CPUMIPSState *env, int function)
2579{
2580    function /= 2;
2581    switch (function) {
2582    case 2: /* TODO: char inbyte(int waitflag); */
2583        if (env->active_tc.gpr[4] == 0)
2584            env->active_tc.gpr[2] = -1;
2585        /* Fall through */
2586    case 11: /* TODO: char inbyte (void); */
2587        env->active_tc.gpr[2] = -1;
2588        break;
2589    case 3:
2590    case 12:
2591        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2592        break;
2593    case 17:
2594        break;
2595    case 158:
2596        {
2597            unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
2598            printf("%s", fmt);
2599        }
2600        break;
2601    }
2602}
2603
2604void helper_wait(CPUMIPSState *env)
2605{
2606    CPUState *cs = CPU(mips_env_get_cpu(env));
2607
2608    cs->halted = 1;
2609    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2610    /* Last instruction in the block, PC was updated before
2611       - no need to recover PC and icount */
2612    raise_exception(env, EXCP_HLT);
2613}
2614
2615#if !defined(CONFIG_USER_ONLY)
2616
2617void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
2618                                  MMUAccessType access_type,
2619                                  int mmu_idx, uintptr_t retaddr)
2620{
2621    MIPSCPU *cpu = MIPS_CPU(cs);
2622    CPUMIPSState *env = &cpu->env;
2623    int error_code = 0;
2624    int excp;
2625
2626    if (!(env->hflags & MIPS_HFLAG_DM)) {
2627        env->CP0_BadVAddr = addr;
2628    }
2629
2630    if (access_type == MMU_DATA_STORE) {
2631        excp = EXCP_AdES;
2632    } else {
2633        excp = EXCP_AdEL;
2634        if (access_type == MMU_INST_FETCH) {
2635            error_code |= EXCP_INST_NOTAVAIL;
2636        }
2637    }
2638
2639    do_raise_exception_err(env, excp, error_code, retaddr);
2640}
2641
2642void tlb_fill(CPUState *cs, target_ulong addr, int size,
2643              MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
2644{
2645    int ret;
2646
2647    ret = mips_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
2648    if (ret) {
2649        MIPSCPU *cpu = MIPS_CPU(cs);
2650        CPUMIPSState *env = &cpu->env;
2651
2652        do_raise_exception_err(env, cs->exception_index,
2653                               env->error_code, retaddr);
2654    }
2655}
2656
2657void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2658                                bool is_write, bool is_exec, int unused,
2659                                unsigned size)
2660{
2661    MIPSCPU *cpu = MIPS_CPU(cs);
2662    CPUMIPSState *env = &cpu->env;
2663
2664    /*
2665     * Raising an exception with KVM enabled will crash because it won't be from
2666     * the main execution loop so the longjmp won't have a matching setjmp.
2667     * Until we can trigger a bus error exception through KVM lets just ignore
2668     * the access.
2669     */
2670    if (kvm_enabled()) {
2671        return;
2672    }
2673
2674    if (is_exec) {
2675        raise_exception(env, EXCP_IBE);
2676    } else {
2677        raise_exception(env, EXCP_DBE);
2678    }
2679}
2680#endif /* !CONFIG_USER_ONLY */
2681
2682/* Complex FPU operations which may need stack space. */
2683
2684#define FLOAT_TWO32 make_float32(1 << 30)
2685#define FLOAT_TWO64 make_float64(1ULL << 62)
2686
2687#define FP_TO_INT32_OVERFLOW 0x7fffffff
2688#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
2689
2690/* convert MIPS rounding mode in FCR31 to IEEE library */
2691unsigned int ieee_rm[] = {
2692    float_round_nearest_even,
2693    float_round_to_zero,
2694    float_round_up,
2695    float_round_down
2696};
2697
2698target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2699{
2700    target_ulong arg1 = 0;
2701
2702    switch (reg) {
2703    case 0:
2704        arg1 = (int32_t)env->active_fpu.fcr0;
2705        break;
2706    case 1:
2707        /* UFR Support - Read Status FR */
2708        if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2709            if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2710                arg1 = (int32_t)
2711                       ((env->CP0_Status & (1  << CP0St_FR)) >> CP0St_FR);
2712            } else {
2713                do_raise_exception(env, EXCP_RI, GETPC());
2714            }
2715        }
2716        break;
2717    case 5:
2718        /* FRE Support - read Config5.FRE bit */
2719        if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2720            if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2721                arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2722            } else {
2723                helper_raise_exception(env, EXCP_RI);
2724            }
2725        }
2726        break;
2727    case 25:
2728        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2729        break;
2730    case 26:
2731        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2732        break;
2733    case 28:
2734        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2735        break;
2736    default:
2737        arg1 = (int32_t)env->active_fpu.fcr31;
2738        break;
2739    }
2740
2741    return arg1;
2742}
2743
2744void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
2745{
2746    switch (fs) {
2747    case 1:
2748        /* UFR Alias - Reset Status FR */
2749        if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2750            return;
2751        }
2752        if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2753            env->CP0_Status &= ~(1 << CP0St_FR);
2754            compute_hflags(env);
2755        } else {
2756            do_raise_exception(env, EXCP_RI, GETPC());
2757        }
2758        break;
2759    case 4:
2760        /* UNFR Alias - Set Status FR */
2761        if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2762            return;
2763        }
2764        if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2765            env->CP0_Status |= (1 << CP0St_FR);
2766            compute_hflags(env);
2767        } else {
2768            do_raise_exception(env, EXCP_RI, GETPC());
2769        }
2770        break;
2771    case 5:
2772        /* FRE Support - clear Config5.FRE bit */
2773        if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2774            return;
2775        }
2776        if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2777            env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2778            compute_hflags(env);
2779        } else {
2780            helper_raise_exception(env, EXCP_RI);
2781        }
2782        break;
2783    case 6:
2784        /* FRE Support - set Config5.FRE bit */
2785        if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2786            return;
2787        }
2788        if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2789            env->CP0_Config5 |= (1 << CP0C5_FRE);
2790            compute_hflags(env);
2791        } else {
2792            helper_raise_exception(env, EXCP_RI);
2793        }
2794        break;
2795    case 25:
2796        if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
2797            return;
2798        }
2799        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2800                     ((arg1 & 0x1) << 23);
2801        break;
2802    case 26:
2803        if (arg1 & 0x007c0000)
2804            return;
2805        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2806        break;
2807    case 28:
2808        if (arg1 & 0x007c0000)
2809            return;
2810        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2811                     ((arg1 & 0x4) << 22);
2812        break;
2813    case 31:
2814        env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
2815               (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
2816        break;
2817    default:
2818        if (env->insn_flags & ISA_MIPS32R6) {
2819            do_raise_exception(env, EXCP_RI, GETPC());
2820        }
2821        return;
2822    }
2823    restore_fp_status(env);
2824    set_float_exception_flags(0, &env->active_fpu.fp_status);
2825    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2826        do_raise_exception(env, EXCP_FPE, GETPC());
2827}
2828
2829int ieee_ex_to_mips(int xcpt)
2830{
2831    int ret = 0;
2832    if (xcpt) {
2833        if (xcpt & float_flag_invalid) {
2834            ret |= FP_INVALID;
2835        }
2836        if (xcpt & float_flag_overflow) {
2837            ret |= FP_OVERFLOW;
2838        }
2839        if (xcpt & float_flag_underflow) {
2840            ret |= FP_UNDERFLOW;
2841        }
2842        if (xcpt & float_flag_divbyzero) {
2843            ret |= FP_DIV0;
2844        }
2845        if (xcpt & float_flag_inexact) {
2846            ret |= FP_INEXACT;
2847        }
2848    }
2849    return ret;
2850}
2851
2852static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2853{
2854    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2855
2856    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2857
2858    if (tmp) {
2859        set_float_exception_flags(0, &env->active_fpu.fp_status);
2860
2861        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2862            do_raise_exception(env, EXCP_FPE, pc);
2863        } else {
2864            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2865        }
2866    }
2867}
2868
2869/* Float support.
2870   Single precition routines have a "s" suffix, double precision a
2871   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2872   paired single lower "pl", paired single upper "pu".  */
2873
2874/* unary operations, modifying fp status  */
2875uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2876{
2877    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2878    update_fcr31(env, GETPC());
2879    return fdt0;
2880}
2881
2882uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2883{
2884    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2885    update_fcr31(env, GETPC());
2886    return fst0;
2887}
2888
2889uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2890{
2891    uint64_t fdt2;
2892
2893    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2894    update_fcr31(env, GETPC());
2895    return fdt2;
2896}
2897
2898uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2899{
2900    uint64_t fdt2;
2901
2902    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2903    update_fcr31(env, GETPC());
2904    return fdt2;
2905}
2906
2907uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2908{
2909    uint64_t fdt2;
2910
2911    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2912    update_fcr31(env, GETPC());
2913    return fdt2;
2914}
2915
2916uint64_t helper_float_cvt_l_d(CPUMIPSState *env, uint64_t fdt0)
2917{
2918    uint64_t dt2;
2919
2920    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2921    if (get_float_exception_flags(&env->active_fpu.fp_status)
2922        & (float_flag_invalid | float_flag_overflow)) {
2923        dt2 = FP_TO_INT64_OVERFLOW;
2924    }
2925    update_fcr31(env, GETPC());
2926    return dt2;
2927}
2928
2929uint64_t helper_float_cvt_l_s(CPUMIPSState *env, uint32_t fst0)
2930{
2931    uint64_t dt2;
2932
2933    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2934    if (get_float_exception_flags(&env->active_fpu.fp_status)
2935        & (float_flag_invalid | float_flag_overflow)) {
2936        dt2 = FP_TO_INT64_OVERFLOW;
2937    }
2938    update_fcr31(env, GETPC());
2939    return dt2;
2940}
2941
2942uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2943{
2944    uint32_t fst2;
2945    uint32_t fsth2;
2946
2947    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2948    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2949    update_fcr31(env, GETPC());
2950    return ((uint64_t)fsth2 << 32) | fst2;
2951}
2952
2953uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2954{
2955    uint32_t wt2;
2956    uint32_t wth2;
2957    int excp, excph;
2958
2959    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2960    excp = get_float_exception_flags(&env->active_fpu.fp_status);
2961    if (excp & (float_flag_overflow | float_flag_invalid)) {
2962        wt2 = FP_TO_INT32_OVERFLOW;
2963    }
2964
2965    set_float_exception_flags(0, &env->active_fpu.fp_status);
2966    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2967    excph = get_float_exception_flags(&env->active_fpu.fp_status);
2968    if (excph & (float_flag_overflow | float_flag_invalid)) {
2969        wth2 = FP_TO_INT32_OVERFLOW;
2970    }
2971
2972    set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
2973    update_fcr31(env, GETPC());
2974
2975    return ((uint64_t)wth2 << 32) | wt2;
2976}
2977
2978uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2979{
2980    uint32_t fst2;
2981
2982    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2983    update_fcr31(env, GETPC());
2984    return fst2;
2985}
2986
2987uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2988{
2989    uint32_t fst2;
2990
2991    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2992    update_fcr31(env, GETPC());
2993    return fst2;
2994}
2995
2996uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2997{
2998    uint32_t fst2;
2999
3000    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
3001    update_fcr31(env, GETPC());
3002    return fst2;
3003}
3004
3005uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
3006{
3007    uint32_t wt2;
3008
3009    wt2 = wt0;
3010    update_fcr31(env, GETPC());
3011    return wt2;
3012}
3013
3014uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
3015{
3016    uint32_t wt2;
3017
3018    wt2 = wth0;
3019    update_fcr31(env, GETPC());
3020    return wt2;
3021}
3022
3023uint32_t helper_float_cvt_w_s(CPUMIPSState *env, uint32_t fst0)
3024{
3025    uint32_t wt2;
3026
3027    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3028    if (get_float_exception_flags(&env->active_fpu.fp_status)
3029        & (float_flag_invalid | float_flag_overflow)) {
3030        wt2 = FP_TO_INT32_OVERFLOW;
3031    }
3032    update_fcr31(env, GETPC());
3033    return wt2;
3034}
3035
3036uint32_t helper_float_cvt_w_d(CPUMIPSState *env, uint64_t fdt0)
3037{
3038    uint32_t wt2;
3039
3040    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3041    if (get_float_exception_flags(&env->active_fpu.fp_status)
3042        & (float_flag_invalid | float_flag_overflow)) {
3043        wt2 = FP_TO_INT32_OVERFLOW;
3044    }
3045    update_fcr31(env, GETPC());
3046    return wt2;
3047}
3048
3049uint64_t helper_float_round_l_d(CPUMIPSState *env, uint64_t fdt0)
3050{
3051    uint64_t dt2;
3052
3053    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
3054    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3055    restore_rounding_mode(env);
3056    if (get_float_exception_flags(&env->active_fpu.fp_status)
3057        & (float_flag_invalid | float_flag_overflow)) {
3058        dt2 = FP_TO_INT64_OVERFLOW;
3059    }
3060    update_fcr31(env, GETPC());
3061    return dt2;
3062}
3063
3064uint64_t helper_float_round_l_s(CPUMIPSState *env, uint32_t fst0)
3065{
3066    uint64_t dt2;
3067
3068    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
3069    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3070    restore_rounding_mode(env);
3071    if (get_float_exception_flags(&env->active_fpu.fp_status)
3072        & (float_flag_invalid | float_flag_overflow)) {
3073        dt2 = FP_TO_INT64_OVERFLOW;
3074    }
3075    update_fcr31(env, GETPC());
3076    return dt2;
3077}
3078
3079uint32_t helper_float_round_w_d(CPUMIPSState *env, uint64_t fdt0)
3080{
3081    uint32_t wt2;
3082
3083    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
3084    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3085    restore_rounding_mode(env);
3086    if (get_float_exception_flags(&env->active_fpu.fp_status)
3087        & (float_flag_invalid | float_flag_overflow)) {
3088        wt2 = FP_TO_INT32_OVERFLOW;
3089    }
3090    update_fcr31(env, GETPC());
3091    return wt2;
3092}
3093
3094uint32_t helper_float_round_w_s(CPUMIPSState *env, uint32_t fst0)
3095{
3096    uint32_t wt2;
3097
3098    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
3099    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3100    restore_rounding_mode(env);
3101    if (get_float_exception_flags(&env->active_fpu.fp_status)
3102        & (float_flag_invalid | float_flag_overflow)) {
3103        wt2 = FP_TO_INT32_OVERFLOW;
3104    }
3105    update_fcr31(env, GETPC());
3106    return wt2;
3107}
3108
3109uint64_t helper_float_trunc_l_d(CPUMIPSState *env, uint64_t fdt0)
3110{
3111    uint64_t dt2;
3112
3113    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3114    if (get_float_exception_flags(&env->active_fpu.fp_status)
3115        & (float_flag_invalid | float_flag_overflow)) {
3116        dt2 = FP_TO_INT64_OVERFLOW;
3117    }
3118    update_fcr31(env, GETPC());
3119    return dt2;
3120}
3121
3122uint64_t helper_float_trunc_l_s(CPUMIPSState *env, uint32_t fst0)
3123{
3124    uint64_t dt2;
3125
3126    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3127    if (get_float_exception_flags(&env->active_fpu.fp_status)
3128        & (float_flag_invalid | float_flag_overflow)) {
3129        dt2 = FP_TO_INT64_OVERFLOW;
3130    }
3131    update_fcr31(env, GETPC());
3132    return dt2;
3133}
3134
3135uint32_t helper_float_trunc_w_d(CPUMIPSState *env, uint64_t fdt0)
3136{
3137    uint32_t wt2;
3138
3139    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3140    if (get_float_exception_flags(&env->active_fpu.fp_status)
3141        & (float_flag_invalid | float_flag_overflow)) {
3142        wt2 = FP_TO_INT32_OVERFLOW;
3143    }
3144    update_fcr31(env, GETPC());
3145    return wt2;
3146}
3147
3148uint32_t helper_float_trunc_w_s(CPUMIPSState *env, uint32_t fst0)
3149{
3150    uint32_t wt2;
3151
3152    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3153    if (get_float_exception_flags(&env->active_fpu.fp_status)
3154        & (float_flag_invalid | float_flag_overflow)) {
3155        wt2 = FP_TO_INT32_OVERFLOW;
3156    }
3157    update_fcr31(env, GETPC());
3158    return wt2;
3159}
3160
3161uint64_t helper_float_ceil_l_d(CPUMIPSState *env, uint64_t fdt0)
3162{
3163    uint64_t dt2;
3164
3165    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3166    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3167    restore_rounding_mode(env);
3168    if (get_float_exception_flags(&env->active_fpu.fp_status)
3169        & (float_flag_invalid | float_flag_overflow)) {
3170        dt2 = FP_TO_INT64_OVERFLOW;
3171    }
3172    update_fcr31(env, GETPC());
3173    return dt2;
3174}
3175
3176uint64_t helper_float_ceil_l_s(CPUMIPSState *env, uint32_t fst0)
3177{
3178    uint64_t dt2;
3179
3180    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3181    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3182    restore_rounding_mode(env);
3183    if (get_float_exception_flags(&env->active_fpu.fp_status)
3184        & (float_flag_invalid | float_flag_overflow)) {
3185        dt2 = FP_TO_INT64_OVERFLOW;
3186    }
3187    update_fcr31(env, GETPC());
3188    return dt2;
3189}
3190
3191uint32_t helper_float_ceil_w_d(CPUMIPSState *env, uint64_t fdt0)
3192{
3193    uint32_t wt2;
3194
3195    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3196    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3197    restore_rounding_mode(env);
3198    if (get_float_exception_flags(&env->active_fpu.fp_status)
3199        & (float_flag_invalid | float_flag_overflow)) {
3200        wt2 = FP_TO_INT32_OVERFLOW;
3201    }
3202    update_fcr31(env, GETPC());
3203    return wt2;
3204}
3205
3206uint32_t helper_float_ceil_w_s(CPUMIPSState *env, uint32_t fst0)
3207{
3208    uint32_t wt2;
3209
3210    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3211    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3212    restore_rounding_mode(env);
3213    if (get_float_exception_flags(&env->active_fpu.fp_status)
3214        & (float_flag_invalid | float_flag_overflow)) {
3215        wt2 = FP_TO_INT32_OVERFLOW;
3216    }
3217    update_fcr31(env, GETPC());
3218    return wt2;
3219}
3220
3221uint64_t helper_float_floor_l_d(CPUMIPSState *env, uint64_t fdt0)
3222{
3223    uint64_t dt2;
3224
3225    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3226    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3227    restore_rounding_mode(env);
3228    if (get_float_exception_flags(&env->active_fpu.fp_status)
3229        & (float_flag_invalid | float_flag_overflow)) {
3230        dt2 = FP_TO_INT64_OVERFLOW;
3231    }
3232    update_fcr31(env, GETPC());
3233    return dt2;
3234}
3235
3236uint64_t helper_float_floor_l_s(CPUMIPSState *env, uint32_t fst0)
3237{
3238    uint64_t dt2;
3239
3240    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3241    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3242    restore_rounding_mode(env);
3243    if (get_float_exception_flags(&env->active_fpu.fp_status)
3244        & (float_flag_invalid | float_flag_overflow)) {
3245        dt2 = FP_TO_INT64_OVERFLOW;
3246    }
3247    update_fcr31(env, GETPC());
3248    return dt2;
3249}
3250
3251uint32_t helper_float_floor_w_d(CPUMIPSState *env, uint64_t fdt0)
3252{
3253    uint32_t wt2;
3254
3255    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3256    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3257    restore_rounding_mode(env);
3258    if (get_float_exception_flags(&env->active_fpu.fp_status)
3259        & (float_flag_invalid | float_flag_overflow)) {
3260        wt2 = FP_TO_INT32_OVERFLOW;
3261    }
3262    update_fcr31(env, GETPC());
3263    return wt2;
3264}
3265
3266uint32_t helper_float_floor_w_s(CPUMIPSState *env, uint32_t fst0)
3267{
3268    uint32_t wt2;
3269
3270    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3271    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3272    restore_rounding_mode(env);
3273    if (get_float_exception_flags(&env->active_fpu.fp_status)
3274        & (float_flag_invalid | float_flag_overflow)) {
3275        wt2 = FP_TO_INT32_OVERFLOW;
3276    }
3277    update_fcr31(env, GETPC());
3278    return wt2;
3279}
3280
3281uint64_t helper_float_cvt_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3282{
3283    uint64_t dt2;
3284
3285    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3286    if (get_float_exception_flags(&env->active_fpu.fp_status)
3287            & float_flag_invalid) {
3288        if (float64_is_any_nan(fdt0)) {
3289            dt2 = 0;
3290        }
3291    }
3292    update_fcr31(env, GETPC());
3293    return dt2;
3294}
3295
3296uint64_t helper_float_cvt_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3297{
3298    uint64_t dt2;
3299
3300    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3301    if (get_float_exception_flags(&env->active_fpu.fp_status)
3302            & float_flag_invalid) {
3303        if (float32_is_any_nan(fst0)) {
3304            dt2 = 0;
3305        }
3306    }
3307    update_fcr31(env, GETPC());
3308    return dt2;
3309}
3310
3311uint32_t helper_float_cvt_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3312{
3313    uint32_t wt2;
3314
3315    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3316    if (get_float_exception_flags(&env->active_fpu.fp_status)
3317            & float_flag_invalid) {
3318        if (float64_is_any_nan(fdt0)) {
3319            wt2 = 0;
3320        }
3321    }
3322    update_fcr31(env, GETPC());
3323    return wt2;
3324}
3325
3326uint32_t helper_float_cvt_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3327{
3328    uint32_t wt2;
3329
3330    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3331    if (get_float_exception_flags(&env->active_fpu.fp_status)
3332            & float_flag_invalid) {
3333        if (float32_is_any_nan(fst0)) {
3334            wt2 = 0;
3335        }
3336    }
3337    update_fcr31(env, GETPC());
3338    return wt2;
3339}
3340
3341uint64_t helper_float_round_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3342{
3343    uint64_t dt2;
3344
3345    set_float_rounding_mode(float_round_nearest_even,
3346            &env->active_fpu.fp_status);
3347    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3348    restore_rounding_mode(env);
3349    if (get_float_exception_flags(&env->active_fpu.fp_status)
3350            & float_flag_invalid) {
3351        if (float64_is_any_nan(fdt0)) {
3352            dt2 = 0;
3353        }
3354    }
3355    update_fcr31(env, GETPC());
3356    return dt2;
3357}
3358
3359uint64_t helper_float_round_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3360{
3361    uint64_t dt2;
3362
3363    set_float_rounding_mode(float_round_nearest_even,
3364            &env->active_fpu.fp_status);
3365    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3366    restore_rounding_mode(env);
3367    if (get_float_exception_flags(&env->active_fpu.fp_status)
3368            & float_flag_invalid) {
3369        if (float32_is_any_nan(fst0)) {
3370            dt2 = 0;
3371        }
3372    }
3373    update_fcr31(env, GETPC());
3374    return dt2;
3375}
3376
3377uint32_t helper_float_round_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3378{
3379    uint32_t wt2;
3380
3381    set_float_rounding_mode(float_round_nearest_even,
3382            &env->active_fpu.fp_status);
3383    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3384    restore_rounding_mode(env);
3385    if (get_float_exception_flags(&env->active_fpu.fp_status)
3386            & float_flag_invalid) {
3387        if (float64_is_any_nan(fdt0)) {
3388            wt2 = 0;
3389        }
3390    }
3391    update_fcr31(env, GETPC());
3392    return wt2;
3393}
3394
3395uint32_t helper_float_round_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3396{
3397    uint32_t wt2;
3398
3399    set_float_rounding_mode(float_round_nearest_even,
3400            &env->active_fpu.fp_status);
3401    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3402    restore_rounding_mode(env);
3403    if (get_float_exception_flags(&env->active_fpu.fp_status)
3404            & float_flag_invalid) {
3405        if (float32_is_any_nan(fst0)) {
3406            wt2 = 0;
3407        }
3408    }
3409    update_fcr31(env, GETPC());
3410    return wt2;
3411}
3412
3413uint64_t helper_float_trunc_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3414{
3415    uint64_t dt2;
3416
3417    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3418    if (get_float_exception_flags(&env->active_fpu.fp_status)
3419            & float_flag_invalid) {
3420        if (float64_is_any_nan(fdt0)) {
3421            dt2 = 0;
3422        }
3423    }
3424    update_fcr31(env, GETPC());
3425    return dt2;
3426}
3427
3428uint64_t helper_float_trunc_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3429{
3430    uint64_t dt2;
3431
3432    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3433    if (get_float_exception_flags(&env->active_fpu.fp_status)
3434            & float_flag_invalid) {
3435        if (float32_is_any_nan(fst0)) {
3436            dt2 = 0;
3437        }
3438    }
3439    update_fcr31(env, GETPC());
3440    return dt2;
3441}
3442
3443uint32_t helper_float_trunc_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3444{
3445    uint32_t wt2;
3446
3447    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3448    if (get_float_exception_flags(&env->active_fpu.fp_status)
3449            & float_flag_invalid) {
3450        if (float64_is_any_nan(fdt0)) {
3451            wt2 = 0;
3452        }
3453    }
3454    update_fcr31(env, GETPC());
3455    return wt2;
3456}
3457
3458uint32_t helper_float_trunc_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3459{
3460    uint32_t wt2;
3461
3462    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3463    if (get_float_exception_flags(&env->active_fpu.fp_status)
3464            & float_flag_invalid) {
3465        if (float32_is_any_nan(fst0)) {
3466            wt2 = 0;
3467        }
3468    }
3469    update_fcr31(env, GETPC());
3470    return wt2;
3471}
3472
3473uint64_t helper_float_ceil_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3474{
3475    uint64_t dt2;
3476
3477    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3478    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3479    restore_rounding_mode(env);
3480    if (get_float_exception_flags(&env->active_fpu.fp_status)
3481            & float_flag_invalid) {
3482        if (float64_is_any_nan(fdt0)) {
3483            dt2 = 0;
3484        }
3485    }
3486    update_fcr31(env, GETPC());
3487    return dt2;
3488}
3489
3490uint64_t helper_float_ceil_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3491{
3492    uint64_t dt2;
3493
3494    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3495    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3496    restore_rounding_mode(env);
3497    if (get_float_exception_flags(&env->active_fpu.fp_status)
3498            & float_flag_invalid) {
3499        if (float32_is_any_nan(fst0)) {
3500            dt2 = 0;
3501        }
3502    }
3503    update_fcr31(env, GETPC());
3504    return dt2;
3505}
3506
3507uint32_t helper_float_ceil_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3508{
3509    uint32_t wt2;
3510
3511    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3512    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3513    restore_rounding_mode(env);
3514    if (get_float_exception_flags(&env->active_fpu.fp_status)
3515            & float_flag_invalid) {
3516        if (float64_is_any_nan(fdt0)) {
3517            wt2 = 0;
3518        }
3519    }
3520    update_fcr31(env, GETPC());
3521    return wt2;
3522}
3523
3524uint32_t helper_float_ceil_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3525{
3526    uint32_t wt2;
3527
3528    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3529    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3530    restore_rounding_mode(env);
3531    if (get_float_exception_flags(&env->active_fpu.fp_status)
3532            & float_flag_invalid) {
3533        if (float32_is_any_nan(fst0)) {
3534            wt2 = 0;
3535        }
3536    }
3537    update_fcr31(env, GETPC());
3538    return wt2;
3539}
3540
3541uint64_t helper_float_floor_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3542{
3543    uint64_t dt2;
3544
3545    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3546    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3547    restore_rounding_mode(env);
3548    if (get_float_exception_flags(&env->active_fpu.fp_status)
3549            & float_flag_invalid) {
3550        if (float64_is_any_nan(fdt0)) {
3551            dt2 = 0;
3552        }
3553    }
3554    update_fcr31(env, GETPC());
3555    return dt2;
3556}
3557
3558uint64_t helper_float_floor_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3559{
3560    uint64_t dt2;
3561
3562    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3563    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3564    restore_rounding_mode(env);
3565    if (get_float_exception_flags(&env->active_fpu.fp_status)
3566            & float_flag_invalid) {
3567        if (float32_is_any_nan(fst0)) {
3568            dt2 = 0;
3569        }
3570    }
3571    update_fcr31(env, GETPC());
3572    return dt2;
3573}
3574
3575uint32_t helper_float_floor_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3576{
3577    uint32_t wt2;
3578
3579    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3580    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3581    restore_rounding_mode(env);
3582    if (get_float_exception_flags(&env->active_fpu.fp_status)
3583            & float_flag_invalid) {
3584        if (float64_is_any_nan(fdt0)) {
3585            wt2 = 0;
3586        }
3587    }
3588    update_fcr31(env, GETPC());
3589    return wt2;
3590}
3591
3592uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3593{
3594    uint32_t wt2;
3595
3596    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3597    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3598    restore_rounding_mode(env);
3599    if (get_float_exception_flags(&env->active_fpu.fp_status)
3600            & float_flag_invalid) {
3601        if (float32_is_any_nan(fst0)) {
3602            wt2 = 0;
3603        }
3604    }
3605    update_fcr31(env, GETPC());
3606    return wt2;
3607}
3608
3609/* unary operations, not modifying fp status  */
3610#define FLOAT_UNOP(name)                                       \
3611uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
3612{                                                              \
3613    return float64_ ## name(fdt0);                             \
3614}                                                              \
3615uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
3616{                                                              \
3617    return float32_ ## name(fst0);                             \
3618}                                                              \
3619uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
3620{                                                              \
3621    uint32_t wt0;                                              \
3622    uint32_t wth0;                                             \
3623                                                               \
3624    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
3625    wth0 = float32_ ## name(fdt0 >> 32);                       \
3626    return ((uint64_t)wth0 << 32) | wt0;                       \
3627}
3628FLOAT_UNOP(abs)
3629FLOAT_UNOP(chs)
3630#undef FLOAT_UNOP
3631
3632/* MIPS specific unary operations */
3633uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
3634{
3635    uint64_t fdt2;
3636
3637    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3638    update_fcr31(env, GETPC());
3639    return fdt2;
3640}
3641
3642uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
3643{
3644    uint32_t fst2;
3645
3646    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3647    update_fcr31(env, GETPC());
3648    return fst2;
3649}
3650
3651uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
3652{
3653    uint64_t fdt2;
3654
3655    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3656    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3657    update_fcr31(env, GETPC());
3658    return fdt2;
3659}
3660
3661uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
3662{
3663    uint32_t fst2;
3664
3665    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3666    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3667    update_fcr31(env, GETPC());
3668    return fst2;
3669}
3670
3671uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
3672{
3673    uint64_t fdt2;
3674
3675    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3676    update_fcr31(env, GETPC());
3677    return fdt2;
3678}
3679
3680uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
3681{
3682    uint32_t fst2;
3683
3684    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3685    update_fcr31(env, GETPC());
3686    return fst2;
3687}
3688
3689uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
3690{
3691    uint32_t fst2;
3692    uint32_t fsth2;
3693
3694    fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3695    fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
3696    update_fcr31(env, GETPC());
3697    return ((uint64_t)fsth2 << 32) | fst2;
3698}
3699
3700uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
3701{
3702    uint64_t fdt2;
3703
3704    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3705    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3706    update_fcr31(env, GETPC());
3707    return fdt2;
3708}
3709
3710uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
3711{
3712    uint32_t fst2;
3713
3714    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3715    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3716    update_fcr31(env, GETPC());
3717    return fst2;
3718}
3719
3720uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
3721{
3722    uint32_t fst2;
3723    uint32_t fsth2;
3724
3725    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3726    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3727    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3728    fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3729    update_fcr31(env, GETPC());
3730    return ((uint64_t)fsth2 << 32) | fst2;
3731}
3732
3733#define FLOAT_RINT(name, bits)                                              \
3734uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,                \
3735                                          uint ## bits ## _t fs)            \
3736{                                                                           \
3737    uint ## bits ## _t fdret;                                               \
3738                                                                            \
3739    fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3740    update_fcr31(env, GETPC());                                             \
3741    return fdret;                                                           \
3742}
3743
3744FLOAT_RINT(rint_s, 32)
3745FLOAT_RINT(rint_d, 64)
3746#undef FLOAT_RINT
3747
3748#define FLOAT_CLASS_SIGNALING_NAN      0x001
3749#define FLOAT_CLASS_QUIET_NAN          0x002
3750#define FLOAT_CLASS_NEGATIVE_INFINITY  0x004
3751#define FLOAT_CLASS_NEGATIVE_NORMAL    0x008
3752#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3753#define FLOAT_CLASS_NEGATIVE_ZERO      0x020
3754#define FLOAT_CLASS_POSITIVE_INFINITY  0x040
3755#define FLOAT_CLASS_POSITIVE_NORMAL    0x080
3756#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3757#define FLOAT_CLASS_POSITIVE_ZERO      0x200
3758
3759#define FLOAT_CLASS(name, bits)                                      \
3760uint ## bits ## _t float_ ## name (uint ## bits ## _t arg,           \
3761                                   float_status *status)             \
3762{                                                                    \
3763    if (float ## bits ## _is_signaling_nan(arg, status)) {           \
3764        return FLOAT_CLASS_SIGNALING_NAN;                            \
3765    } else if (float ## bits ## _is_quiet_nan(arg, status)) {        \
3766        return FLOAT_CLASS_QUIET_NAN;                                \
3767    } else if (float ## bits ## _is_neg(arg)) {                      \
3768        if (float ## bits ## _is_infinity(arg)) {                    \
3769            return FLOAT_CLASS_NEGATIVE_INFINITY;                    \
3770        } else if (float ## bits ## _is_zero(arg)) {                 \
3771            return FLOAT_CLASS_NEGATIVE_ZERO;                        \
3772        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3773            return FLOAT_CLASS_NEGATIVE_SUBNORMAL;                   \
3774        } else {                                                     \
3775            return FLOAT_CLASS_NEGATIVE_NORMAL;                      \
3776        }                                                            \
3777    } else {                                                         \
3778        if (float ## bits ## _is_infinity(arg)) {                    \
3779            return FLOAT_CLASS_POSITIVE_INFINITY;                    \
3780        } else if (float ## bits ## _is_zero(arg)) {                 \
3781            return FLOAT_CLASS_POSITIVE_ZERO;                        \
3782        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3783            return FLOAT_CLASS_POSITIVE_SUBNORMAL;                   \
3784        } else {                                                     \
3785            return FLOAT_CLASS_POSITIVE_NORMAL;                      \
3786        }                                                            \
3787    }                                                                \
3788}                                                                    \
3789                                                                     \
3790uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,         \
3791                                          uint ## bits ## _t arg)    \
3792{                                                                    \
3793    return float_ ## name(arg, &env->active_fpu.fp_status);          \
3794}
3795
3796FLOAT_CLASS(class_s, 32)
3797FLOAT_CLASS(class_d, 64)
3798#undef FLOAT_CLASS
3799
3800/* binary operations */
3801#define FLOAT_BINOP(name)                                          \
3802uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
3803                                     uint64_t fdt0, uint64_t fdt1) \
3804{                                                                  \
3805    uint64_t dt2;                                                  \
3806                                                                   \
3807    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3808    update_fcr31(env, GETPC());                                    \
3809    return dt2;                                                    \
3810}                                                                  \
3811                                                                   \
3812uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
3813                                     uint32_t fst0, uint32_t fst1) \
3814{                                                                  \
3815    uint32_t wt2;                                                  \
3816                                                                   \
3817    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3818    update_fcr31(env, GETPC());                                    \
3819    return wt2;                                                    \
3820}                                                                  \
3821                                                                   \
3822uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
3823                                      uint64_t fdt0,               \
3824                                      uint64_t fdt1)               \
3825{                                                                  \
3826    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
3827    uint32_t fsth0 = fdt0 >> 32;                                   \
3828    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
3829    uint32_t fsth1 = fdt1 >> 32;                                   \
3830    uint32_t wt2;                                                  \
3831    uint32_t wth2;                                                 \
3832                                                                   \
3833    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3834    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3835    update_fcr31(env, GETPC());                                    \
3836    return ((uint64_t)wth2 << 32) | wt2;                           \
3837}
3838
3839FLOAT_BINOP(add)
3840FLOAT_BINOP(sub)
3841FLOAT_BINOP(mul)
3842FLOAT_BINOP(div)
3843#undef FLOAT_BINOP
3844
3845/* MIPS specific binary operations */
3846uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3847{
3848    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3849    fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3850    update_fcr31(env, GETPC());
3851    return fdt2;
3852}
3853
3854uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3855{
3856    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3857    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3858    update_fcr31(env, GETPC());
3859    return fst2;
3860}
3861
3862uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3863{
3864    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3865    uint32_t fsth0 = fdt0 >> 32;
3866    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3867    uint32_t fsth2 = fdt2 >> 32;
3868
3869    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3870    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3871    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3872    fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
3873    update_fcr31(env, GETPC());
3874    return ((uint64_t)fsth2 << 32) | fst2;
3875}
3876
3877uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3878{
3879    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3880    fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3881    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3882    update_fcr31(env, GETPC());
3883    return fdt2;
3884}
3885
3886uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3887{
3888    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3889    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3890    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3891    update_fcr31(env, GETPC());
3892    return fst2;
3893}
3894
3895uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3896{
3897    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3898    uint32_t fsth0 = fdt0 >> 32;
3899    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3900    uint32_t fsth2 = fdt2 >> 32;
3901
3902    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3903    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3904    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3905    fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3906    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3907    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
3908    update_fcr31(env, GETPC());
3909    return ((uint64_t)fsth2 << 32) | fst2;
3910}
3911
3912uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3913{
3914    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3915    uint32_t fsth0 = fdt0 >> 32;
3916    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3917    uint32_t fsth1 = fdt1 >> 32;
3918    uint32_t fst2;
3919    uint32_t fsth2;
3920
3921    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3922    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3923    update_fcr31(env, GETPC());
3924    return ((uint64_t)fsth2 << 32) | fst2;
3925}
3926
3927uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3928{
3929    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3930    uint32_t fsth0 = fdt0 >> 32;
3931    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3932    uint32_t fsth1 = fdt1 >> 32;
3933    uint32_t fst2;
3934    uint32_t fsth2;
3935
3936    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3937    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3938    update_fcr31(env, GETPC());
3939    return ((uint64_t)fsth2 << 32) | fst2;
3940}
3941
3942#define FLOAT_MINMAX(name, bits, minmaxfunc)                            \
3943uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
3944                                          uint ## bits ## _t fs,        \
3945                                          uint ## bits ## _t ft)        \
3946{                                                                       \
3947    uint ## bits ## _t fdret;                                           \
3948                                                                        \
3949    fdret = float ## bits ## _ ## minmaxfunc(fs, ft,                    \
3950                                           &env->active_fpu.fp_status); \
3951    update_fcr31(env, GETPC());                                         \
3952    return fdret;                                                       \
3953}
3954
3955FLOAT_MINMAX(max_s, 32, maxnum)
3956FLOAT_MINMAX(max_d, 64, maxnum)
3957FLOAT_MINMAX(maxa_s, 32, maxnummag)
3958FLOAT_MINMAX(maxa_d, 64, maxnummag)
3959
3960FLOAT_MINMAX(min_s, 32, minnum)
3961FLOAT_MINMAX(min_d, 64, minnum)
3962FLOAT_MINMAX(mina_s, 32, minnummag)
3963FLOAT_MINMAX(mina_d, 64, minnummag)
3964#undef FLOAT_MINMAX
3965
3966/* ternary operations */
3967#define UNFUSED_FMA(prefix, a, b, c, flags)                          \
3968{                                                                    \
3969    a = prefix##_mul(a, b, &env->active_fpu.fp_status);              \
3970    if ((flags) & float_muladd_negate_c) {                           \
3971        a = prefix##_sub(a, c, &env->active_fpu.fp_status);          \
3972    } else {                                                         \
3973        a = prefix##_add(a, c, &env->active_fpu.fp_status);          \
3974    }                                                                \
3975    if ((flags) & float_muladd_negate_result) {                      \
3976        a = prefix##_chs(a);                                         \
3977    }                                                                \
3978}
3979
3980/* FMA based operations */
3981#define FLOAT_FMA(name, type)                                        \
3982uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
3983                                     uint64_t fdt0, uint64_t fdt1,   \
3984                                     uint64_t fdt2)                  \
3985{                                                                    \
3986    UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
3987    update_fcr31(env, GETPC());                                      \
3988    return fdt0;                                                     \
3989}                                                                    \
3990                                                                     \
3991uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
3992                                     uint32_t fst0, uint32_t fst1,   \
3993                                     uint32_t fst2)                  \
3994{                                                                    \
3995    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3996    update_fcr31(env, GETPC());                                      \
3997    return fst0;                                                     \
3998}                                                                    \
3999                                                                     \
4000uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
4001                                      uint64_t fdt0, uint64_t fdt1,  \
4002                                      uint64_t fdt2)                 \
4003{                                                                    \
4004    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
4005    uint32_t fsth0 = fdt0 >> 32;                                     \
4006    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
4007    uint32_t fsth1 = fdt1 >> 32;                                     \
4008    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
4009    uint32_t fsth2 = fdt2 >> 32;                                     \
4010                                                                     \
4011    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
4012    UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
4013    update_fcr31(env, GETPC());                                      \
4014    return ((uint64_t)fsth0 << 32) | fst0;                           \
4015}
4016FLOAT_FMA(madd, 0)
4017FLOAT_FMA(msub, float_muladd_negate_c)
4018FLOAT_FMA(nmadd, float_muladd_negate_result)
4019FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
4020#undef FLOAT_FMA
4021
4022#define FLOAT_FMADDSUB(name, bits, muladd_arg)                          \
4023uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
4024                                          uint ## bits ## _t fs,        \
4025                                          uint ## bits ## _t ft,        \
4026                                          uint ## bits ## _t fd)        \
4027{                                                                       \
4028    uint ## bits ## _t fdret;                                           \
4029                                                                        \
4030    fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg,            \
4031                                     &env->active_fpu.fp_status);       \
4032    update_fcr31(env, GETPC());                                         \
4033    return fdret;                                                       \
4034}
4035
4036FLOAT_FMADDSUB(maddf_s, 32, 0)
4037FLOAT_FMADDSUB(maddf_d, 64, 0)
4038FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
4039FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
4040#undef FLOAT_FMADDSUB
4041
4042/* compare operations */
4043#define FOP_COND_D(op, cond)                                   \
4044void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
4045                         uint64_t fdt1, int cc)                \
4046{                                                              \
4047    int c;                                                     \
4048    c = cond;                                                  \
4049    update_fcr31(env, GETPC());                                \
4050    if (c)                                                     \
4051        SET_FP_COND(cc, env->active_fpu);                      \
4052    else                                                       \
4053        CLEAR_FP_COND(cc, env->active_fpu);                    \
4054}                                                              \
4055void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
4056                            uint64_t fdt1, int cc)             \
4057{                                                              \
4058    int c;                                                     \
4059    fdt0 = float64_abs(fdt0);                                  \
4060    fdt1 = float64_abs(fdt1);                                  \
4061    c = cond;                                                  \
4062    update_fcr31(env, GETPC());                                \
4063    if (c)                                                     \
4064        SET_FP_COND(cc, env->active_fpu);                      \
4065    else                                                       \
4066        CLEAR_FP_COND(cc, env->active_fpu);                    \
4067}
4068
4069/* NOTE: the comma operator will make "cond" to eval to false,
4070 * but float64_unordered_quiet() is still called. */
4071FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4072FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
4073FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4074FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4075FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4076FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4077FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4078FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
4079/* NOTE: the comma operator will make "cond" to eval to false,
4080 * but float64_unordered() is still called. */
4081FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4082FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
4083FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
4084FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
4085FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
4086FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
4087FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
4088FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
4089
4090#define FOP_COND_S(op, cond)                                   \
4091void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
4092                         uint32_t fst1, int cc)                \
4093{                                                              \
4094    int c;                                                     \
4095    c = cond;                                                  \
4096    update_fcr31(env, GETPC());                                \
4097    if (c)                                                     \
4098        SET_FP_COND(cc, env->active_fpu);                      \
4099    else                                                       \
4100        CLEAR_FP_COND(cc, env->active_fpu);                    \
4101}                                                              \
4102void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
4103                            uint32_t fst1, int cc)             \
4104{                                                              \
4105    int c;                                                     \
4106    fst0 = float32_abs(fst0);                                  \
4107    fst1 = float32_abs(fst1);                                  \
4108    c = cond;                                                  \
4109    update_fcr31(env, GETPC());                                \
4110    if (c)                                                     \
4111        SET_FP_COND(cc, env->active_fpu);                      \
4112    else                                                       \
4113        CLEAR_FP_COND(cc, env->active_fpu);                    \
4114}
4115
4116/* NOTE: the comma operator will make "cond" to eval to false,
4117 * but float32_unordered_quiet() is still called. */
4118FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4119FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
4120FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
4121FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
4122FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
4123FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
4124FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
4125FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
4126/* NOTE: the comma operator will make "cond" to eval to false,
4127 * but float32_unordered() is still called. */
4128FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4129FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
4130FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
4131FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
4132FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
4133FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
4134FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
4135FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
4136
4137#define FOP_COND_PS(op, condl, condh)                           \
4138void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
4139                          uint64_t fdt1, int cc)                \
4140{                                                               \
4141    uint32_t fst0, fsth0, fst1, fsth1;                          \
4142    int ch, cl;                                                 \
4143    fst0 = fdt0 & 0XFFFFFFFF;                                   \
4144    fsth0 = fdt0 >> 32;                                         \
4145    fst1 = fdt1 & 0XFFFFFFFF;                                   \
4146    fsth1 = fdt1 >> 32;                                         \
4147    cl = condl;                                                 \
4148    ch = condh;                                                 \
4149    update_fcr31(env, GETPC());                                 \
4150    if (cl)                                                     \
4151        SET_FP_COND(cc, env->active_fpu);                       \
4152    else                                                        \
4153        CLEAR_FP_COND(cc, env->active_fpu);                     \
4154    if (ch)                                                     \
4155        SET_FP_COND(cc + 1, env->active_fpu);                   \
4156    else                                                        \
4157        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
4158}                                                               \
4159void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
4160                             uint64_t fdt1, int cc)             \
4161{                                                               \
4162    uint32_t fst0, fsth0, fst1, fsth1;                          \
4163    int ch, cl;                                                 \
4164    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
4165    fsth0 = float32_abs(fdt0 >> 32);                            \
4166    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
4167    fsth1 = float32_abs(fdt1 >> 32);                            \
4168    cl = condl;                                                 \
4169    ch = condh;                                                 \
4170    update_fcr31(env, GETPC());                                 \
4171    if (cl)                                                     \
4172        SET_FP_COND(cc, env->active_fpu);                       \
4173    else                                                        \
4174        CLEAR_FP_COND(cc, env->active_fpu);                     \
4175    if (ch)                                                     \
4176        SET_FP_COND(cc + 1, env->active_fpu);                   \
4177    else                                                        \
4178        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
4179}
4180
4181/* NOTE: the comma operator will make "cond" to eval to false,
4182 * but float32_unordered_quiet() is still called. */
4183FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
4184                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4185FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
4186                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
4187FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4188                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4189FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4190                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4191FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4192                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4193FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4194                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4195FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4196                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4197FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4198                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4199/* NOTE: the comma operator will make "cond" to eval to false,
4200 * but float32_unordered() is still called. */
4201FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
4202                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4203FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
4204                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
4205FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4206                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4207FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4208                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4209FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4210                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4211FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4212                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4213FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
4214                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4215FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
4216                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4217
4218/* R6 compare operations */
4219#define FOP_CONDN_D(op, cond)                                       \
4220uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0,  \
4221                         uint64_t fdt1)                             \
4222{                                                                   \
4223    uint64_t c;                                                     \
4224    c = cond;                                                       \
4225    update_fcr31(env, GETPC());                                     \
4226    if (c) {                                                        \
4227        return -1;                                                  \
4228    } else {                                                        \
4229        return 0;                                                   \
4230    }                                                               \
4231}
4232
4233/* NOTE: the comma operator will make "cond" to eval to false,
4234 * but float64_unordered_quiet() is still called. */
4235FOP_CONDN_D(af,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4236FOP_CONDN_D(un,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
4237FOP_CONDN_D(eq,  (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4238FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4239                  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4240FOP_CONDN_D(lt,  (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4241FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4242                  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4243FOP_CONDN_D(le,  (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4244FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4245                  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4246/* NOTE: the comma operator will make "cond" to eval to false,
4247 * but float64_unordered() is still called. */
4248FOP_CONDN_D(saf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4249FOP_CONDN_D(sun,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
4250FOP_CONDN_D(seq,  (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4251FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4252                   || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4253FOP_CONDN_D(slt,  (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4254FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4255                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4256FOP_CONDN_D(sle,  (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4257FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4258                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4259FOP_CONDN_D(or,   (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4260                   || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4261FOP_CONDN_D(une,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4262                   || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4263                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4264FOP_CONDN_D(ne,   (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4265                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4266FOP_CONDN_D(sor,  (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
4267                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4268FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4269                   || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4270                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4271FOP_CONDN_D(sne,  (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4272                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4273
4274#define FOP_CONDN_S(op, cond)                                       \
4275uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0,  \
4276                         uint32_t fst1)                             \
4277{                                                                   \
4278    uint64_t c;                                                     \
4279    c = cond;                                                       \
4280    update_fcr31(env, GETPC());                                     \
4281    if (c) {                                                        \
4282        return -1;                                                  \
4283    } else {                                                        \
4284        return 0;                                                   \
4285    }                                                               \
4286}
4287
4288/* NOTE: the comma operator will make "cond" to eval to false,
4289 * but float32_unordered_quiet() is still called. */
4290FOP_CONDN_S(af,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4291FOP_CONDN_S(un,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
4292FOP_CONDN_S(eq,   (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4293FOP_CONDN_S(ueq,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4294                   || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4295FOP_CONDN_S(lt,   (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4296FOP_CONDN_S(ult,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4297                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4298FOP_CONDN_S(le,   (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4299FOP_CONDN_S(ule,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4300                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4301/* NOTE: the comma operator will make "cond" to eval to false,
4302 * but float32_unordered() is still called. */
4303FOP_CONDN_S(saf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4304FOP_CONDN_S(sun,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
4305FOP_CONDN_S(seq,  (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4306FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4307                   || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4308FOP_CONDN_S(slt,  (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4309FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4310                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4311FOP_CONDN_S(sle,  (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4312FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4313                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4314FOP_CONDN_S(or,   (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
4315                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4316FOP_CONDN_S(une,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4317                   || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4318                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4319FOP_CONDN_S(ne,   (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4320                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4321FOP_CONDN_S(sor,  (float32_le(fst1, fst0, &env->active_fpu.fp_status)
4322                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4323FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4324                   || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4325                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4326FOP_CONDN_S(sne,  (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4327                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4328
4329/* MSA */
4330/* Data format min and max values */
4331#define DF_BITS(df) (1 << ((df) + 3))
4332
4333/* Element-by-element access macros */
4334#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
4335
4336#if !defined(CONFIG_USER_ONLY)
4337#define MEMOP_IDX(DF)                                           \
4338        TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN,  \
4339                                        cpu_mmu_index(env, false));
4340#else
4341#define MEMOP_IDX(DF)
4342#endif
4343
4344#define MSA_LD_DF(DF, TYPE, LD_INSN, ...)                               \
4345void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4346                            target_ulong addr)                          \
4347{                                                                       \
4348    wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4349    wr_t wx;                                                            \
4350    int i;                                                              \
4351    MEMOP_IDX(DF)                                                       \
4352    for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4353        wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__);     \
4354    }                                                                   \
4355    memcpy(pwd, &wx, sizeof(wr_t));                                     \
4356}
4357
4358#if !defined(CONFIG_USER_ONLY)
4359MSA_LD_DF(DF_BYTE,   b, helper_ret_ldub_mmu, oi, GETPC())
4360MSA_LD_DF(DF_HALF,   h, helper_ret_lduw_mmu, oi, GETPC())
4361MSA_LD_DF(DF_WORD,   w, helper_ret_ldul_mmu, oi, GETPC())
4362MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu,  oi, GETPC())
4363#else
4364MSA_LD_DF(DF_BYTE,   b, cpu_ldub_data)
4365MSA_LD_DF(DF_HALF,   h, cpu_lduw_data)
4366MSA_LD_DF(DF_WORD,   w, cpu_ldl_data)
4367MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
4368#endif
4369
4370#define MSA_PAGESPAN(x) \
4371        ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
4372
4373static inline void ensure_writable_pages(CPUMIPSState *env,
4374                                         target_ulong addr,
4375                                         int mmu_idx,
4376                                         uintptr_t retaddr)
4377{
4378#if !defined(CONFIG_USER_ONLY)
4379    target_ulong page_addr;
4380    if (unlikely(MSA_PAGESPAN(addr))) {
4381        /* first page */
4382        probe_write(env, addr, 0, mmu_idx, retaddr);
4383        /* second page */
4384        page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
4385        probe_write(env, page_addr, 0, mmu_idx, retaddr);
4386    }
4387#endif
4388}
4389
4390#define MSA_ST_DF(DF, TYPE, ST_INSN, ...)                               \
4391void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4392                            target_ulong addr)                          \
4393{                                                                       \
4394    wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4395    int mmu_idx = cpu_mmu_index(env, false);                            \
4396    int i;                                                              \
4397    MEMOP_IDX(DF)                                                       \
4398    ensure_writable_pages(env, addr, mmu_idx, GETPC());                 \
4399    for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4400        ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__);    \
4401    }                                                                   \
4402}
4403
4404#if !defined(CONFIG_USER_ONLY)
4405MSA_ST_DF(DF_BYTE,   b, helper_ret_stb_mmu, oi, GETPC())
4406MSA_ST_DF(DF_HALF,   h, helper_ret_stw_mmu, oi, GETPC())
4407MSA_ST_DF(DF_WORD,   w, helper_ret_stl_mmu, oi, GETPC())
4408MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC())
4409#else
4410MSA_ST_DF(DF_BYTE,   b, cpu_stb_data)
4411MSA_ST_DF(DF_HALF,   h, cpu_stw_data)
4412MSA_ST_DF(DF_WORD,   w, cpu_stl_data)
4413MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
4414#endif
4415
4416void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
4417{
4418#ifndef CONFIG_USER_ONLY
4419    target_ulong index = addr & 0x1fffffff;
4420    if (op == 9) {
4421        /* Index Store Tag */
4422        memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
4423                                     8, MEMTXATTRS_UNSPECIFIED);
4424    } else if (op == 5) {
4425        /* Index Load Tag */
4426        memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
4427                                    8, MEMTXATTRS_UNSPECIFIED);
4428    }
4429#endif
4430}
4431