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