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 <stdlib.h>
  20#include "cpu.h"
  21#include "qemu/host-utils.h"
  22
  23#include "helper.h"
  24
  25#if !defined(CONFIG_USER_ONLY)
  26#include "exec/softmmu_exec.h"
  27#endif /* !defined(CONFIG_USER_ONLY) */
  28
  29#ifndef CONFIG_USER_ONLY
  30static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
  31#endif
  32
  33/*****************************************************************************/
  34/* Exceptions processing helpers */
  35
  36static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
  37                                                        uint32_t exception,
  38                                                        int error_code,
  39                                                        uintptr_t pc)
  40{
  41    if (exception < EXCP_SC) {
  42        qemu_log("%s: %d %d\n", __func__, exception, error_code);
  43    }
  44    env->exception_index = exception;
  45    env->error_code = error_code;
  46
  47    if (pc) {
  48        /* now we have a real cpu fault */
  49        cpu_restore_state(env, pc);
  50    }
  51
  52    cpu_loop_exit(env);
  53}
  54
  55static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
  56                                                    uint32_t exception,
  57                                                    uintptr_t pc)
  58{
  59    do_raise_exception_err(env, exception, 0, pc);
  60}
  61
  62void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
  63                                int error_code)
  64{
  65    do_raise_exception_err(env, exception, error_code, 0);
  66}
  67
  68void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
  69{
  70    do_raise_exception(env, exception, 0);
  71}
  72
  73#if defined(CONFIG_USER_ONLY)
  74#define HELPER_LD(name, insn, type)                                     \
  75static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
  76                             int mem_idx)                               \
  77{                                                                       \
  78    return (type) insn##_raw(addr);                                     \
  79}
  80#else
  81#define HELPER_LD(name, insn, type)                                     \
  82static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
  83                             int mem_idx)                               \
  84{                                                                       \
  85    switch (mem_idx)                                                    \
  86    {                                                                   \
  87    case 0: return (type) cpu_##insn##_kernel(env, addr); break;        \
  88    case 1: return (type) cpu_##insn##_super(env, addr); break;         \
  89    default:                                                            \
  90    case 2: return (type) cpu_##insn##_user(env, addr); break;          \
  91    }                                                                   \
  92}
  93#endif
  94HELPER_LD(lbu, ldub, uint8_t)
  95HELPER_LD(lw, ldl, int32_t)
  96#ifdef TARGET_MIPS64
  97HELPER_LD(ld, ldq, int64_t)
  98#endif
  99#undef HELPER_LD
 100
 101#if defined(CONFIG_USER_ONLY)
 102#define HELPER_ST(name, insn, type)                                     \
 103static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
 104                             type val, int mem_idx)                     \
 105{                                                                       \
 106    insn##_raw(addr, val);                                              \
 107}
 108#else
 109#define HELPER_ST(name, insn, type)                                     \
 110static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
 111                             type val, int mem_idx)                     \
 112{                                                                       \
 113    switch (mem_idx)                                                    \
 114    {                                                                   \
 115    case 0: cpu_##insn##_kernel(env, addr, val); break;                 \
 116    case 1: cpu_##insn##_super(env, addr, val); break;                  \
 117    default:                                                            \
 118    case 2: cpu_##insn##_user(env, addr, val); break;                   \
 119    }                                                                   \
 120}
 121#endif
 122HELPER_ST(sb, stb, uint8_t)
 123HELPER_ST(sw, stl, uint32_t)
 124#ifdef TARGET_MIPS64
 125HELPER_ST(sd, stq, uint64_t)
 126#endif
 127#undef HELPER_ST
 128
 129target_ulong helper_clo (target_ulong arg1)
 130{
 131    return clo32(arg1);
 132}
 133
 134target_ulong helper_clz (target_ulong arg1)
 135{
 136    return clz32(arg1);
 137}
 138
 139#if defined(TARGET_MIPS64)
 140target_ulong helper_dclo (target_ulong arg1)
 141{
 142    return clo64(arg1);
 143}
 144
 145target_ulong helper_dclz (target_ulong arg1)
 146{
 147    return clz64(arg1);
 148}
 149#endif /* TARGET_MIPS64 */
 150
 151/* 64 bits arithmetic for 32 bits hosts */
 152static inline uint64_t get_HILO(CPUMIPSState *env)
 153{
 154    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
 155}
 156
 157static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
 158{
 159    target_ulong tmp;
 160    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
 161    tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 162    return tmp;
 163}
 164
 165static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
 166{
 167    target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
 168    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 169    return tmp;
 170}
 171
 172/* Multiplication variants of the vr54xx. */
 173target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
 174                         target_ulong arg2)
 175{
 176    return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
 177                                 (int64_t)(int32_t)arg2));
 178}
 179
 180target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
 181                          target_ulong arg2)
 182{
 183    return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
 184                       (uint64_t)(uint32_t)arg2);
 185}
 186
 187target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
 188                         target_ulong arg2)
 189{
 190    return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
 191                       (int64_t)(int32_t)arg2);
 192}
 193
 194target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
 195                           target_ulong arg2)
 196{
 197    return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
 198                       (int64_t)(int32_t)arg2);
 199}
 200
 201target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
 202                          target_ulong arg2)
 203{
 204    return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
 205                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 206}
 207
 208target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
 209                            target_ulong arg2)
 210{
 211    return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
 212                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 213}
 214
 215target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
 216                         target_ulong arg2)
 217{
 218    return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
 219                       (int64_t)(int32_t)arg2);
 220}
 221
 222target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
 223                           target_ulong arg2)
 224{
 225    return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
 226                       (int64_t)(int32_t)arg2);
 227}
 228
 229target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
 230                          target_ulong arg2)
 231{
 232    return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
 233                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 234}
 235
 236target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
 237                            target_ulong arg2)
 238{
 239    return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
 240                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
 241}
 242
 243target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
 244                          target_ulong arg2)
 245{
 246    return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
 247}
 248
 249target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
 250                           target_ulong arg2)
 251{
 252    return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
 253                       (uint64_t)(uint32_t)arg2);
 254}
 255
 256target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
 257                           target_ulong arg2)
 258{
 259    return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
 260                       (int64_t)(int32_t)arg2);
 261}
 262
 263target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
 264                            target_ulong arg2)
 265{
 266    return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
 267                       (uint64_t)(uint32_t)arg2);
 268}
 269
 270#ifndef CONFIG_USER_ONLY
 271
 272static inline hwaddr do_translate_address(CPUMIPSState *env,
 273                                                      target_ulong address,
 274                                                      int rw)
 275{
 276    hwaddr lladdr;
 277
 278    lladdr = cpu_mips_translate_address(env, address, rw);
 279
 280    if (lladdr == -1LL) {
 281        cpu_loop_exit(env);
 282    } else {
 283        return lladdr;
 284    }
 285}
 286
 287#define HELPER_LD_ATOMIC(name, insn)                                          \
 288target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
 289{                                                                             \
 290    env->lladdr = do_translate_address(env, arg, 0);                          \
 291    env->llval = do_##insn(env, arg, mem_idx);                                \
 292    return env->llval;                                                        \
 293}
 294HELPER_LD_ATOMIC(ll, lw)
 295#ifdef TARGET_MIPS64
 296HELPER_LD_ATOMIC(lld, ld)
 297#endif
 298#undef HELPER_LD_ATOMIC
 299
 300#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
 301target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
 302                           target_ulong arg2, int mem_idx)                    \
 303{                                                                             \
 304    target_long tmp;                                                          \
 305                                                                              \
 306    if (arg2 & almask) {                                                      \
 307        env->CP0_BadVAddr = arg2;                                             \
 308        helper_raise_exception(env, EXCP_AdES);                               \
 309    }                                                                         \
 310    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
 311        tmp = do_##ld_insn(env, arg2, mem_idx);                               \
 312        if (tmp == env->llval) {                                              \
 313            do_##st_insn(env, arg2, arg1, mem_idx);                           \
 314            return 1;                                                         \
 315        }                                                                     \
 316    }                                                                         \
 317    return 0;                                                                 \
 318}
 319HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
 320#ifdef TARGET_MIPS64
 321HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
 322#endif
 323#undef HELPER_ST_ATOMIC
 324#endif
 325
 326#ifdef TARGET_WORDS_BIGENDIAN
 327#define GET_LMASK(v) ((v) & 3)
 328#define GET_OFFSET(addr, offset) (addr + (offset))
 329#else
 330#define GET_LMASK(v) (((v) & 3) ^ 3)
 331#define GET_OFFSET(addr, offset) (addr - (offset))
 332#endif
 333
 334void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 335                int mem_idx)
 336{
 337    do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
 338
 339    if (GET_LMASK(arg2) <= 2)
 340        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
 341
 342    if (GET_LMASK(arg2) <= 1)
 343        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
 344
 345    if (GET_LMASK(arg2) == 0)
 346        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
 347}
 348
 349void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 350                int mem_idx)
 351{
 352    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
 353
 354    if (GET_LMASK(arg2) >= 1)
 355        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 356
 357    if (GET_LMASK(arg2) >= 2)
 358        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 359
 360    if (GET_LMASK(arg2) == 3)
 361        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 362}
 363
 364#if defined(TARGET_MIPS64)
 365/* "half" load and stores.  We must do the memory access inline,
 366   or fault handling won't work.  */
 367
 368#ifdef TARGET_WORDS_BIGENDIAN
 369#define GET_LMASK64(v) ((v) & 7)
 370#else
 371#define GET_LMASK64(v) (((v) & 7) ^ 7)
 372#endif
 373
 374void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 375                int mem_idx)
 376{
 377    do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
 378
 379    if (GET_LMASK64(arg2) <= 6)
 380        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
 381
 382    if (GET_LMASK64(arg2) <= 5)
 383        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
 384
 385    if (GET_LMASK64(arg2) <= 4)
 386        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
 387
 388    if (GET_LMASK64(arg2) <= 3)
 389        do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
 390
 391    if (GET_LMASK64(arg2) <= 2)
 392        do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
 393
 394    if (GET_LMASK64(arg2) <= 1)
 395        do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
 396
 397    if (GET_LMASK64(arg2) <= 0)
 398        do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
 399}
 400
 401void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
 402                int mem_idx)
 403{
 404    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
 405
 406    if (GET_LMASK64(arg2) >= 1)
 407        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 408
 409    if (GET_LMASK64(arg2) >= 2)
 410        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 411
 412    if (GET_LMASK64(arg2) >= 3)
 413        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 414
 415    if (GET_LMASK64(arg2) >= 4)
 416        do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
 417
 418    if (GET_LMASK64(arg2) >= 5)
 419        do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
 420
 421    if (GET_LMASK64(arg2) >= 6)
 422        do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
 423
 424    if (GET_LMASK64(arg2) == 7)
 425        do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
 426}
 427#endif /* TARGET_MIPS64 */
 428
 429static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
 430
 431void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 432                uint32_t mem_idx)
 433{
 434    target_ulong base_reglist = reglist & 0xf;
 435    target_ulong do_r31 = reglist & 0x10;
 436
 437    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 438        target_ulong i;
 439
 440        for (i = 0; i < base_reglist; i++) {
 441            env->active_tc.gpr[multiple_regs[i]] =
 442                (target_long)do_lw(env, addr, mem_idx);
 443            addr += 4;
 444        }
 445    }
 446
 447    if (do_r31) {
 448        env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
 449    }
 450}
 451
 452void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 453                uint32_t mem_idx)
 454{
 455    target_ulong base_reglist = reglist & 0xf;
 456    target_ulong do_r31 = reglist & 0x10;
 457
 458    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 459        target_ulong i;
 460
 461        for (i = 0; i < base_reglist; i++) {
 462            do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
 463            addr += 4;
 464        }
 465    }
 466
 467    if (do_r31) {
 468        do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
 469    }
 470}
 471
 472#if defined(TARGET_MIPS64)
 473void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 474                uint32_t mem_idx)
 475{
 476    target_ulong base_reglist = reglist & 0xf;
 477    target_ulong do_r31 = reglist & 0x10;
 478
 479    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 480        target_ulong i;
 481
 482        for (i = 0; i < base_reglist; i++) {
 483            env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
 484            addr += 8;
 485        }
 486    }
 487
 488    if (do_r31) {
 489        env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
 490    }
 491}
 492
 493void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
 494                uint32_t mem_idx)
 495{
 496    target_ulong base_reglist = reglist & 0xf;
 497    target_ulong do_r31 = reglist & 0x10;
 498
 499    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
 500        target_ulong i;
 501
 502        for (i = 0; i < base_reglist; i++) {
 503            do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
 504            addr += 8;
 505        }
 506    }
 507
 508    if (do_r31) {
 509        do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
 510    }
 511}
 512#endif
 513
 514#ifndef CONFIG_USER_ONLY
 515/* SMP helpers.  */
 516static bool mips_vpe_is_wfi(MIPSCPU *c)
 517{
 518    CPUState *cpu = CPU(c);
 519    CPUMIPSState *env = &c->env;
 520
 521    /* If the VPE is halted but otherwise active, it means it's waiting for
 522       an interrupt.  */
 523    return cpu->halted && mips_vpe_active(env);
 524}
 525
 526static inline void mips_vpe_wake(MIPSCPU *c)
 527{
 528    /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
 529       because there might be other conditions that state that c should
 530       be sleeping.  */
 531    cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
 532}
 533
 534static inline void mips_vpe_sleep(MIPSCPU *cpu)
 535{
 536    CPUState *cs = CPU(cpu);
 537
 538    /* The VPE was shut off, really go to bed.
 539       Reset any old _WAKE requests.  */
 540    cs->halted = 1;
 541    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
 542}
 543
 544static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
 545{
 546    CPUMIPSState *c = &cpu->env;
 547
 548    /* FIXME: TC reschedule.  */
 549    if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
 550        mips_vpe_wake(cpu);
 551    }
 552}
 553
 554static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
 555{
 556    CPUMIPSState *c = &cpu->env;
 557
 558    /* FIXME: TC reschedule.  */
 559    if (!mips_vpe_active(c)) {
 560        mips_vpe_sleep(cpu);
 561    }
 562}
 563
 564/**
 565 * mips_cpu_map_tc:
 566 * @env: CPU from which mapping is performed.
 567 * @tc: Should point to an int with the value of the global TC index.
 568 *
 569 * This function will transform @tc into a local index within the
 570 * returned #CPUMIPSState.
 571 */
 572/* FIXME: This code assumes that all VPEs have the same number of TCs,
 573          which depends on runtime setup. Can probably be fixed by
 574          walking the list of CPUMIPSStates.  */
 575static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
 576{
 577    MIPSCPU *cpu;
 578    CPUState *cs;
 579    CPUState *other_cs;
 580    int vpe_idx;
 581    int tc_idx = *tc;
 582
 583    if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
 584        /* Not allowed to address other CPUs.  */
 585        *tc = env->current_tc;
 586        return env;
 587    }
 588
 589    cs = CPU(mips_env_get_cpu(env));
 590    vpe_idx = tc_idx / cs->nr_threads;
 591    *tc = tc_idx % cs->nr_threads;
 592    other_cs = qemu_get_cpu(vpe_idx);
 593    if (other_cs == NULL) {
 594        return env;
 595    }
 596    cpu = MIPS_CPU(other_cs);
 597    return &cpu->env;
 598}
 599
 600/* The per VPE CP0_Status register shares some fields with the per TC
 601   CP0_TCStatus registers. These fields are wired to the same registers,
 602   so changes to either of them should be reflected on both registers.
 603
 604   Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
 605
 606   These helper call synchronizes the regs for a given cpu.  */
 607
 608/* Called for updates to CP0_Status.  */
 609static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
 610{
 611    int32_t tcstatus, *tcst;
 612    uint32_t v = cpu->CP0_Status;
 613    uint32_t cu, mx, asid, ksu;
 614    uint32_t mask = ((1 << CP0TCSt_TCU3)
 615                       | (1 << CP0TCSt_TCU2)
 616                       | (1 << CP0TCSt_TCU1)
 617                       | (1 << CP0TCSt_TCU0)
 618                       | (1 << CP0TCSt_TMX)
 619                       | (3 << CP0TCSt_TKSU)
 620                       | (0xff << CP0TCSt_TASID));
 621
 622    cu = (v >> CP0St_CU0) & 0xf;
 623    mx = (v >> CP0St_MX) & 0x1;
 624    ksu = (v >> CP0St_KSU) & 0x3;
 625    asid = env->CP0_EntryHi & 0xff;
 626
 627    tcstatus = cu << CP0TCSt_TCU0;
 628    tcstatus |= mx << CP0TCSt_TMX;
 629    tcstatus |= ksu << CP0TCSt_TKSU;
 630    tcstatus |= asid;
 631
 632    if (tc == cpu->current_tc) {
 633        tcst = &cpu->active_tc.CP0_TCStatus;
 634    } else {
 635        tcst = &cpu->tcs[tc].CP0_TCStatus;
 636    }
 637
 638    *tcst &= ~mask;
 639    *tcst |= tcstatus;
 640    compute_hflags(cpu);
 641}
 642
 643/* Called for updates to CP0_TCStatus.  */
 644static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
 645                             target_ulong v)
 646{
 647    uint32_t status;
 648    uint32_t tcu, tmx, tasid, tksu;
 649    uint32_t mask = ((1 << CP0St_CU3)
 650                       | (1 << CP0St_CU2)
 651                       | (1 << CP0St_CU1)
 652                       | (1 << CP0St_CU0)
 653                       | (1 << CP0St_MX)
 654                       | (3 << CP0St_KSU));
 655
 656    tcu = (v >> CP0TCSt_TCU0) & 0xf;
 657    tmx = (v >> CP0TCSt_TMX) & 0x1;
 658    tasid = v & 0xff;
 659    tksu = (v >> CP0TCSt_TKSU) & 0x3;
 660
 661    status = tcu << CP0St_CU0;
 662    status |= tmx << CP0St_MX;
 663    status |= tksu << CP0St_KSU;
 664
 665    cpu->CP0_Status &= ~mask;
 666    cpu->CP0_Status |= status;
 667
 668    /* Sync the TASID with EntryHi.  */
 669    cpu->CP0_EntryHi &= ~0xff;
 670    cpu->CP0_EntryHi = tasid;
 671
 672    compute_hflags(cpu);
 673}
 674
 675/* Called for updates to CP0_EntryHi.  */
 676static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
 677{
 678    int32_t *tcst;
 679    uint32_t asid, v = cpu->CP0_EntryHi;
 680
 681    asid = v & 0xff;
 682
 683    if (tc == cpu->current_tc) {
 684        tcst = &cpu->active_tc.CP0_TCStatus;
 685    } else {
 686        tcst = &cpu->tcs[tc].CP0_TCStatus;
 687    }
 688
 689    *tcst &= ~0xff;
 690    *tcst |= asid;
 691}
 692
 693/* CP0 helpers */
 694target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
 695{
 696    return env->mvp->CP0_MVPControl;
 697}
 698
 699target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
 700{
 701    return env->mvp->CP0_MVPConf0;
 702}
 703
 704target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
 705{
 706    return env->mvp->CP0_MVPConf1;
 707}
 708
 709target_ulong helper_mfc0_random(CPUMIPSState *env)
 710{
 711    return (int32_t)cpu_mips_get_random(env);
 712}
 713
 714target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
 715{
 716    return env->active_tc.CP0_TCStatus;
 717}
 718
 719target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
 720{
 721    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 722    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 723
 724    if (other_tc == other->current_tc)
 725        return other->active_tc.CP0_TCStatus;
 726    else
 727        return other->tcs[other_tc].CP0_TCStatus;
 728}
 729
 730target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
 731{
 732    return env->active_tc.CP0_TCBind;
 733}
 734
 735target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
 736{
 737    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 738    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 739
 740    if (other_tc == other->current_tc)
 741        return other->active_tc.CP0_TCBind;
 742    else
 743        return other->tcs[other_tc].CP0_TCBind;
 744}
 745
 746target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
 747{
 748    return env->active_tc.PC;
 749}
 750
 751target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
 752{
 753    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 754    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 755
 756    if (other_tc == other->current_tc)
 757        return other->active_tc.PC;
 758    else
 759        return other->tcs[other_tc].PC;
 760}
 761
 762target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
 763{
 764    return env->active_tc.CP0_TCHalt;
 765}
 766
 767target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
 768{
 769    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 770    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 771
 772    if (other_tc == other->current_tc)
 773        return other->active_tc.CP0_TCHalt;
 774    else
 775        return other->tcs[other_tc].CP0_TCHalt;
 776}
 777
 778target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
 779{
 780    return env->active_tc.CP0_TCContext;
 781}
 782
 783target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
 784{
 785    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 786    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 787
 788    if (other_tc == other->current_tc)
 789        return other->active_tc.CP0_TCContext;
 790    else
 791        return other->tcs[other_tc].CP0_TCContext;
 792}
 793
 794target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
 795{
 796    return env->active_tc.CP0_TCSchedule;
 797}
 798
 799target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
 800{
 801    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 802    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 803
 804    if (other_tc == other->current_tc)
 805        return other->active_tc.CP0_TCSchedule;
 806    else
 807        return other->tcs[other_tc].CP0_TCSchedule;
 808}
 809
 810target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
 811{
 812    return env->active_tc.CP0_TCScheFBack;
 813}
 814
 815target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
 816{
 817    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 818    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 819
 820    if (other_tc == other->current_tc)
 821        return other->active_tc.CP0_TCScheFBack;
 822    else
 823        return other->tcs[other_tc].CP0_TCScheFBack;
 824}
 825
 826target_ulong helper_mfc0_count(CPUMIPSState *env)
 827{
 828    return (int32_t)cpu_mips_get_count(env);
 829}
 830
 831target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
 832{
 833    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 834    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 835
 836    return other->CP0_EntryHi;
 837}
 838
 839target_ulong helper_mftc0_cause(CPUMIPSState *env)
 840{
 841    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 842    int32_t tccause;
 843    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 844
 845    if (other_tc == other->current_tc) {
 846        tccause = other->CP0_Cause;
 847    } else {
 848        tccause = other->CP0_Cause;
 849    }
 850
 851    return tccause;
 852}
 853
 854target_ulong helper_mftc0_status(CPUMIPSState *env)
 855{
 856    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 857    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 858
 859    return other->CP0_Status;
 860}
 861
 862target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
 863{
 864    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
 865}
 866
 867target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
 868{
 869    return (int32_t)env->CP0_WatchLo[sel];
 870}
 871
 872target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
 873{
 874    return env->CP0_WatchHi[sel];
 875}
 876
 877target_ulong helper_mfc0_debug(CPUMIPSState *env)
 878{
 879    target_ulong t0 = env->CP0_Debug;
 880    if (env->hflags & MIPS_HFLAG_DM)
 881        t0 |= 1 << CP0DB_DM;
 882
 883    return t0;
 884}
 885
 886target_ulong helper_mftc0_debug(CPUMIPSState *env)
 887{
 888    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 889    int32_t tcstatus;
 890    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 891
 892    if (other_tc == other->current_tc)
 893        tcstatus = other->active_tc.CP0_Debug_tcstatus;
 894    else
 895        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
 896
 897    /* XXX: Might be wrong, check with EJTAG spec. */
 898    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
 899            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
 900}
 901
 902#if defined(TARGET_MIPS64)
 903target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
 904{
 905    return env->active_tc.PC;
 906}
 907
 908target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
 909{
 910    return env->active_tc.CP0_TCHalt;
 911}
 912
 913target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
 914{
 915    return env->active_tc.CP0_TCContext;
 916}
 917
 918target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
 919{
 920    return env->active_tc.CP0_TCSchedule;
 921}
 922
 923target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
 924{
 925    return env->active_tc.CP0_TCScheFBack;
 926}
 927
 928target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
 929{
 930    return env->lladdr >> env->CP0_LLAddr_shift;
 931}
 932
 933target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
 934{
 935    return env->CP0_WatchLo[sel];
 936}
 937#endif /* TARGET_MIPS64 */
 938
 939void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
 940{
 941    int num = 1;
 942    unsigned int tmp = env->tlb->nb_tlb;
 943
 944    do {
 945        tmp >>= 1;
 946        num <<= 1;
 947    } while (tmp);
 948    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
 949}
 950
 951void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
 952{
 953    uint32_t mask = 0;
 954    uint32_t newval;
 955
 956    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
 957        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
 958                (1 << CP0MVPCo_EVP);
 959    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
 960        mask |= (1 << CP0MVPCo_STLB);
 961    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
 962
 963    // TODO: Enable/disable shared TLB, enable/disable VPEs.
 964
 965    env->mvp->CP0_MVPControl = newval;
 966}
 967
 968void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
 969{
 970    uint32_t mask;
 971    uint32_t newval;
 972
 973    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
 974           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
 975    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
 976
 977    /* Yield scheduler intercept not implemented. */
 978    /* Gating storage scheduler intercept not implemented. */
 979
 980    // TODO: Enable/disable TCs.
 981
 982    env->CP0_VPEControl = newval;
 983}
 984
 985void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
 986{
 987    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 988    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
 989    uint32_t mask;
 990    uint32_t newval;
 991
 992    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
 993           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
 994    newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
 995
 996    /* TODO: Enable/disable TCs.  */
 997
 998    other->CP0_VPEControl = newval;
 999}
1000
1001target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
1002{
1003    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1004    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1005    /* FIXME: Mask away return zero on read bits.  */
1006    return other->CP0_VPEControl;
1007}
1008
1009target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1010{
1011    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1012    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1013
1014    return other->CP0_VPEConf0;
1015}
1016
1017void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1018{
1019    uint32_t mask = 0;
1020    uint32_t newval;
1021
1022    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1023        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1024            mask |= (0xff << CP0VPEC0_XTC);
1025        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1026    }
1027    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1028
1029    // TODO: TC exclusive handling due to ERL/EXL.
1030
1031    env->CP0_VPEConf0 = newval;
1032}
1033
1034void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1035{
1036    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1037    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1038    uint32_t mask = 0;
1039    uint32_t newval;
1040
1041    mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1042    newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1043
1044    /* TODO: TC exclusive handling due to ERL/EXL.  */
1045    other->CP0_VPEConf0 = newval;
1046}
1047
1048void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1049{
1050    uint32_t mask = 0;
1051    uint32_t newval;
1052
1053    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1054        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1055                (0xff << CP0VPEC1_NCP1);
1056    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1057
1058    /* UDI not implemented. */
1059    /* CP2 not implemented. */
1060
1061    // TODO: Handle FPU (CP1) binding.
1062
1063    env->CP0_VPEConf1 = newval;
1064}
1065
1066void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1067{
1068    /* Yield qualifier inputs not implemented. */
1069    env->CP0_YQMask = 0x00000000;
1070}
1071
1072void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1073{
1074    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1075}
1076
1077void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1078{
1079    /* Large physaddr (PABITS) not implemented */
1080    /* 1k pages not implemented */
1081    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1082}
1083
1084void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1085{
1086    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1087    uint32_t newval;
1088
1089    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1090
1091    env->active_tc.CP0_TCStatus = newval;
1092    sync_c0_tcstatus(env, env->current_tc, newval);
1093}
1094
1095void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1096{
1097    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1098    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1099
1100    if (other_tc == other->current_tc)
1101        other->active_tc.CP0_TCStatus = arg1;
1102    else
1103        other->tcs[other_tc].CP0_TCStatus = arg1;
1104    sync_c0_tcstatus(other, other_tc, arg1);
1105}
1106
1107void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1108{
1109    uint32_t mask = (1 << CP0TCBd_TBE);
1110    uint32_t newval;
1111
1112    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1113        mask |= (1 << CP0TCBd_CurVPE);
1114    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1115    env->active_tc.CP0_TCBind = newval;
1116}
1117
1118void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1119{
1120    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1121    uint32_t mask = (1 << CP0TCBd_TBE);
1122    uint32_t newval;
1123    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1124
1125    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1126        mask |= (1 << CP0TCBd_CurVPE);
1127    if (other_tc == other->current_tc) {
1128        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1129        other->active_tc.CP0_TCBind = newval;
1130    } else {
1131        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1132        other->tcs[other_tc].CP0_TCBind = newval;
1133    }
1134}
1135
1136void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1137{
1138    env->active_tc.PC = arg1;
1139    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1140    env->lladdr = 0ULL;
1141    /* MIPS16 not implemented. */
1142}
1143
1144void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1145{
1146    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1147    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1148
1149    if (other_tc == other->current_tc) {
1150        other->active_tc.PC = arg1;
1151        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1152        other->lladdr = 0ULL;
1153        /* MIPS16 not implemented. */
1154    } else {
1155        other->tcs[other_tc].PC = arg1;
1156        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1157        other->lladdr = 0ULL;
1158        /* MIPS16 not implemented. */
1159    }
1160}
1161
1162void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1163{
1164    MIPSCPU *cpu = mips_env_get_cpu(env);
1165
1166    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1167
1168    // TODO: Halt TC / Restart (if allocated+active) TC.
1169    if (env->active_tc.CP0_TCHalt & 1) {
1170        mips_tc_sleep(cpu, env->current_tc);
1171    } else {
1172        mips_tc_wake(cpu, env->current_tc);
1173    }
1174}
1175
1176void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1177{
1178    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1179    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1180    MIPSCPU *other_cpu = mips_env_get_cpu(other);
1181
1182    // TODO: Halt TC / Restart (if allocated+active) TC.
1183
1184    if (other_tc == other->current_tc)
1185        other->active_tc.CP0_TCHalt = arg1;
1186    else
1187        other->tcs[other_tc].CP0_TCHalt = arg1;
1188
1189    if (arg1 & 1) {
1190        mips_tc_sleep(other_cpu, other_tc);
1191    } else {
1192        mips_tc_wake(other_cpu, other_tc);
1193    }
1194}
1195
1196void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1197{
1198    env->active_tc.CP0_TCContext = arg1;
1199}
1200
1201void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1202{
1203    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1204    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1205
1206    if (other_tc == other->current_tc)
1207        other->active_tc.CP0_TCContext = arg1;
1208    else
1209        other->tcs[other_tc].CP0_TCContext = arg1;
1210}
1211
1212void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1213{
1214    env->active_tc.CP0_TCSchedule = arg1;
1215}
1216
1217void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1218{
1219    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1220    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1221
1222    if (other_tc == other->current_tc)
1223        other->active_tc.CP0_TCSchedule = arg1;
1224    else
1225        other->tcs[other_tc].CP0_TCSchedule = arg1;
1226}
1227
1228void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1229{
1230    env->active_tc.CP0_TCScheFBack = arg1;
1231}
1232
1233void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1234{
1235    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1236    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1237
1238    if (other_tc == other->current_tc)
1239        other->active_tc.CP0_TCScheFBack = arg1;
1240    else
1241        other->tcs[other_tc].CP0_TCScheFBack = arg1;
1242}
1243
1244void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1245{
1246    /* Large physaddr (PABITS) not implemented */
1247    /* 1k pages not implemented */
1248    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1249}
1250
1251void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1252{
1253    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1254}
1255
1256void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1257{
1258    /* 1k pages not implemented */
1259    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1260}
1261
1262void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1263{
1264    /* SmartMIPS not implemented */
1265    /* Large physaddr (PABITS) not implemented */
1266    /* 1k pages not implemented */
1267    env->CP0_PageGrain = 0;
1268}
1269
1270void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1271{
1272    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1273}
1274
1275void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1276{
1277    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1278}
1279
1280void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1281{
1282    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1283}
1284
1285void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1286{
1287    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1288}
1289
1290void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1291{
1292    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1293}
1294
1295void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1296{
1297    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1298}
1299
1300void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1301{
1302    env->CP0_HWREna = arg1 & 0x0000000F;
1303}
1304
1305void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1306{
1307    cpu_mips_store_count(env, arg1);
1308}
1309
1310void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1311{
1312    target_ulong old, val;
1313
1314    /* 1k pages not implemented */
1315    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1316#if defined(TARGET_MIPS64)
1317    val &= env->SEGMask;
1318#endif
1319    old = env->CP0_EntryHi;
1320    env->CP0_EntryHi = val;
1321    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1322        sync_c0_entryhi(env, env->current_tc);
1323    }
1324    /* If the ASID changes, flush qemu's TLB.  */
1325    if ((old & 0xFF) != (val & 0xFF))
1326        cpu_mips_tlb_flush(env, 1);
1327}
1328
1329void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1330{
1331    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1332    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1333
1334    other->CP0_EntryHi = arg1;
1335    sync_c0_entryhi(other, other_tc);
1336}
1337
1338void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1339{
1340    cpu_mips_store_compare(env, arg1);
1341}
1342
1343void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1344{
1345    uint32_t val, old;
1346    uint32_t mask = env->CP0_Status_rw_bitmask;
1347
1348    val = arg1 & mask;
1349    old = env->CP0_Status;
1350    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1351    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1352        sync_c0_status(env, env, env->current_tc);
1353    } else {
1354        compute_hflags(env);
1355    }
1356
1357    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1358        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1359                old, old & env->CP0_Cause & CP0Ca_IP_mask,
1360                val, val & env->CP0_Cause & CP0Ca_IP_mask,
1361                env->CP0_Cause);
1362        switch (env->hflags & MIPS_HFLAG_KSU) {
1363        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1364        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1365        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1366        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1367        }
1368    }
1369}
1370
1371void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1372{
1373    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1374    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1375
1376    other->CP0_Status = arg1 & ~0xf1000018;
1377    sync_c0_status(env, other, other_tc);
1378}
1379
1380void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1381{
1382    /* vectored interrupts not implemented, no performance counters. */
1383    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1384}
1385
1386void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1387{
1388    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1389    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1390}
1391
1392static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
1393{
1394    uint32_t mask = 0x00C00300;
1395    uint32_t old = cpu->CP0_Cause;
1396    int i;
1397
1398    if (cpu->insn_flags & ISA_MIPS32R2) {
1399        mask |= 1 << CP0Ca_DC;
1400    }
1401
1402    cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
1403
1404    if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
1405        if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
1406            cpu_mips_stop_count(cpu);
1407        } else {
1408            cpu_mips_start_count(cpu);
1409        }
1410    }
1411
1412    /* Set/reset software interrupts */
1413    for (i = 0 ; i < 2 ; i++) {
1414        if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
1415            cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
1416        }
1417    }
1418}
1419
1420void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1421{
1422    mtc0_cause(env, arg1);
1423}
1424
1425void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1426{
1427    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1428    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1429
1430    mtc0_cause(other, arg1);
1431}
1432
1433target_ulong helper_mftc0_epc(CPUMIPSState *env)
1434{
1435    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1436    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1437
1438    return other->CP0_EPC;
1439}
1440
1441target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1442{
1443    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1444    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1445
1446    return other->CP0_EBase;
1447}
1448
1449void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1450{
1451    /* vectored interrupts not implemented */
1452    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1453}
1454
1455void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1456{
1457    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1458    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1459    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1460}
1461
1462target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1463{
1464    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1465    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1466
1467    switch (idx) {
1468    case 0: return other->CP0_Config0;
1469    case 1: return other->CP0_Config1;
1470    case 2: return other->CP0_Config2;
1471    case 3: return other->CP0_Config3;
1472    /* 4 and 5 are reserved.  */
1473    case 6: return other->CP0_Config6;
1474    case 7: return other->CP0_Config7;
1475    default:
1476        break;
1477    }
1478    return 0;
1479}
1480
1481void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1482{
1483    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1484}
1485
1486void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1487{
1488    /* tertiary/secondary caches not implemented */
1489    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1490}
1491
1492void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1493{
1494    target_long mask = env->CP0_LLAddr_rw_bitmask;
1495    arg1 = arg1 << env->CP0_LLAddr_shift;
1496    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1497}
1498
1499void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1500{
1501    /* Watch exceptions for instructions, data loads, data stores
1502       not implemented. */
1503    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1504}
1505
1506void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1507{
1508    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1509    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1510}
1511
1512void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1513{
1514    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1515    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1516}
1517
1518void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1519{
1520    env->CP0_Framemask = arg1; /* XXX */
1521}
1522
1523void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1524{
1525    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1526    if (arg1 & (1 << CP0DB_DM))
1527        env->hflags |= MIPS_HFLAG_DM;
1528    else
1529        env->hflags &= ~MIPS_HFLAG_DM;
1530}
1531
1532void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1533{
1534    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1535    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1536    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1537
1538    /* XXX: Might be wrong, check with EJTAG spec. */
1539    if (other_tc == other->current_tc)
1540        other->active_tc.CP0_Debug_tcstatus = val;
1541    else
1542        other->tcs[other_tc].CP0_Debug_tcstatus = val;
1543    other->CP0_Debug = (other->CP0_Debug &
1544                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1545                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1546}
1547
1548void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1549{
1550    env->CP0_Performance0 = arg1 & 0x000007ff;
1551}
1552
1553void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1554{
1555    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1556}
1557
1558void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1559{
1560    env->CP0_DataLo = arg1; /* XXX */
1561}
1562
1563void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1564{
1565    env->CP0_TagHi = arg1; /* XXX */
1566}
1567
1568void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1569{
1570    env->CP0_DataHi = arg1; /* XXX */
1571}
1572
1573/* MIPS MT functions */
1574target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1575{
1576    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1577    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1578
1579    if (other_tc == other->current_tc)
1580        return other->active_tc.gpr[sel];
1581    else
1582        return other->tcs[other_tc].gpr[sel];
1583}
1584
1585target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1586{
1587    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1588    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1589
1590    if (other_tc == other->current_tc)
1591        return other->active_tc.LO[sel];
1592    else
1593        return other->tcs[other_tc].LO[sel];
1594}
1595
1596target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1597{
1598    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1599    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1600
1601    if (other_tc == other->current_tc)
1602        return other->active_tc.HI[sel];
1603    else
1604        return other->tcs[other_tc].HI[sel];
1605}
1606
1607target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1608{
1609    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1610    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1611
1612    if (other_tc == other->current_tc)
1613        return other->active_tc.ACX[sel];
1614    else
1615        return other->tcs[other_tc].ACX[sel];
1616}
1617
1618target_ulong helper_mftdsp(CPUMIPSState *env)
1619{
1620    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1621    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1622
1623    if (other_tc == other->current_tc)
1624        return other->active_tc.DSPControl;
1625    else
1626        return other->tcs[other_tc].DSPControl;
1627}
1628
1629void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1630{
1631    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1632    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1633
1634    if (other_tc == other->current_tc)
1635        other->active_tc.gpr[sel] = arg1;
1636    else
1637        other->tcs[other_tc].gpr[sel] = arg1;
1638}
1639
1640void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1641{
1642    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1643    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1644
1645    if (other_tc == other->current_tc)
1646        other->active_tc.LO[sel] = arg1;
1647    else
1648        other->tcs[other_tc].LO[sel] = arg1;
1649}
1650
1651void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1652{
1653    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1654    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1655
1656    if (other_tc == other->current_tc)
1657        other->active_tc.HI[sel] = arg1;
1658    else
1659        other->tcs[other_tc].HI[sel] = arg1;
1660}
1661
1662void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1663{
1664    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1665    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1666
1667    if (other_tc == other->current_tc)
1668        other->active_tc.ACX[sel] = arg1;
1669    else
1670        other->tcs[other_tc].ACX[sel] = arg1;
1671}
1672
1673void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1674{
1675    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1676    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1677
1678    if (other_tc == other->current_tc)
1679        other->active_tc.DSPControl = arg1;
1680    else
1681        other->tcs[other_tc].DSPControl = arg1;
1682}
1683
1684/* MIPS MT functions */
1685target_ulong helper_dmt(void)
1686{
1687    // TODO
1688     return 0;
1689}
1690
1691target_ulong helper_emt(void)
1692{
1693    // TODO
1694    return 0;
1695}
1696
1697target_ulong helper_dvpe(CPUMIPSState *env)
1698{
1699    CPUState *other_cs = first_cpu;
1700    target_ulong prev = env->mvp->CP0_MVPControl;
1701
1702    CPU_FOREACH(other_cs) {
1703        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1704        /* Turn off all VPEs except the one executing the dvpe.  */
1705        if (&other_cpu->env != env) {
1706            other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1707            mips_vpe_sleep(other_cpu);
1708        }
1709    }
1710    return prev;
1711}
1712
1713target_ulong helper_evpe(CPUMIPSState *env)
1714{
1715    CPUState *other_cs = first_cpu;
1716    target_ulong prev = env->mvp->CP0_MVPControl;
1717
1718    CPU_FOREACH(other_cs) {
1719        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1720
1721        if (&other_cpu->env != env
1722            /* If the VPE is WFI, don't disturb its sleep.  */
1723            && !mips_vpe_is_wfi(other_cpu)) {
1724            /* Enable the VPE.  */
1725            other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1726            mips_vpe_wake(other_cpu); /* And wake it up.  */
1727        }
1728    }
1729    return prev;
1730}
1731#endif /* !CONFIG_USER_ONLY */
1732
1733void helper_fork(target_ulong arg1, target_ulong arg2)
1734{
1735    // arg1 = rt, arg2 = rs
1736    // TODO: store to TC register
1737}
1738
1739target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
1740{
1741    target_long arg1 = arg;
1742
1743    if (arg1 < 0) {
1744        /* No scheduling policy implemented. */
1745        if (arg1 != -2) {
1746            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1747                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1748                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1749                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1750                helper_raise_exception(env, EXCP_THREAD);
1751            }
1752        }
1753    } else if (arg1 == 0) {
1754        if (0 /* TODO: TC underflow */) {
1755            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1756            helper_raise_exception(env, EXCP_THREAD);
1757        } else {
1758            // TODO: Deallocate TC
1759        }
1760    } else if (arg1 > 0) {
1761        /* Yield qualifier inputs not implemented. */
1762        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1763        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1764        helper_raise_exception(env, EXCP_THREAD);
1765    }
1766    return env->CP0_YQMask;
1767}
1768
1769#ifndef CONFIG_USER_ONLY
1770/* TLB management */
1771static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1772{
1773    /* Flush qemu's TLB and discard all shadowed entries.  */
1774    tlb_flush (env, flush_global);
1775    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1776}
1777
1778static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1779{
1780    /* Discard entries from env->tlb[first] onwards.  */
1781    while (env->tlb->tlb_in_use > first) {
1782        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1783    }
1784}
1785
1786static void r4k_fill_tlb(CPUMIPSState *env, int idx)
1787{
1788    r4k_tlb_t *tlb;
1789
1790    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1791    tlb = &env->tlb->mmu.r4k.tlb[idx];
1792    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1793#if defined(TARGET_MIPS64)
1794    tlb->VPN &= env->SEGMask;
1795#endif
1796    tlb->ASID = env->CP0_EntryHi & 0xFF;
1797    tlb->PageMask = env->CP0_PageMask;
1798    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1799    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1800    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1801    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1802    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1803    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1804    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1805    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1806    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1807}
1808
1809void r4k_helper_tlbwi(CPUMIPSState *env)
1810{
1811    r4k_tlb_t *tlb;
1812    int idx;
1813    target_ulong VPN;
1814    uint8_t ASID;
1815    bool G, V0, D0, V1, D1;
1816
1817    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1818    tlb = &env->tlb->mmu.r4k.tlb[idx];
1819    VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1820#if defined(TARGET_MIPS64)
1821    VPN &= env->SEGMask;
1822#endif
1823    ASID = env->CP0_EntryHi & 0xff;
1824    G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1825    V0 = (env->CP0_EntryLo0 & 2) != 0;
1826    D0 = (env->CP0_EntryLo0 & 4) != 0;
1827    V1 = (env->CP0_EntryLo1 & 2) != 0;
1828    D1 = (env->CP0_EntryLo1 & 4) != 0;
1829
1830    /* Discard cached TLB entries, unless tlbwi is just upgrading access
1831       permissions on the current entry. */
1832    if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
1833        (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
1834        (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
1835        r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1836    }
1837
1838    r4k_invalidate_tlb(env, idx, 0);
1839    r4k_fill_tlb(env, idx);
1840}
1841
1842void r4k_helper_tlbwr(CPUMIPSState *env)
1843{
1844    int r = cpu_mips_get_random(env);
1845
1846    r4k_invalidate_tlb(env, r, 1);
1847    r4k_fill_tlb(env, r);
1848}
1849
1850void r4k_helper_tlbp(CPUMIPSState *env)
1851{
1852    r4k_tlb_t *tlb;
1853    target_ulong mask;
1854    target_ulong tag;
1855    target_ulong VPN;
1856    uint8_t ASID;
1857    int i;
1858
1859    ASID = env->CP0_EntryHi & 0xFF;
1860    for (i = 0; i < env->tlb->nb_tlb; i++) {
1861        tlb = &env->tlb->mmu.r4k.tlb[i];
1862        /* 1k pages are not supported. */
1863        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1864        tag = env->CP0_EntryHi & ~mask;
1865        VPN = tlb->VPN & ~mask;
1866#if defined(TARGET_MIPS64)
1867        tag &= env->SEGMask;
1868#endif
1869        /* Check ASID, virtual page number & size */
1870        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1871            /* TLB match */
1872            env->CP0_Index = i;
1873            break;
1874        }
1875    }
1876    if (i == env->tlb->nb_tlb) {
1877        /* No match.  Discard any shadow entries, if any of them match.  */
1878        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
1879            tlb = &env->tlb->mmu.r4k.tlb[i];
1880            /* 1k pages are not supported. */
1881            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1882            tag = env->CP0_EntryHi & ~mask;
1883            VPN = tlb->VPN & ~mask;
1884#if defined(TARGET_MIPS64)
1885            tag &= env->SEGMask;
1886#endif
1887            /* Check ASID, virtual page number & size */
1888            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1889                r4k_mips_tlb_flush_extra (env, i);
1890                break;
1891            }
1892        }
1893
1894        env->CP0_Index |= 0x80000000;
1895    }
1896}
1897
1898void r4k_helper_tlbr(CPUMIPSState *env)
1899{
1900    r4k_tlb_t *tlb;
1901    uint8_t ASID;
1902    int idx;
1903
1904    ASID = env->CP0_EntryHi & 0xFF;
1905    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1906    tlb = &env->tlb->mmu.r4k.tlb[idx];
1907
1908    /* If this will change the current ASID, flush qemu's TLB.  */
1909    if (ASID != tlb->ASID)
1910        cpu_mips_tlb_flush (env, 1);
1911
1912    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1913
1914    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1915    env->CP0_PageMask = tlb->PageMask;
1916    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1917                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1918    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1919                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1920}
1921
1922void helper_tlbwi(CPUMIPSState *env)
1923{
1924    env->tlb->helper_tlbwi(env);
1925}
1926
1927void helper_tlbwr(CPUMIPSState *env)
1928{
1929    env->tlb->helper_tlbwr(env);
1930}
1931
1932void helper_tlbp(CPUMIPSState *env)
1933{
1934    env->tlb->helper_tlbp(env);
1935}
1936
1937void helper_tlbr(CPUMIPSState *env)
1938{
1939    env->tlb->helper_tlbr(env);
1940}
1941
1942/* Specials */
1943target_ulong helper_di(CPUMIPSState *env)
1944{
1945    target_ulong t0 = env->CP0_Status;
1946
1947    env->CP0_Status = t0 & ~(1 << CP0St_IE);
1948    return t0;
1949}
1950
1951target_ulong helper_ei(CPUMIPSState *env)
1952{
1953    target_ulong t0 = env->CP0_Status;
1954
1955    env->CP0_Status = t0 | (1 << CP0St_IE);
1956    return t0;
1957}
1958
1959static void debug_pre_eret(CPUMIPSState *env)
1960{
1961    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1962        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1963                env->active_tc.PC, env->CP0_EPC);
1964        if (env->CP0_Status & (1 << CP0St_ERL))
1965            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1966        if (env->hflags & MIPS_HFLAG_DM)
1967            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1968        qemu_log("\n");
1969    }
1970}
1971
1972static void debug_post_eret(CPUMIPSState *env)
1973{
1974    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1975        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1976                env->active_tc.PC, env->CP0_EPC);
1977        if (env->CP0_Status & (1 << CP0St_ERL))
1978            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1979        if (env->hflags & MIPS_HFLAG_DM)
1980            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1981        switch (env->hflags & MIPS_HFLAG_KSU) {
1982        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1983        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1984        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1985        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1986        }
1987    }
1988}
1989
1990static void set_pc(CPUMIPSState *env, target_ulong error_pc)
1991{
1992    env->active_tc.PC = error_pc & ~(target_ulong)1;
1993    if (error_pc & 1) {
1994        env->hflags |= MIPS_HFLAG_M16;
1995    } else {
1996        env->hflags &= ~(MIPS_HFLAG_M16);
1997    }
1998}
1999
2000void helper_eret(CPUMIPSState *env)
2001{
2002    debug_pre_eret(env);
2003    if (env->CP0_Status & (1 << CP0St_ERL)) {
2004        set_pc(env, env->CP0_ErrorEPC);
2005        env->CP0_Status &= ~(1 << CP0St_ERL);
2006    } else {
2007        set_pc(env, env->CP0_EPC);
2008        env->CP0_Status &= ~(1 << CP0St_EXL);
2009    }
2010    compute_hflags(env);
2011    debug_post_eret(env);
2012    env->lladdr = 1;
2013}
2014
2015void helper_deret(CPUMIPSState *env)
2016{
2017    debug_pre_eret(env);
2018    set_pc(env, env->CP0_DEPC);
2019
2020    env->hflags &= MIPS_HFLAG_DM;
2021    compute_hflags(env);
2022    debug_post_eret(env);
2023    env->lladdr = 1;
2024}
2025#endif /* !CONFIG_USER_ONLY */
2026
2027target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2028{
2029    if ((env->hflags & MIPS_HFLAG_CP0) ||
2030        (env->CP0_HWREna & (1 << 0)))
2031        return env->CP0_EBase & 0x3ff;
2032    else
2033        helper_raise_exception(env, EXCP_RI);
2034
2035    return 0;
2036}
2037
2038target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2039{
2040    if ((env->hflags & MIPS_HFLAG_CP0) ||
2041        (env->CP0_HWREna & (1 << 1)))
2042        return env->SYNCI_Step;
2043    else
2044        helper_raise_exception(env, EXCP_RI);
2045
2046    return 0;
2047}
2048
2049target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2050{
2051    if ((env->hflags & MIPS_HFLAG_CP0) ||
2052        (env->CP0_HWREna & (1 << 2)))
2053        return env->CP0_Count;
2054    else
2055        helper_raise_exception(env, EXCP_RI);
2056
2057    return 0;
2058}
2059
2060target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2061{
2062    if ((env->hflags & MIPS_HFLAG_CP0) ||
2063        (env->CP0_HWREna & (1 << 3)))
2064        return env->CCRes;
2065    else
2066        helper_raise_exception(env, EXCP_RI);
2067
2068    return 0;
2069}
2070
2071void helper_pmon(CPUMIPSState *env, int function)
2072{
2073    function /= 2;
2074    switch (function) {
2075    case 2: /* TODO: char inbyte(int waitflag); */
2076        if (env->active_tc.gpr[4] == 0)
2077            env->active_tc.gpr[2] = -1;
2078        /* Fall through */
2079    case 11: /* TODO: char inbyte (void); */
2080        env->active_tc.gpr[2] = -1;
2081        break;
2082    case 3:
2083    case 12:
2084        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2085        break;
2086    case 17:
2087        break;
2088    case 158:
2089        {
2090            unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
2091            printf("%s", fmt);
2092        }
2093        break;
2094    }
2095}
2096
2097void helper_wait(CPUMIPSState *env)
2098{
2099    CPUState *cs = CPU(mips_env_get_cpu(env));
2100
2101    cs->halted = 1;
2102    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2103    helper_raise_exception(env, EXCP_HLT);
2104}
2105
2106#if !defined(CONFIG_USER_ONLY)
2107
2108static void QEMU_NORETURN do_unaligned_access(CPUMIPSState *env,
2109                                              target_ulong addr, int is_write,
2110                                              int is_user, uintptr_t retaddr);
2111
2112#define MMUSUFFIX _mmu
2113#define ALIGNED_ONLY
2114
2115#define SHIFT 0
2116#include "exec/softmmu_template.h"
2117
2118#define SHIFT 1
2119#include "exec/softmmu_template.h"
2120
2121#define SHIFT 2
2122#include "exec/softmmu_template.h"
2123
2124#define SHIFT 3
2125#include "exec/softmmu_template.h"
2126
2127static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
2128                                int is_write, int is_user, uintptr_t retaddr)
2129{
2130    env->CP0_BadVAddr = addr;
2131    do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
2132}
2133
2134void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
2135              uintptr_t retaddr)
2136{
2137    int ret;
2138
2139    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
2140    if (ret) {
2141        do_raise_exception_err(env, env->exception_index,
2142                               env->error_code, retaddr);
2143    }
2144}
2145
2146void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2147                                bool is_write, bool is_exec, int unused,
2148                                unsigned size)
2149{
2150    MIPSCPU *cpu = MIPS_CPU(cs);
2151    CPUMIPSState *env = &cpu->env;
2152
2153    if (is_exec) {
2154        helper_raise_exception(env, EXCP_IBE);
2155    } else {
2156        helper_raise_exception(env, EXCP_DBE);
2157    }
2158}
2159#endif /* !CONFIG_USER_ONLY */
2160
2161/* Complex FPU operations which may need stack space. */
2162
2163#define FLOAT_TWO32 make_float32(1 << 30)
2164#define FLOAT_TWO64 make_float64(1ULL << 62)
2165#define FP_TO_INT32_OVERFLOW 0x7fffffff
2166#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
2167
2168/* convert MIPS rounding mode in FCR31 to IEEE library */
2169static unsigned int ieee_rm[] = {
2170    float_round_nearest_even,
2171    float_round_to_zero,
2172    float_round_up,
2173    float_round_down
2174};
2175
2176static inline void restore_rounding_mode(CPUMIPSState *env)
2177{
2178    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
2179                            &env->active_fpu.fp_status);
2180}
2181
2182static inline void restore_flush_mode(CPUMIPSState *env)
2183{
2184    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
2185                      &env->active_fpu.fp_status);
2186}
2187
2188target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2189{
2190    target_ulong arg1;
2191
2192    switch (reg) {
2193    case 0:
2194        arg1 = (int32_t)env->active_fpu.fcr0;
2195        break;
2196    case 25:
2197        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2198        break;
2199    case 26:
2200        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2201        break;
2202    case 28:
2203        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2204        break;
2205    default:
2206        arg1 = (int32_t)env->active_fpu.fcr31;
2207        break;
2208    }
2209
2210    return arg1;
2211}
2212
2213void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg)
2214{
2215    switch(reg) {
2216    case 25:
2217        if (arg1 & 0xffffff00)
2218            return;
2219        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2220                     ((arg1 & 0x1) << 23);
2221        break;
2222    case 26:
2223        if (arg1 & 0x007c0000)
2224            return;
2225        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2226        break;
2227    case 28:
2228        if (arg1 & 0x007c0000)
2229            return;
2230        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2231                     ((arg1 & 0x4) << 22);
2232        break;
2233    case 31:
2234        if (arg1 & 0x007c0000)
2235            return;
2236        env->active_fpu.fcr31 = arg1;
2237        break;
2238    default:
2239        return;
2240    }
2241    /* set rounding mode */
2242    restore_rounding_mode(env);
2243    /* set flush-to-zero mode */
2244    restore_flush_mode(env);
2245    set_float_exception_flags(0, &env->active_fpu.fp_status);
2246    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2247        do_raise_exception(env, EXCP_FPE, GETPC());
2248}
2249
2250static inline int ieee_ex_to_mips(int xcpt)
2251{
2252    int ret = 0;
2253    if (xcpt) {
2254        if (xcpt & float_flag_invalid) {
2255            ret |= FP_INVALID;
2256        }
2257        if (xcpt & float_flag_overflow) {
2258            ret |= FP_OVERFLOW;
2259        }
2260        if (xcpt & float_flag_underflow) {
2261            ret |= FP_UNDERFLOW;
2262        }
2263        if (xcpt & float_flag_divbyzero) {
2264            ret |= FP_DIV0;
2265        }
2266        if (xcpt & float_flag_inexact) {
2267            ret |= FP_INEXACT;
2268        }
2269    }
2270    return ret;
2271}
2272
2273static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2274{
2275    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2276
2277    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2278
2279    if (tmp) {
2280        set_float_exception_flags(0, &env->active_fpu.fp_status);
2281
2282        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2283            do_raise_exception(env, EXCP_FPE, pc);
2284        } else {
2285            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2286        }
2287    }
2288}
2289
2290/* Float support.
2291   Single precition routines have a "s" suffix, double precision a
2292   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2293   paired single lower "pl", paired single upper "pu".  */
2294
2295/* unary operations, modifying fp status  */
2296uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2297{
2298    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2299    update_fcr31(env, GETPC());
2300    return fdt0;
2301}
2302
2303uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2304{
2305    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2306    update_fcr31(env, GETPC());
2307    return fst0;
2308}
2309
2310uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2311{
2312    uint64_t fdt2;
2313
2314    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2315    update_fcr31(env, GETPC());
2316    return fdt2;
2317}
2318
2319uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2320{
2321    uint64_t fdt2;
2322
2323    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2324    update_fcr31(env, GETPC());
2325    return fdt2;
2326}
2327
2328uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2329{
2330    uint64_t fdt2;
2331
2332    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2333    update_fcr31(env, GETPC());
2334    return fdt2;
2335}
2336
2337uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
2338{
2339    uint64_t dt2;
2340
2341    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2342    if (get_float_exception_flags(&env->active_fpu.fp_status)
2343        & (float_flag_invalid | float_flag_overflow)) {
2344        dt2 = FP_TO_INT64_OVERFLOW;
2345    }
2346    update_fcr31(env, GETPC());
2347    return dt2;
2348}
2349
2350uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
2351{
2352    uint64_t dt2;
2353
2354    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2355    if (get_float_exception_flags(&env->active_fpu.fp_status)
2356        & (float_flag_invalid | float_flag_overflow)) {
2357        dt2 = FP_TO_INT64_OVERFLOW;
2358    }
2359    update_fcr31(env, GETPC());
2360    return dt2;
2361}
2362
2363uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2364{
2365    uint32_t fst2;
2366    uint32_t fsth2;
2367
2368    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2369    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2370    update_fcr31(env, GETPC());
2371    return ((uint64_t)fsth2 << 32) | fst2;
2372}
2373
2374uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2375{
2376    uint32_t wt2;
2377    uint32_t wth2;
2378    int excp, excph;
2379
2380    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2381    excp = get_float_exception_flags(&env->active_fpu.fp_status);
2382    if (excp & (float_flag_overflow | float_flag_invalid)) {
2383        wt2 = FP_TO_INT32_OVERFLOW;
2384    }
2385
2386    set_float_exception_flags(0, &env->active_fpu.fp_status);
2387    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2388    excph = get_float_exception_flags(&env->active_fpu.fp_status);
2389    if (excph & (float_flag_overflow | float_flag_invalid)) {
2390        wth2 = FP_TO_INT32_OVERFLOW;
2391    }
2392
2393    set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
2394    update_fcr31(env, GETPC());
2395
2396    return ((uint64_t)wth2 << 32) | wt2;
2397}
2398
2399uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2400{
2401    uint32_t fst2;
2402
2403    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2404    update_fcr31(env, GETPC());
2405    return fst2;
2406}
2407
2408uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2409{
2410    uint32_t fst2;
2411
2412    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2413    update_fcr31(env, GETPC());
2414    return fst2;
2415}
2416
2417uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2418{
2419    uint32_t fst2;
2420
2421    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2422    update_fcr31(env, GETPC());
2423    return fst2;
2424}
2425
2426uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2427{
2428    uint32_t wt2;
2429
2430    wt2 = wt0;
2431    update_fcr31(env, GETPC());
2432    return wt2;
2433}
2434
2435uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2436{
2437    uint32_t wt2;
2438
2439    wt2 = wth0;
2440    update_fcr31(env, GETPC());
2441    return wt2;
2442}
2443
2444uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
2445{
2446    uint32_t wt2;
2447
2448    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2449    update_fcr31(env, GETPC());
2450    if (get_float_exception_flags(&env->active_fpu.fp_status)
2451        & (float_flag_invalid | float_flag_overflow)) {
2452        wt2 = FP_TO_INT32_OVERFLOW;
2453    }
2454    return wt2;
2455}
2456
2457uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
2458{
2459    uint32_t wt2;
2460
2461    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2462    if (get_float_exception_flags(&env->active_fpu.fp_status)
2463        & (float_flag_invalid | float_flag_overflow)) {
2464        wt2 = FP_TO_INT32_OVERFLOW;
2465    }
2466    update_fcr31(env, GETPC());
2467    return wt2;
2468}
2469
2470uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
2471{
2472    uint64_t dt2;
2473
2474    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2475    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2476    restore_rounding_mode(env);
2477    if (get_float_exception_flags(&env->active_fpu.fp_status)
2478        & (float_flag_invalid | float_flag_overflow)) {
2479        dt2 = FP_TO_INT64_OVERFLOW;
2480    }
2481    update_fcr31(env, GETPC());
2482    return dt2;
2483}
2484
2485uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
2486{
2487    uint64_t dt2;
2488
2489    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2490    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2491    restore_rounding_mode(env);
2492    if (get_float_exception_flags(&env->active_fpu.fp_status)
2493        & (float_flag_invalid | float_flag_overflow)) {
2494        dt2 = FP_TO_INT64_OVERFLOW;
2495    }
2496    update_fcr31(env, GETPC());
2497    return dt2;
2498}
2499
2500uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
2501{
2502    uint32_t wt2;
2503
2504    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2505    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2506    restore_rounding_mode(env);
2507    if (get_float_exception_flags(&env->active_fpu.fp_status)
2508        & (float_flag_invalid | float_flag_overflow)) {
2509        wt2 = FP_TO_INT32_OVERFLOW;
2510    }
2511    update_fcr31(env, GETPC());
2512    return wt2;
2513}
2514
2515uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
2516{
2517    uint32_t wt2;
2518
2519    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2520    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2521    restore_rounding_mode(env);
2522    if (get_float_exception_flags(&env->active_fpu.fp_status)
2523        & (float_flag_invalid | float_flag_overflow)) {
2524        wt2 = FP_TO_INT32_OVERFLOW;
2525    }
2526    update_fcr31(env, GETPC());
2527    return wt2;
2528}
2529
2530uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
2531{
2532    uint64_t dt2;
2533
2534    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2535    if (get_float_exception_flags(&env->active_fpu.fp_status)
2536        & (float_flag_invalid | float_flag_overflow)) {
2537        dt2 = FP_TO_INT64_OVERFLOW;
2538    }
2539    update_fcr31(env, GETPC());
2540    return dt2;
2541}
2542
2543uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
2544{
2545    uint64_t dt2;
2546
2547    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2548    if (get_float_exception_flags(&env->active_fpu.fp_status)
2549        & (float_flag_invalid | float_flag_overflow)) {
2550        dt2 = FP_TO_INT64_OVERFLOW;
2551    }
2552    update_fcr31(env, GETPC());
2553    return dt2;
2554}
2555
2556uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
2557{
2558    uint32_t wt2;
2559
2560    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2561    if (get_float_exception_flags(&env->active_fpu.fp_status)
2562        & (float_flag_invalid | float_flag_overflow)) {
2563        wt2 = FP_TO_INT32_OVERFLOW;
2564    }
2565    update_fcr31(env, GETPC());
2566    return wt2;
2567}
2568
2569uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
2570{
2571    uint32_t wt2;
2572
2573    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2574    if (get_float_exception_flags(&env->active_fpu.fp_status)
2575        & (float_flag_invalid | float_flag_overflow)) {
2576        wt2 = FP_TO_INT32_OVERFLOW;
2577    }
2578    update_fcr31(env, GETPC());
2579    return wt2;
2580}
2581
2582uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
2583{
2584    uint64_t dt2;
2585
2586    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2587    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2588    restore_rounding_mode(env);
2589    if (get_float_exception_flags(&env->active_fpu.fp_status)
2590        & (float_flag_invalid | float_flag_overflow)) {
2591        dt2 = FP_TO_INT64_OVERFLOW;
2592    }
2593    update_fcr31(env, GETPC());
2594    return dt2;
2595}
2596
2597uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
2598{
2599    uint64_t dt2;
2600
2601    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2602    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2603    restore_rounding_mode(env);
2604    if (get_float_exception_flags(&env->active_fpu.fp_status)
2605        & (float_flag_invalid | float_flag_overflow)) {
2606        dt2 = FP_TO_INT64_OVERFLOW;
2607    }
2608    update_fcr31(env, GETPC());
2609    return dt2;
2610}
2611
2612uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
2613{
2614    uint32_t wt2;
2615
2616    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2617    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2618    restore_rounding_mode(env);
2619    if (get_float_exception_flags(&env->active_fpu.fp_status)
2620        & (float_flag_invalid | float_flag_overflow)) {
2621        wt2 = FP_TO_INT32_OVERFLOW;
2622    }
2623    update_fcr31(env, GETPC());
2624    return wt2;
2625}
2626
2627uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
2628{
2629    uint32_t wt2;
2630
2631    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2632    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2633    restore_rounding_mode(env);
2634    if (get_float_exception_flags(&env->active_fpu.fp_status)
2635        & (float_flag_invalid | float_flag_overflow)) {
2636        wt2 = FP_TO_INT32_OVERFLOW;
2637    }
2638    update_fcr31(env, GETPC());
2639    return wt2;
2640}
2641
2642uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
2643{
2644    uint64_t dt2;
2645
2646    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2647    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2648    restore_rounding_mode(env);
2649    if (get_float_exception_flags(&env->active_fpu.fp_status)
2650        & (float_flag_invalid | float_flag_overflow)) {
2651        dt2 = FP_TO_INT64_OVERFLOW;
2652    }
2653    update_fcr31(env, GETPC());
2654    return dt2;
2655}
2656
2657uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
2658{
2659    uint64_t dt2;
2660
2661    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2662    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2663    restore_rounding_mode(env);
2664    if (get_float_exception_flags(&env->active_fpu.fp_status)
2665        & (float_flag_invalid | float_flag_overflow)) {
2666        dt2 = FP_TO_INT64_OVERFLOW;
2667    }
2668    update_fcr31(env, GETPC());
2669    return dt2;
2670}
2671
2672uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
2673{
2674    uint32_t wt2;
2675
2676    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2677    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2678    restore_rounding_mode(env);
2679    if (get_float_exception_flags(&env->active_fpu.fp_status)
2680        & (float_flag_invalid | float_flag_overflow)) {
2681        wt2 = FP_TO_INT32_OVERFLOW;
2682    }
2683    update_fcr31(env, GETPC());
2684    return wt2;
2685}
2686
2687uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
2688{
2689    uint32_t wt2;
2690
2691    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2692    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2693    restore_rounding_mode(env);
2694    if (get_float_exception_flags(&env->active_fpu.fp_status)
2695        & (float_flag_invalid | float_flag_overflow)) {
2696        wt2 = FP_TO_INT32_OVERFLOW;
2697    }
2698    update_fcr31(env, GETPC());
2699    return wt2;
2700}
2701
2702/* unary operations, not modifying fp status  */
2703#define FLOAT_UNOP(name)                                       \
2704uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2705{                                                              \
2706    return float64_ ## name(fdt0);                             \
2707}                                                              \
2708uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2709{                                                              \
2710    return float32_ ## name(fst0);                             \
2711}                                                              \
2712uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2713{                                                              \
2714    uint32_t wt0;                                              \
2715    uint32_t wth0;                                             \
2716                                                               \
2717    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
2718    wth0 = float32_ ## name(fdt0 >> 32);                       \
2719    return ((uint64_t)wth0 << 32) | wt0;                       \
2720}
2721FLOAT_UNOP(abs)
2722FLOAT_UNOP(chs)
2723#undef FLOAT_UNOP
2724
2725/* MIPS specific unary operations */
2726uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
2727{
2728    uint64_t fdt2;
2729
2730    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
2731    update_fcr31(env, GETPC());
2732    return fdt2;
2733}
2734
2735uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
2736{
2737    uint32_t fst2;
2738
2739    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
2740    update_fcr31(env, GETPC());
2741    return fst2;
2742}
2743
2744uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
2745{
2746    uint64_t fdt2;
2747
2748    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2749    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
2750    update_fcr31(env, GETPC());
2751    return fdt2;
2752}
2753
2754uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
2755{
2756    uint32_t fst2;
2757
2758    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2759    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2760    update_fcr31(env, GETPC());
2761    return fst2;
2762}
2763
2764uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
2765{
2766    uint64_t fdt2;
2767
2768    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
2769    update_fcr31(env, GETPC());
2770    return fdt2;
2771}
2772
2773uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
2774{
2775    uint32_t fst2;
2776
2777    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
2778    update_fcr31(env, GETPC());
2779    return fst2;
2780}
2781
2782uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
2783{
2784    uint32_t fst2;
2785    uint32_t fsth2;
2786
2787    fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2788    fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
2789    update_fcr31(env, GETPC());
2790    return ((uint64_t)fsth2 << 32) | fst2;
2791}
2792
2793uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
2794{
2795    uint64_t fdt2;
2796
2797    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2798    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
2799    update_fcr31(env, GETPC());
2800    return fdt2;
2801}
2802
2803uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
2804{
2805    uint32_t fst2;
2806
2807    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2808    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2809    update_fcr31(env, GETPC());
2810    return fst2;
2811}
2812
2813uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
2814{
2815    uint32_t fst2;
2816    uint32_t fsth2;
2817
2818    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2819    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2820    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2821    fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
2822    update_fcr31(env, GETPC());
2823    return ((uint64_t)fsth2 << 32) | fst2;
2824}
2825
2826#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
2827
2828/* binary operations */
2829#define FLOAT_BINOP(name)                                          \
2830uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
2831                                     uint64_t fdt0, uint64_t fdt1) \
2832{                                                                  \
2833    uint64_t dt2;                                                  \
2834                                                                   \
2835    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2836    update_fcr31(env, GETPC());                                    \
2837    return dt2;                                                    \
2838}                                                                  \
2839                                                                   \
2840uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
2841                                     uint32_t fst0, uint32_t fst1) \
2842{                                                                  \
2843    uint32_t wt2;                                                  \
2844                                                                   \
2845    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2846    update_fcr31(env, GETPC());                                    \
2847    return wt2;                                                    \
2848}                                                                  \
2849                                                                   \
2850uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
2851                                      uint64_t fdt0,               \
2852                                      uint64_t fdt1)               \
2853{                                                                  \
2854    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
2855    uint32_t fsth0 = fdt0 >> 32;                                   \
2856    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
2857    uint32_t fsth1 = fdt1 >> 32;                                   \
2858    uint32_t wt2;                                                  \
2859    uint32_t wth2;                                                 \
2860                                                                   \
2861    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2862    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2863    update_fcr31(env, GETPC());                                    \
2864    return ((uint64_t)wth2 << 32) | wt2;                           \
2865}
2866
2867FLOAT_BINOP(add)
2868FLOAT_BINOP(sub)
2869FLOAT_BINOP(mul)
2870FLOAT_BINOP(div)
2871#undef FLOAT_BINOP
2872
2873#define UNFUSED_FMA(prefix, a, b, c, flags)                          \
2874{                                                                    \
2875    a = prefix##_mul(a, b, &env->active_fpu.fp_status);              \
2876    if ((flags) & float_muladd_negate_c) {                           \
2877        a = prefix##_sub(a, c, &env->active_fpu.fp_status);          \
2878    } else {                                                         \
2879        a = prefix##_add(a, c, &env->active_fpu.fp_status);          \
2880    }                                                                \
2881    if ((flags) & float_muladd_negate_result) {                      \
2882        a = prefix##_chs(a);                                         \
2883    }                                                                \
2884}
2885
2886/* FMA based operations */
2887#define FLOAT_FMA(name, type)                                        \
2888uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
2889                                     uint64_t fdt0, uint64_t fdt1,   \
2890                                     uint64_t fdt2)                  \
2891{                                                                    \
2892    UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
2893    update_fcr31(env, GETPC());                                      \
2894    return fdt0;                                                     \
2895}                                                                    \
2896                                                                     \
2897uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
2898                                     uint32_t fst0, uint32_t fst1,   \
2899                                     uint32_t fst2)                  \
2900{                                                                    \
2901    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
2902    update_fcr31(env, GETPC());                                      \
2903    return fst0;                                                     \
2904}                                                                    \
2905                                                                     \
2906uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
2907                                      uint64_t fdt0, uint64_t fdt1,  \
2908                                      uint64_t fdt2)                 \
2909{                                                                    \
2910    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
2911    uint32_t fsth0 = fdt0 >> 32;                                     \
2912    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
2913    uint32_t fsth1 = fdt1 >> 32;                                     \
2914    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
2915    uint32_t fsth2 = fdt2 >> 32;                                     \
2916                                                                     \
2917    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
2918    UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
2919    update_fcr31(env, GETPC());                                      \
2920    return ((uint64_t)fsth0 << 32) | fst0;                           \
2921}
2922FLOAT_FMA(madd, 0)
2923FLOAT_FMA(msub, float_muladd_negate_c)
2924FLOAT_FMA(nmadd, float_muladd_negate_result)
2925FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
2926#undef FLOAT_FMA
2927
2928/* MIPS specific binary operations */
2929uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
2930{
2931    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2932    fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
2933    update_fcr31(env, GETPC());
2934    return fdt2;
2935}
2936
2937uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
2938{
2939    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2940    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
2941    update_fcr31(env, GETPC());
2942    return fst2;
2943}
2944
2945uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
2946{
2947    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2948    uint32_t fsth0 = fdt0 >> 32;
2949    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2950    uint32_t fsth2 = fdt2 >> 32;
2951
2952    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2953    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2954    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
2955    fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
2956    update_fcr31(env, GETPC());
2957    return ((uint64_t)fsth2 << 32) | fst2;
2958}
2959
2960uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
2961{
2962    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2963    fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
2964    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
2965    update_fcr31(env, GETPC());
2966    return fdt2;
2967}
2968
2969uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
2970{
2971    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2972    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
2973    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2974    update_fcr31(env, GETPC());
2975    return fst2;
2976}
2977
2978uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
2979{
2980    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2981    uint32_t fsth0 = fdt0 >> 32;
2982    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2983    uint32_t fsth2 = fdt2 >> 32;
2984
2985    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2986    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2987    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
2988    fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
2989    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2990    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
2991    update_fcr31(env, GETPC());
2992    return ((uint64_t)fsth2 << 32) | fst2;
2993}
2994
2995uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
2996{
2997    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2998    uint32_t fsth0 = fdt0 >> 32;
2999    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3000    uint32_t fsth1 = fdt1 >> 32;
3001    uint32_t fst2;
3002    uint32_t fsth2;
3003
3004    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3005    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3006    update_fcr31(env, GETPC());
3007    return ((uint64_t)fsth2 << 32) | fst2;
3008}
3009
3010uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3011{
3012    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3013    uint32_t fsth0 = fdt0 >> 32;
3014    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3015    uint32_t fsth1 = fdt1 >> 32;
3016    uint32_t fst2;
3017    uint32_t fsth2;
3018
3019    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3020    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3021    update_fcr31(env, GETPC());
3022    return ((uint64_t)fsth2 << 32) | fst2;
3023}
3024
3025/* compare operations */
3026#define FOP_COND_D(op, cond)                                   \
3027void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
3028                         uint64_t fdt1, int cc)                \
3029{                                                              \
3030    int c;                                                     \
3031    c = cond;                                                  \
3032    update_fcr31(env, GETPC());                                \
3033    if (c)                                                     \
3034        SET_FP_COND(cc, env->active_fpu);                      \
3035    else                                                       \
3036        CLEAR_FP_COND(cc, env->active_fpu);                    \
3037}                                                              \
3038void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
3039                            uint64_t fdt1, int cc)             \
3040{                                                              \
3041    int c;                                                     \
3042    fdt0 = float64_abs(fdt0);                                  \
3043    fdt1 = float64_abs(fdt1);                                  \
3044    c = cond;                                                  \
3045    update_fcr31(env, GETPC());                                \
3046    if (c)                                                     \
3047        SET_FP_COND(cc, env->active_fpu);                      \
3048    else                                                       \
3049        CLEAR_FP_COND(cc, env->active_fpu);                    \
3050}
3051
3052/* NOTE: the comma operator will make "cond" to eval to false,
3053 * but float64_unordered_quiet() is still called. */
3054FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3055FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
3056FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3057FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3058FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3059FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3060FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3061FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3062/* NOTE: the comma operator will make "cond" to eval to false,
3063 * but float64_unordered() is still called. */
3064FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3065FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
3066FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3067FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3068FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3069FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3070FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3071FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3072
3073#define FOP_COND_S(op, cond)                                   \
3074void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
3075                         uint32_t fst1, int cc)                \
3076{                                                              \
3077    int c;                                                     \
3078    c = cond;                                                  \
3079    update_fcr31(env, GETPC());                                \
3080    if (c)                                                     \
3081        SET_FP_COND(cc, env->active_fpu);                      \
3082    else                                                       \
3083        CLEAR_FP_COND(cc, env->active_fpu);                    \
3084}                                                              \
3085void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
3086                            uint32_t fst1, int cc)             \
3087{                                                              \
3088    int c;                                                     \
3089    fst0 = float32_abs(fst0);                                  \
3090    fst1 = float32_abs(fst1);                                  \
3091    c = cond;                                                  \
3092    update_fcr31(env, GETPC());                                \
3093    if (c)                                                     \
3094        SET_FP_COND(cc, env->active_fpu);                      \
3095    else                                                       \
3096        CLEAR_FP_COND(cc, env->active_fpu);                    \
3097}
3098
3099/* NOTE: the comma operator will make "cond" to eval to false,
3100 * but float32_unordered_quiet() is still called. */
3101FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3102FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
3103FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3104FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3105FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3106FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3107FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3108FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3109/* NOTE: the comma operator will make "cond" to eval to false,
3110 * but float32_unordered() is still called. */
3111FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3112FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
3113FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3114FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3115FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3116FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3117FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3118FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3119
3120#define FOP_COND_PS(op, condl, condh)                           \
3121void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
3122                          uint64_t fdt1, int cc)                \
3123{                                                               \
3124    uint32_t fst0, fsth0, fst1, fsth1;                          \
3125    int ch, cl;                                                 \
3126    fst0 = fdt0 & 0XFFFFFFFF;                                   \
3127    fsth0 = fdt0 >> 32;                                         \
3128    fst1 = fdt1 & 0XFFFFFFFF;                                   \
3129    fsth1 = fdt1 >> 32;                                         \
3130    cl = condl;                                                 \
3131    ch = condh;                                                 \
3132    update_fcr31(env, GETPC());                                 \
3133    if (cl)                                                     \
3134        SET_FP_COND(cc, env->active_fpu);                       \
3135    else                                                        \
3136        CLEAR_FP_COND(cc, env->active_fpu);                     \
3137    if (ch)                                                     \
3138        SET_FP_COND(cc + 1, env->active_fpu);                   \
3139    else                                                        \
3140        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3141}                                                               \
3142void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
3143                             uint64_t fdt1, int cc)             \
3144{                                                               \
3145    uint32_t fst0, fsth0, fst1, fsth1;                          \
3146    int ch, cl;                                                 \
3147    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
3148    fsth0 = float32_abs(fdt0 >> 32);                            \
3149    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
3150    fsth1 = float32_abs(fdt1 >> 32);                            \
3151    cl = condl;                                                 \
3152    ch = condh;                                                 \
3153    update_fcr31(env, GETPC());                                 \
3154    if (cl)                                                     \
3155        SET_FP_COND(cc, env->active_fpu);                       \
3156    else                                                        \
3157        CLEAR_FP_COND(cc, env->active_fpu);                     \
3158    if (ch)                                                     \
3159        SET_FP_COND(cc + 1, env->active_fpu);                   \
3160    else                                                        \
3161        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3162}
3163
3164/* NOTE: the comma operator will make "cond" to eval to false,
3165 * but float32_unordered_quiet() is still called. */
3166FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3167                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3168FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3169                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
3170FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3171                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3172FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3173                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3174FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3175                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3176FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3177                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3178FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3179                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3180FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3181                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3182/* NOTE: the comma operator will make "cond" to eval to false,
3183 * but float32_unordered() is still called. */
3184FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3185                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3186FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3187                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
3188FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3189                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3190FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3191                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3192FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3193                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3194FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3195                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3196FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
3197                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3198FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3199                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3200