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