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