op_helper.c 120.5 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  MIPS emulation helpers for qemu.
3
 *
B
bellard 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16
 *  Copyright (c) 2004-2005 Jocelyn Mayer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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/>.
B
bellard 已提交
18
 */
19
#include <stdlib.h>
B
Blue Swirl 已提交
20
#include "cpu.h"
21
#include "qemu/host-utils.h"
22
#include "exec/helper-proto.h"
P
Paolo Bonzini 已提交
23
#include "exec/cpu_ldst.h"
24
#include "sysemu/kvm.h"
B
Blue Swirl 已提交
25

26
#ifndef CONFIG_USER_ONLY
27
static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
28 29
#endif

B
bellard 已提交
30 31 32
/*****************************************************************************/
/* Exceptions processing helpers */

33 34 35 36
static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
                                                        uint32_t exception,
                                                        int error_code,
                                                        uintptr_t pc)
B
bellard 已提交
37
{
38 39
    CPUState *cs = CPU(mips_env_get_cpu(env));

40
    if (exception < EXCP_SC) {
41
        qemu_log("%s: %d %d\n", __func__, exception, error_code);
42
    }
43
    cs->exception_index = exception;
B
bellard 已提交
44
    env->error_code = error_code;
45 46 47

    if (pc) {
        /* now we have a real cpu fault */
48
        cpu_restore_state(cs, pc);
49 50
    }

51
    cpu_loop_exit(cs);
B
bellard 已提交
52 53
}

54 55 56
static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
                                                    uint32_t exception,
                                                    uintptr_t pc)
B
bellard 已提交
57
{
58
    do_raise_exception_err(env, exception, 0, pc);
B
bellard 已提交
59 60
}

61 62
void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
                                int error_code)
B
bellard 已提交
63
{
64 65
    do_raise_exception_err(env, exception, error_code, 0);
}
66

67 68 69
void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
{
    do_raise_exception(env, exception, 0);
B
bellard 已提交
70 71
}

72 73
#if defined(CONFIG_USER_ONLY)
#define HELPER_LD(name, insn, type)                                     \
74 75
static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
                             int mem_idx)                               \
76 77 78 79 80
{                                                                       \
    return (type) insn##_raw(addr);                                     \
}
#else
#define HELPER_LD(name, insn, type)                                     \
81 82
static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
                             int mem_idx)                               \
83 84 85
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
86 87
    case 0: return (type) cpu_##insn##_kernel(env, addr); break;        \
    case 1: return (type) cpu_##insn##_super(env, addr); break;         \
88
    default:                                                            \
89
    case 2: return (type) cpu_##insn##_user(env, addr); break;          \
90 91 92 93 94 95 96 97 98 99 100
    }                                                                   \
}
#endif
HELPER_LD(lw, ldl, int32_t)
#ifdef TARGET_MIPS64
HELPER_LD(ld, ldq, int64_t)
#endif
#undef HELPER_LD

#if defined(CONFIG_USER_ONLY)
#define HELPER_ST(name, insn, type)                                     \
101 102
static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
                             type val, int mem_idx)                     \
103 104 105 106 107
{                                                                       \
    insn##_raw(addr, val);                                              \
}
#else
#define HELPER_ST(name, insn, type)                                     \
108 109
static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
                             type val, int mem_idx)                     \
110 111 112
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
113 114
    case 0: cpu_##insn##_kernel(env, addr, val); break;                 \
    case 1: cpu_##insn##_super(env, addr, val); break;                  \
115
    default:                                                            \
116
    case 2: cpu_##insn##_user(env, addr, val); break;                   \
117 118 119 120 121 122 123 124 125 126
    }                                                                   \
}
#endif
HELPER_ST(sb, stb, uint8_t)
HELPER_ST(sw, stl, uint32_t)
#ifdef TARGET_MIPS64
HELPER_ST(sd, stq, uint64_t)
#endif
#undef HELPER_ST

127
target_ulong helper_clo (target_ulong arg1)
128
{
129
    return clo32(arg1);
130 131
}

132
target_ulong helper_clz (target_ulong arg1)
133
{
134
    return clz32(arg1);
135 136
}

137
#if defined(TARGET_MIPS64)
138
target_ulong helper_dclo (target_ulong arg1)
139
{
140
    return clo64(arg1);
141 142
}

143
target_ulong helper_dclz (target_ulong arg1)
144
{
145
    return clz64(arg1);
146
}
147
#endif /* TARGET_MIPS64 */
148

B
bellard 已提交
149
/* 64 bits arithmetic for 32 bits hosts */
150
static inline uint64_t get_HILO(CPUMIPSState *env)
B
bellard 已提交
151
{
152
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
B
bellard 已提交
153 154
}

155
static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
156
{
157
    target_ulong tmp;
158
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
159 160
    tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
    return tmp;
161 162
}

163
static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
164
{
165
    target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
166
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
167
    return tmp;
168 169 170
}

/* Multiplication variants of the vr54xx. */
171 172
target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
173
{
174 175
    return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
                                 (int64_t)(int32_t)arg2));
176 177
}

178 179
target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
180
{
181 182
    return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
183 184
}

185 186
target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
187
{
188 189
    return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
190 191
}

192 193
target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
194
{
195 196
    return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
197 198
}

199 200
target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
201
{
202 203
    return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
204 205
}

206 207
target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
                            target_ulong arg2)
208
{
209 210
    return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
211 212
}

213 214
target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
215
{
216 217
    return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
218 219
}

220 221
target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
222
{
223 224
    return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
225 226
}

227 228
target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
229
{
230 231
    return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
232 233
}

234 235
target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
                            target_ulong arg2)
236
{
237 238
    return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
239 240
}

241 242
target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
243
{
244
    return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
245 246
}

247 248
target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
249
{
250 251
    return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
252 253
}

254 255
target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
256
{
257 258
    return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
259 260
}

261 262
target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
                            target_ulong arg2)
263
{
264 265
    return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
266
}
B
bellard 已提交
267

268 269
static inline target_ulong bitswap(target_ulong v)
{
270 271 272 273 274 275
    v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
              ((v & (target_ulong)0x5555555555555555ULL) << 1);
    v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
              ((v & (target_ulong)0x3333333333333333ULL) << 2);
    v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
              ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    return v;
}

#ifdef TARGET_MIPS64
target_ulong helper_dbitswap(target_ulong rt)
{
    return bitswap(rt);
}
#endif

target_ulong helper_bitswap(target_ulong rt)
{
    return (int32_t)bitswap(rt);
}

291
#ifndef CONFIG_USER_ONLY
292

A
Avi Kivity 已提交
293
static inline hwaddr do_translate_address(CPUMIPSState *env,
294 295
                                                      target_ulong address,
                                                      int rw)
296
{
A
Avi Kivity 已提交
297
    hwaddr lladdr;
298 299 300 301

    lladdr = cpu_mips_translate_address(env, address, rw);

    if (lladdr == -1LL) {
302
        cpu_loop_exit(CPU(mips_env_get_cpu(env)));
303 304 305 306 307
    } else {
        return lladdr;
    }
}

308
#define HELPER_LD_ATOMIC(name, insn)                                          \
309
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
310
{                                                                             \
311 312
    env->lladdr = do_translate_address(env, arg, 0);                          \
    env->llval = do_##insn(env, arg, mem_idx);                                \
313 314 315 316 317 318 319 320 321
    return env->llval;                                                        \
}
HELPER_LD_ATOMIC(ll, lw)
#ifdef TARGET_MIPS64
HELPER_LD_ATOMIC(lld, ld)
#endif
#undef HELPER_LD_ATOMIC

#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
322 323
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
                           target_ulong arg2, int mem_idx)                    \
324 325 326 327 328
{                                                                             \
    target_long tmp;                                                          \
                                                                              \
    if (arg2 & almask) {                                                      \
        env->CP0_BadVAddr = arg2;                                             \
329
        helper_raise_exception(env, EXCP_AdES);                               \
330
    }                                                                         \
331 332
    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
        tmp = do_##ld_insn(env, arg2, mem_idx);                               \
333
        if (tmp == env->llval) {                                              \
334
            do_##st_insn(env, arg2, arg1, mem_idx);                           \
335 336 337 338 339 340 341 342 343 344 345 346
            return 1;                                                         \
        }                                                                     \
    }                                                                         \
    return 0;                                                                 \
}
HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
#ifdef TARGET_MIPS64
HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
#endif
#undef HELPER_ST_ATOMIC
#endif

T
ths 已提交
347 348 349 350 351 352 353 354
#ifdef TARGET_WORDS_BIGENDIAN
#define GET_LMASK(v) ((v) & 3)
#define GET_OFFSET(addr, offset) (addr + (offset))
#else
#define GET_LMASK(v) (((v) & 3) ^ 3)
#define GET_OFFSET(addr, offset) (addr - (offset))
#endif

355 356
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
357
{
358
    do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
359

360
    if (GET_LMASK(arg2) <= 2)
361
        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
362

363
    if (GET_LMASK(arg2) <= 1)
364
        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
365

366
    if (GET_LMASK(arg2) == 0)
367
        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
T
ths 已提交
368 369
}

370 371
void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
372
{
373
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
374

375
    if (GET_LMASK(arg2) >= 1)
376
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
377

378
    if (GET_LMASK(arg2) >= 2)
379
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
380

381
    if (GET_LMASK(arg2) == 3)
382
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
383 384 385 386 387 388 389 390 391 392 393 394
}

#if defined(TARGET_MIPS64)
/* "half" load and stores.  We must do the memory access inline,
   or fault handling won't work.  */

#ifdef TARGET_WORDS_BIGENDIAN
#define GET_LMASK64(v) ((v) & 7)
#else
#define GET_LMASK64(v) (((v) & 7) ^ 7)
#endif

395 396
void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
397
{
398
    do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
399

400
    if (GET_LMASK64(arg2) <= 6)
401
        do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
402

403
    if (GET_LMASK64(arg2) <= 5)
404
        do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
405

406
    if (GET_LMASK64(arg2) <= 4)
407
        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
408

409
    if (GET_LMASK64(arg2) <= 3)
410
        do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
411

412
    if (GET_LMASK64(arg2) <= 2)
413
        do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
414

415
    if (GET_LMASK64(arg2) <= 1)
416
        do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
417

418
    if (GET_LMASK64(arg2) <= 0)
419
        do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
T
ths 已提交
420 421
}

422 423
void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
424
{
425
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
426

427
    if (GET_LMASK64(arg2) >= 1)
428
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
429

430
    if (GET_LMASK64(arg2) >= 2)
431
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
432

433
    if (GET_LMASK64(arg2) >= 3)
434
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
435

436
    if (GET_LMASK64(arg2) >= 4)
437
        do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
438

439
    if (GET_LMASK64(arg2) >= 5)
440
        do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
441

442
    if (GET_LMASK64(arg2) >= 6)
443
        do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
444

445
    if (GET_LMASK64(arg2) == 7)
446
        do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
447 448 449
}
#endif /* TARGET_MIPS64 */

450 451
static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };

452 453
void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
454 455 456 457 458 459 460 461
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;

    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
        target_ulong i;

        for (i = 0; i < base_reglist; i++) {
462 463
            env->active_tc.gpr[multiple_regs[i]] =
                (target_long)do_lw(env, addr, mem_idx);
464 465 466 467 468
            addr += 4;
        }
    }

    if (do_r31) {
469
        env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
470 471 472
    }
}

473 474
void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
475 476 477 478 479 480 481 482
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;

    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
        target_ulong i;

        for (i = 0; i < base_reglist; i++) {
483
            do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
484 485 486 487 488
            addr += 4;
        }
    }

    if (do_r31) {
489
        do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
490 491 492 493
    }
}

#if defined(TARGET_MIPS64)
494 495
void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
496 497 498 499 500 501 502 503
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;

    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
        target_ulong i;

        for (i = 0; i < base_reglist; i++) {
504
            env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
505 506 507 508 509
            addr += 8;
        }
    }

    if (do_r31) {
510
        env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
511 512 513
    }
}

514 515
void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
516 517 518 519 520 521 522 523
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;

    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
        target_ulong i;

        for (i = 0; i < base_reglist; i++) {
524
            do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
525 526 527 528 529
            addr += 8;
        }
    }

    if (do_r31) {
530
        do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
531 532 533 534
    }
}
#endif

T
ths 已提交
535
#ifndef CONFIG_USER_ONLY
536
/* SMP helpers.  */
537
static bool mips_vpe_is_wfi(MIPSCPU *c)
538
{
539
    CPUState *cpu = CPU(c);
540 541
    CPUMIPSState *env = &c->env;

542 543
    /* If the VPE is halted but otherwise active, it means it's waiting for
       an interrupt.  */
544
    return cpu->halted && mips_vpe_active(env);
545 546
}

547
static inline void mips_vpe_wake(MIPSCPU *c)
548 549 550 551
{
    /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
       because there might be other conditions that state that c should
       be sleeping.  */
552
    cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
553 554
}

555
static inline void mips_vpe_sleep(MIPSCPU *cpu)
556
{
557
    CPUState *cs = CPU(cpu);
558

559 560
    /* The VPE was shut off, really go to bed.
       Reset any old _WAKE requests.  */
561
    cs->halted = 1;
562
    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
563 564
}

565
static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
566
{
567 568
    CPUMIPSState *c = &cpu->env;

569
    /* FIXME: TC reschedule.  */
570
    if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
571
        mips_vpe_wake(cpu);
572 573 574
    }
}

575
static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
576
{
577 578
    CPUMIPSState *c = &cpu->env;

579 580
    /* FIXME: TC reschedule.  */
    if (!mips_vpe_active(c)) {
581
        mips_vpe_sleep(cpu);
582 583 584
    }
}

585 586 587 588 589 590 591 592 593
/**
 * mips_cpu_map_tc:
 * @env: CPU from which mapping is performed.
 * @tc: Should point to an int with the value of the global TC index.
 *
 * This function will transform @tc into a local index within the
 * returned #CPUMIPSState.
 */
/* FIXME: This code assumes that all VPEs have the same number of TCs,
594
          which depends on runtime setup. Can probably be fixed by
595
          walking the list of CPUMIPSStates.  */
596
static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
597
{
598
    MIPSCPU *cpu;
599
    CPUState *cs;
600
    CPUState *other_cs;
601
    int vpe_idx;
602 603 604 605 606 607 608 609
    int tc_idx = *tc;

    if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
        /* Not allowed to address other CPUs.  */
        *tc = env->current_tc;
        return env;
    }

610 611 612
    cs = CPU(mips_env_get_cpu(env));
    vpe_idx = tc_idx / cs->nr_threads;
    *tc = tc_idx % cs->nr_threads;
613 614 615 616 617 618
    other_cs = qemu_get_cpu(vpe_idx);
    if (other_cs == NULL) {
        return env;
    }
    cpu = MIPS_CPU(other_cs);
    return &cpu->env;
619 620
}

621 622 623 624 625 626 627 628 629
/* The per VPE CP0_Status register shares some fields with the per TC
   CP0_TCStatus registers. These fields are wired to the same registers,
   so changes to either of them should be reflected on both registers.

   Also, EntryHi shares the bottom 8 bit ASID with TCStauts.

   These helper call synchronizes the regs for a given cpu.  */

/* Called for updates to CP0_Status.  */
630
static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
{
    int32_t tcstatus, *tcst;
    uint32_t v = cpu->CP0_Status;
    uint32_t cu, mx, asid, ksu;
    uint32_t mask = ((1 << CP0TCSt_TCU3)
                       | (1 << CP0TCSt_TCU2)
                       | (1 << CP0TCSt_TCU1)
                       | (1 << CP0TCSt_TCU0)
                       | (1 << CP0TCSt_TMX)
                       | (3 << CP0TCSt_TKSU)
                       | (0xff << CP0TCSt_TASID));

    cu = (v >> CP0St_CU0) & 0xf;
    mx = (v >> CP0St_MX) & 0x1;
    ksu = (v >> CP0St_KSU) & 0x3;
    asid = env->CP0_EntryHi & 0xff;

    tcstatus = cu << CP0TCSt_TCU0;
    tcstatus |= mx << CP0TCSt_TMX;
    tcstatus |= ksu << CP0TCSt_TKSU;
    tcstatus |= asid;

    if (tc == cpu->current_tc) {
        tcst = &cpu->active_tc.CP0_TCStatus;
    } else {
        tcst = &cpu->tcs[tc].CP0_TCStatus;
    }

    *tcst &= ~mask;
    *tcst |= tcstatus;
    compute_hflags(cpu);
}

/* Called for updates to CP0_TCStatus.  */
665 666
static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
                             target_ulong v)
667 668 669
{
    uint32_t status;
    uint32_t tcu, tmx, tasid, tksu;
670
    uint32_t mask = ((1U << CP0St_CU3)
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
                       | (1 << CP0St_CU2)
                       | (1 << CP0St_CU1)
                       | (1 << CP0St_CU0)
                       | (1 << CP0St_MX)
                       | (3 << CP0St_KSU));

    tcu = (v >> CP0TCSt_TCU0) & 0xf;
    tmx = (v >> CP0TCSt_TMX) & 0x1;
    tasid = v & 0xff;
    tksu = (v >> CP0TCSt_TKSU) & 0x3;

    status = tcu << CP0St_CU0;
    status |= tmx << CP0St_MX;
    status |= tksu << CP0St_KSU;

    cpu->CP0_Status &= ~mask;
    cpu->CP0_Status |= status;

    /* Sync the TASID with EntryHi.  */
    cpu->CP0_EntryHi &= ~0xff;
    cpu->CP0_EntryHi = tasid;

    compute_hflags(cpu);
}

/* Called for updates to CP0_EntryHi.  */
697
static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
{
    int32_t *tcst;
    uint32_t asid, v = cpu->CP0_EntryHi;

    asid = v & 0xff;

    if (tc == cpu->current_tc) {
        tcst = &cpu->active_tc.CP0_TCStatus;
    } else {
        tcst = &cpu->tcs[tc].CP0_TCStatus;
    }

    *tcst &= ~0xff;
    *tcst |= asid;
}

B
bellard 已提交
714
/* CP0 helpers */
715
target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
716
{
717
    return env->mvp->CP0_MVPControl;
718 719
}

720
target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
721
{
722
    return env->mvp->CP0_MVPConf0;
723 724
}

725
target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
726
{
727
    return env->mvp->CP0_MVPConf1;
728 729
}

730
target_ulong helper_mfc0_random(CPUMIPSState *env)
B
bellard 已提交
731
{
732
    return (int32_t)cpu_mips_get_random(env);
733
}
B
bellard 已提交
734

735
target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
736
{
737
    return env->active_tc.CP0_TCStatus;
738 739
}

740
target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
741 742
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
743
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
744

745 746
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCStatus;
747
    else
748
        return other->tcs[other_tc].CP0_TCStatus;
749 750
}

751
target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
752
{
753
    return env->active_tc.CP0_TCBind;
754 755
}

756
target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
757 758
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
759
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
760

761 762
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCBind;
763
    else
764
        return other->tcs[other_tc].CP0_TCBind;
765 766
}

767
target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
768
{
769
    return env->active_tc.PC;
770 771
}

772
target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
773 774
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
775
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
776

777 778
    if (other_tc == other->current_tc)
        return other->active_tc.PC;
779
    else
780
        return other->tcs[other_tc].PC;
781 782
}

783
target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
784
{
785
    return env->active_tc.CP0_TCHalt;
786 787
}

788
target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
789 790
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
791
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
792

793 794
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCHalt;
795
    else
796
        return other->tcs[other_tc].CP0_TCHalt;
797 798
}

799
target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
800
{
801
    return env->active_tc.CP0_TCContext;
802 803
}

804
target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
805 806
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
807
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
808

809 810
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCContext;
811
    else
812
        return other->tcs[other_tc].CP0_TCContext;
813 814
}

815
target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
816
{
817
    return env->active_tc.CP0_TCSchedule;
818 819
}

820
target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
821 822
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
823
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
824

825 826
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCSchedule;
827
    else
828
        return other->tcs[other_tc].CP0_TCSchedule;
829 830
}

831
target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
832
{
833
    return env->active_tc.CP0_TCScheFBack;
834 835
}

836
target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
837 838
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
839
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
840

841 842
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCScheFBack;
843
    else
844
        return other->tcs[other_tc].CP0_TCScheFBack;
845 846
}

847
target_ulong helper_mfc0_count(CPUMIPSState *env)
848
{
849
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
850 851
}

852
target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
853 854
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
855
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
856

857
    return other->CP0_EntryHi;
858 859
}

860
target_ulong helper_mftc0_cause(CPUMIPSState *env)
861 862 863
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    int32_t tccause;
864
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
865 866 867 868 869 870 871 872 873 874

    if (other_tc == other->current_tc) {
        tccause = other->CP0_Cause;
    } else {
        tccause = other->CP0_Cause;
    }

    return tccause;
}

875
target_ulong helper_mftc0_status(CPUMIPSState *env)
876 877
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
878
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
879

880
    return other->CP0_Status;
881 882
}

883
target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
884
{
885
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
886 887
}

888
target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
889
{
890
    return (int32_t)env->CP0_WatchLo[sel];
891 892
}

893
target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
894
{
895
    return env->CP0_WatchHi[sel];
896 897
}

898
target_ulong helper_mfc0_debug(CPUMIPSState *env)
899
{
900
    target_ulong t0 = env->CP0_Debug;
901
    if (env->hflags & MIPS_HFLAG_DM)
902 903 904
        t0 |= 1 << CP0DB_DM;

    return t0;
905 906
}

907
target_ulong helper_mftc0_debug(CPUMIPSState *env)
908 909
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
910
    int32_t tcstatus;
911
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
912

913 914
    if (other_tc == other->current_tc)
        tcstatus = other->active_tc.CP0_Debug_tcstatus;
915
    else
916
        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
917 918

    /* XXX: Might be wrong, check with EJTAG spec. */
919
    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
920
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
921 922 923
}

#if defined(TARGET_MIPS64)
924
target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
925
{
926
    return env->active_tc.PC;
927 928
}

929
target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
930
{
931
    return env->active_tc.CP0_TCHalt;
932 933
}

934
target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
935
{
936
    return env->active_tc.CP0_TCContext;
937 938
}

939
target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
940
{
941
    return env->active_tc.CP0_TCSchedule;
942 943
}

944
target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
945
{
946
    return env->active_tc.CP0_TCScheFBack;
947 948
}

949
target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
950
{
951
    return env->lladdr >> env->CP0_LLAddr_shift;
952 953
}

954
target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
955
{
956
    return env->CP0_WatchLo[sel];
957 958 959
}
#endif /* TARGET_MIPS64 */

960
void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
961 962 963 964 965 966 967 968
{
    int num = 1;
    unsigned int tmp = env->tlb->nb_tlb;

    do {
        tmp >>= 1;
        num <<= 1;
    } while (tmp);
969
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
970 971
}

972
void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
973 974 975 976 977 978 979 980 981
{
    uint32_t mask = 0;
    uint32_t newval;

    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
                (1 << CP0MVPCo_EVP);
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0MVPCo_STLB);
982
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
983 984 985 986 987 988

    // TODO: Enable/disable shared TLB, enable/disable VPEs.

    env->mvp->CP0_MVPControl = newval;
}

989
void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
990 991 992 993 994 995
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
996
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
997 998 999 1000 1001 1002 1003 1004 1005

    /* Yield scheduler intercept not implemented. */
    /* Gating storage scheduler intercept not implemented. */

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

1006
void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1007 1008
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1009
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
    newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);

    /* TODO: Enable/disable TCs.  */

    other->CP0_VPEControl = newval;
}

1022
target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
1023 1024
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1025
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1026 1027 1028 1029
    /* FIXME: Mask away return zero on read bits.  */
    return other->CP0_VPEControl;
}

1030
target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1031 1032
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1033
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1034 1035 1036 1037

    return other->CP0_VPEConf0;
}

1038
void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1039 1040 1041 1042 1043 1044 1045 1046 1047
{
    uint32_t mask = 0;
    uint32_t newval;

    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
            mask |= (0xff << CP0VPEC0_XTC);
        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
    }
1048
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1049 1050 1051 1052 1053 1054

    // TODO: TC exclusive handling due to ERL/EXL.

    env->CP0_VPEConf0 = newval;
}

1055
void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1056 1057
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1058
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
    uint32_t mask = 0;
    uint32_t newval;

    mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
    newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);

    /* TODO: TC exclusive handling due to ERL/EXL.  */
    other->CP0_VPEConf0 = newval;
}

1069
void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1070 1071 1072 1073 1074 1075 1076
{
    uint32_t mask = 0;
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
                (0xff << CP0VPEC1_NCP1);
1077
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1078 1079 1080 1081 1082 1083 1084 1085 1086

    /* UDI not implemented. */
    /* CP2 not implemented. */

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

1087
void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1088 1089 1090 1091 1092
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

1093
void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1094
{
1095
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1096 1097
}

1098
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1099 1100 1101
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1102 1103
    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
    env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
1104 1105
}

1106 1107 1108 1109 1110 1111 1112 1113
#if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
{
    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
    env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi;
}
#endif

1114
void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1115 1116 1117 1118
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

1119
    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1120

1121
    env->active_tc.CP0_TCStatus = newval;
1122
    sync_c0_tcstatus(env, env->current_tc, newval);
1123 1124
}

1125
void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1126 1127
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1128
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1129

1130 1131
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCStatus = arg1;
1132
    else
1133
        other->tcs[other_tc].CP0_TCStatus = arg1;
1134
    sync_c0_tcstatus(other, other_tc, arg1);
1135 1136
}

1137
void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1138 1139 1140 1141 1142 1143
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
1144
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1145
    env->active_tc.CP0_TCBind = newval;
1146 1147
}

1148
void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1149 1150 1151 1152
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;
1153
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1154

1155
    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1156
        mask |= (1 << CP0TCBd_CurVPE);
1157 1158 1159
    if (other_tc == other->current_tc) {
        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
        other->active_tc.CP0_TCBind = newval;
1160
    } else {
1161 1162
        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
        other->tcs[other_tc].CP0_TCBind = newval;
1163
    }
1164 1165
}

1166
void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1167
{
1168
    env->active_tc.PC = arg1;
1169
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1170
    env->lladdr = 0ULL;
1171 1172 1173
    /* MIPS16 not implemented. */
}

1174
void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1175 1176
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1177
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1178

1179 1180 1181 1182
    if (other_tc == other->current_tc) {
        other->active_tc.PC = arg1;
        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1183 1184
        /* MIPS16 not implemented. */
    } else {
1185 1186 1187
        other->tcs[other_tc].PC = arg1;
        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1188 1189
        /* MIPS16 not implemented. */
    }
1190 1191
}

1192
void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1193
{
1194 1195
    MIPSCPU *cpu = mips_env_get_cpu(env);

1196
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1197 1198

    // TODO: Halt TC / Restart (if allocated+active) TC.
1199
    if (env->active_tc.CP0_TCHalt & 1) {
1200
        mips_tc_sleep(cpu, env->current_tc);
1201
    } else {
1202
        mips_tc_wake(cpu, env->current_tc);
1203
    }
1204 1205
}

1206
void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1207 1208
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1209
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1210
    MIPSCPU *other_cpu = mips_env_get_cpu(other);
1211 1212 1213

    // TODO: Halt TC / Restart (if allocated+active) TC.

1214 1215
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCHalt = arg1;
1216
    else
1217
        other->tcs[other_tc].CP0_TCHalt = arg1;
1218 1219

    if (arg1 & 1) {
1220
        mips_tc_sleep(other_cpu, other_tc);
1221
    } else {
1222
        mips_tc_wake(other_cpu, other_tc);
1223
    }
1224 1225
}

1226
void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1227
{
1228
    env->active_tc.CP0_TCContext = arg1;
1229 1230
}

1231
void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1232 1233
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1234
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1235

1236 1237
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCContext = arg1;
1238
    else
1239
        other->tcs[other_tc].CP0_TCContext = arg1;
1240 1241
}

1242
void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1243
{
1244
    env->active_tc.CP0_TCSchedule = arg1;
1245 1246
}

1247
void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1248 1249
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1250
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1251

1252 1253
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCSchedule = arg1;
1254
    else
1255
        other->tcs[other_tc].CP0_TCSchedule = arg1;
1256 1257
}

1258
void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1259
{
1260
    env->active_tc.CP0_TCScheFBack = arg1;
1261 1262
}

1263
void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1264 1265
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1266
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1267

1268 1269
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCScheFBack = arg1;
1270
    else
1271
        other->tcs[other_tc].CP0_TCScheFBack = arg1;
1272 1273
}

1274
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1275 1276 1277
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1278 1279
    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
    env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
1280 1281
}

1282 1283 1284 1285 1286 1287 1288 1289
#if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
{
    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
    env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi;
}
#endif

1290
void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1291
{
1292
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1293 1294
}

1295
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1296 1297
{
    /* 1k pages not implemented */
1298
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1299 1300
}

1301
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1302 1303 1304 1305
{
    /* SmartMIPS not implemented */
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1306 1307
    env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
                         (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
1308 1309
}

1310
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1311
{
1312
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1313 1314
}

1315
void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1316
{
1317
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1318 1319
}

1320
void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1321
{
1322
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1323 1324
}

1325
void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1326
{
1327
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1328 1329
}

1330
void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1331
{
1332
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1333 1334
}

1335
void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1336
{
1337
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1338 1339
}

1340
void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1341
{
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
    uint32_t mask = 0x0000000F;

    if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
        mask |= (1 << 29);

        if (arg1 & (1 << 29)) {
            env->hflags |= MIPS_HFLAG_HWRENA_ULR;
        } else {
            env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
        }
    }

    env->CP0_HWREna = arg1 & mask;
1355 1356
}

1357
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1358
{
1359
    cpu_mips_store_count(env, arg1);
1360 1361
}

1362
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1363
{
L
Leon Alrae 已提交
1364 1365 1366 1367 1368
    target_ulong old, val, mask;
    mask = (TARGET_PAGE_MASK << 1) | 0xFF;
    if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
        mask |= 1 << CP0EnHi_EHINV;
    }
1369 1370

    /* 1k pages not implemented */
L
Leon Alrae 已提交
1371
    val = arg1 & mask;
1372 1373 1374 1375 1376 1377
#if defined(TARGET_MIPS64)
    val &= env->SEGMask;
#endif
    old = env->CP0_EntryHi;
    env->CP0_EntryHi = val;
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1378
        sync_c0_entryhi(env, env->current_tc);
1379 1380 1381 1382 1383 1384
    }
    /* If the ASID changes, flush qemu's TLB.  */
    if ((old & 0xFF) != (val & 0xFF))
        cpu_mips_tlb_flush(env, 1);
}

1385
void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1386 1387
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1388
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1389

1390 1391
    other->CP0_EntryHi = arg1;
    sync_c0_entryhi(other, other_tc);
1392 1393
}

1394
void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1395
{
1396
    cpu_mips_store_compare(env, arg1);
1397 1398
}

1399
void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1400
{
1401
    MIPSCPU *cpu = mips_env_get_cpu(env);
1402 1403 1404
    uint32_t val, old;
    uint32_t mask = env->CP0_Status_rw_bitmask;

1405
    val = arg1 & mask;
1406 1407
    old = env->CP0_Status;
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1408
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1409
        sync_c0_status(env, env, env->current_tc);
1410 1411 1412 1413
    } else {
        compute_hflags(env);
    }

1414 1415 1416 1417 1418 1419 1420 1421 1422
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
                old, old & env->CP0_Cause & CP0Ca_IP_mask,
                val, val & env->CP0_Cause & CP0Ca_IP_mask,
                env->CP0_Cause);
        switch (env->hflags & MIPS_HFLAG_KSU) {
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1423 1424 1425
        default:
            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
            break;
A
Aurelien Jarno 已提交
1426
        }
1427
    }
1428 1429
}

1430
void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1431 1432
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1433
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1434

1435
    other->CP0_Status = arg1 & ~0xf1000018;
1436
    sync_c0_status(env, other, other_tc);
1437 1438
}

1439
void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1440 1441
{
    /* vectored interrupts not implemented, no performance counters. */
1442
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1443 1444
}

1445
void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1446 1447
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1448
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1449 1450
}

1451
static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
1452 1453
{
    uint32_t mask = 0x00C00300;
1454
    uint32_t old = cpu->CP0_Cause;
1455
    int i;
1456

1457
    if (cpu->insn_flags & ISA_MIPS32R2) {
1458
        mask |= 1 << CP0Ca_DC;
1459
    }
1460

1461
    cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
1462

1463 1464 1465 1466 1467 1468
    if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
        if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
            cpu_mips_stop_count(cpu);
        } else {
            cpu_mips_start_count(cpu);
        }
1469
    }
1470 1471 1472

    /* Set/reset software interrupts */
    for (i = 0 ; i < 2 ; i++) {
1473 1474
        if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
            cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
1475 1476
        }
    }
1477 1478
}

1479
void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1480 1481 1482 1483
{
    mtc0_cause(env, arg1);
}

1484
void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1485 1486
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1487
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1488 1489 1490 1491

    mtc0_cause(other, arg1);
}

1492
target_ulong helper_mftc0_epc(CPUMIPSState *env)
1493 1494
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1495
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1496 1497 1498 1499

    return other->CP0_EPC;
}

1500
target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1501 1502
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1503
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1504 1505 1506 1507

    return other->CP0_EBase;
}

1508
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1509 1510
{
    /* vectored interrupts not implemented */
1511
    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1512 1513
}

1514
void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1515 1516
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1517
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1518 1519 1520
    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}

1521
target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1522 1523
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1524
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539

    switch (idx) {
    case 0: return other->CP0_Config0;
    case 1: return other->CP0_Config1;
    case 2: return other->CP0_Config2;
    case 3: return other->CP0_Config3;
    /* 4 and 5 are reserved.  */
    case 6: return other->CP0_Config6;
    case 7: return other->CP0_Config7;
    default:
        break;
    }
    return 0;
}

1540
void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1541
{
1542
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1543 1544
}

1545
void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1546 1547 1548 1549 1550
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1551 1552 1553 1554 1555 1556
void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
{
    env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
                       (arg1 & env->CP0_Config4_rw_bitmask);
}

1557 1558 1559 1560 1561 1562
void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
{
    env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
                       (arg1 & env->CP0_Config5_rw_bitmask);
}

1563
void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1564 1565 1566 1567 1568 1569
{
    target_long mask = env->CP0_LLAddr_rw_bitmask;
    arg1 = arg1 << env->CP0_LLAddr_shift;
    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
}

1570
void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1571 1572 1573
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1574
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1575 1576
}

1577
void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1578
{
1579 1580
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1581 1582
}

1583
void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1584 1585
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1586
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1587 1588
}

1589
void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1590
{
1591
    env->CP0_Framemask = arg1; /* XXX */
1592 1593
}

1594
void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1595
{
1596 1597
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1598 1599 1600 1601 1602
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1603
void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1604 1605
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1606
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1607
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1608 1609

    /* XXX: Might be wrong, check with EJTAG spec. */
1610 1611
    if (other_tc == other->current_tc)
        other->active_tc.CP0_Debug_tcstatus = val;
1612
    else
1613 1614 1615
        other->tcs[other_tc].CP0_Debug_tcstatus = val;
    other->CP0_Debug = (other->CP0_Debug &
                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1616
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1617 1618
}

1619
void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1620
{
1621
    env->CP0_Performance0 = arg1 & 0x000007ff;
1622 1623
}

1624
void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1625
{
1626
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1627 1628
}

1629
void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1630
{
1631
    env->CP0_DataLo = arg1; /* XXX */
1632 1633
}

1634
void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1635
{
1636
    env->CP0_TagHi = arg1; /* XXX */
1637 1638
}

1639
void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1640
{
1641
    env->CP0_DataHi = arg1; /* XXX */
1642 1643 1644
}

/* MIPS MT functions */
1645
target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1646 1647
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1648
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1649

1650 1651
    if (other_tc == other->current_tc)
        return other->active_tc.gpr[sel];
1652
    else
1653
        return other->tcs[other_tc].gpr[sel];
1654 1655
}

1656
target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1657 1658
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1659
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1660

1661 1662
    if (other_tc == other->current_tc)
        return other->active_tc.LO[sel];
1663
    else
1664
        return other->tcs[other_tc].LO[sel];
1665 1666
}

1667
target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1668 1669
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1670
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1671

1672 1673
    if (other_tc == other->current_tc)
        return other->active_tc.HI[sel];
1674
    else
1675
        return other->tcs[other_tc].HI[sel];
1676 1677
}

1678
target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1679 1680
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1681
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1682

1683 1684
    if (other_tc == other->current_tc)
        return other->active_tc.ACX[sel];
1685
    else
1686
        return other->tcs[other_tc].ACX[sel];
1687 1688
}

1689
target_ulong helper_mftdsp(CPUMIPSState *env)
1690 1691
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1692
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1693

1694 1695
    if (other_tc == other->current_tc)
        return other->active_tc.DSPControl;
1696
    else
1697
        return other->tcs[other_tc].DSPControl;
1698
}
B
bellard 已提交
1699

1700
void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1701 1702
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1703
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1704

1705 1706
    if (other_tc == other->current_tc)
        other->active_tc.gpr[sel] = arg1;
1707
    else
1708
        other->tcs[other_tc].gpr[sel] = arg1;
1709 1710
}

1711
void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1712 1713
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1714
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1715

1716 1717
    if (other_tc == other->current_tc)
        other->active_tc.LO[sel] = arg1;
1718
    else
1719
        other->tcs[other_tc].LO[sel] = arg1;
1720 1721
}

1722
void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1723 1724
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1725
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1726

1727 1728
    if (other_tc == other->current_tc)
        other->active_tc.HI[sel] = arg1;
1729
    else
1730
        other->tcs[other_tc].HI[sel] = arg1;
1731 1732
}

1733
void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1734 1735
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1736
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1737

1738 1739
    if (other_tc == other->current_tc)
        other->active_tc.ACX[sel] = arg1;
1740
    else
1741
        other->tcs[other_tc].ACX[sel] = arg1;
1742 1743
}

1744
void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1745 1746
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1747
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1748

1749 1750
    if (other_tc == other->current_tc)
        other->active_tc.DSPControl = arg1;
1751
    else
1752
        other->tcs[other_tc].DSPControl = arg1;
1753 1754 1755
}

/* MIPS MT functions */
1756
target_ulong helper_dmt(void)
1757 1758
{
    // TODO
1759
     return 0;
1760 1761
}

1762
target_ulong helper_emt(void)
1763 1764
{
    // TODO
1765
    return 0;
1766 1767
}

1768
target_ulong helper_dvpe(CPUMIPSState *env)
1769
{
1770
    CPUState *other_cs = first_cpu;
1771 1772
    target_ulong prev = env->mvp->CP0_MVPControl;

A
Andreas Färber 已提交
1773
    CPU_FOREACH(other_cs) {
1774
        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1775
        /* Turn off all VPEs except the one executing the dvpe.  */
1776 1777
        if (&other_cpu->env != env) {
            other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1778
            mips_vpe_sleep(other_cpu);
1779
        }
A
Andreas Färber 已提交
1780
    }
1781
    return prev;
1782 1783
}

1784
target_ulong helper_evpe(CPUMIPSState *env)
1785
{
1786
    CPUState *other_cs = first_cpu;
1787 1788
    target_ulong prev = env->mvp->CP0_MVPControl;

A
Andreas Färber 已提交
1789
    CPU_FOREACH(other_cs) {
1790
        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1791

1792
        if (&other_cpu->env != env
1793
            /* If the VPE is WFI, don't disturb its sleep.  */
1794
            && !mips_vpe_is_wfi(other_cpu)) {
1795
            /* Enable the VPE.  */
1796
            other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1797
            mips_vpe_wake(other_cpu); /* And wake it up.  */
1798
        }
A
Andreas Färber 已提交
1799
    }
1800
    return prev;
1801
}
1802
#endif /* !CONFIG_USER_ONLY */
1803

1804
void helper_fork(target_ulong arg1, target_ulong arg2)
1805
{
1806
    // arg1 = rt, arg2 = rs
1807 1808 1809
    // TODO: store to TC register
}

1810
target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
1811
{
B
Blue Swirl 已提交
1812 1813
    target_long arg1 = arg;

1814
    if (arg1 < 0) {
1815
        /* No scheduling policy implemented. */
1816
        if (arg1 != -2) {
1817
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1818
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1819 1820
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1821
                helper_raise_exception(env, EXCP_THREAD);
1822 1823
            }
        }
1824
    } else if (arg1 == 0) {
A
aurel32 已提交
1825
        if (0 /* TODO: TC underflow */) {
1826
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1827
            helper_raise_exception(env, EXCP_THREAD);
1828 1829 1830
        } else {
            // TODO: Deallocate TC
        }
1831
    } else if (arg1 > 0) {
1832 1833 1834
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1835
        helper_raise_exception(env, EXCP_THREAD);
1836
    }
1837
    return env->CP0_YQMask;
1838 1839 1840
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1841
/* TLB management */
1842
static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1843
{
1844 1845
    MIPSCPU *cpu = mips_env_get_cpu(env);

1846
    /* Flush qemu's TLB and discard all shadowed entries.  */
1847
    tlb_flush(CPU(cpu), flush_global);
1848
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1849 1850
}

1851
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1852 1853
{
    /* Discard entries from env->tlb[first] onwards.  */
1854 1855
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1856 1857 1858
    }
}

1859
static void r4k_fill_tlb(CPUMIPSState *env, int idx)
B
bellard 已提交
1860
{
A
Anthony Liguori 已提交
1861
    r4k_tlb_t *tlb;
B
bellard 已提交
1862 1863

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1864
    tlb = &env->tlb->mmu.r4k.tlb[idx];
L
Leon Alrae 已提交
1865 1866 1867 1868 1869
    if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
        tlb->EHINV = 1;
        return;
    }
    tlb->EHINV = 0;
T
ths 已提交
1870
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1871
#if defined(TARGET_MIPS64)
T
ths 已提交
1872
    tlb->VPN &= env->SEGMask;
1873
#endif
1874
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
1875
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
1876
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1877 1878 1879
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1880 1881
    tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
    tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
B
bellard 已提交
1882
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1883 1884 1885
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1886 1887
    tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
    tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
B
bellard 已提交
1888 1889 1890
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}

L
Leon Alrae 已提交
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
void r4k_helper_tlbinv(CPUMIPSState *env)
{
    int idx;
    r4k_tlb_t *tlb;
    uint8_t ASID = env->CP0_EntryHi & 0xFF;

    for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
        tlb = &env->tlb->mmu.r4k.tlb[idx];
        if (!tlb->G && tlb->ASID == ASID) {
            tlb->EHINV = 1;
        }
    }
    cpu_mips_tlb_flush(env, 1);
}

void r4k_helper_tlbinvf(CPUMIPSState *env)
{
    int idx;

    for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
        env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
    }
    cpu_mips_tlb_flush(env, 1);
}

1916
void r4k_helper_tlbwi(CPUMIPSState *env)
B
bellard 已提交
1917
{
1918
    r4k_tlb_t *tlb;
A
aurel32 已提交
1919
    int idx;
1920 1921 1922
    target_ulong VPN;
    uint8_t ASID;
    bool G, V0, D0, V1, D1;
A
aurel32 已提交
1923 1924

    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943
    tlb = &env->tlb->mmu.r4k.tlb[idx];
    VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
#if defined(TARGET_MIPS64)
    VPN &= env->SEGMask;
#endif
    ASID = env->CP0_EntryHi & 0xff;
    G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
    V0 = (env->CP0_EntryLo0 & 2) != 0;
    D0 = (env->CP0_EntryLo0 & 4) != 0;
    V1 = (env->CP0_EntryLo1 & 2) != 0;
    D1 = (env->CP0_EntryLo1 & 4) != 0;

    /* Discard cached TLB entries, unless tlbwi is just upgrading access
       permissions on the current entry. */
    if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
        (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
        (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
        r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
    }
1944

A
aurel32 已提交
1945
    r4k_invalidate_tlb(env, idx, 0);
1946
    r4k_fill_tlb(env, idx);
B
bellard 已提交
1947 1948
}

1949
void r4k_helper_tlbwr(CPUMIPSState *env)
B
bellard 已提交
1950 1951 1952
{
    int r = cpu_mips_get_random(env);

1953
    r4k_invalidate_tlb(env, r, 1);
1954
    r4k_fill_tlb(env, r);
B
bellard 已提交
1955 1956
}

1957
void r4k_helper_tlbp(CPUMIPSState *env)
B
bellard 已提交
1958
{
A
Anthony Liguori 已提交
1959
    r4k_tlb_t *tlb;
T
ths 已提交
1960
    target_ulong mask;
B
bellard 已提交
1961
    target_ulong tag;
T
ths 已提交
1962
    target_ulong VPN;
B
bellard 已提交
1963 1964 1965
    uint8_t ASID;
    int i;

B
bellard 已提交
1966
    ASID = env->CP0_EntryHi & 0xFF;
1967 1968
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
1969 1970 1971 1972
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
A
Aurelien Jarno 已提交
1973 1974 1975
#if defined(TARGET_MIPS64)
        tag &= env->SEGMask;
#endif
B
bellard 已提交
1976
        /* Check ASID, virtual page number & size */
L
Leon Alrae 已提交
1977
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
B
bellard 已提交
1978
            /* TLB match */
T
ths 已提交
1979
            env->CP0_Index = i;
B
bellard 已提交
1980 1981 1982
            break;
        }
    }
1983
    if (i == env->tlb->nb_tlb) {
1984
        /* No match.  Discard any shadow entries, if any of them match.  */
1985
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
1986 1987 1988 1989 1990
            tlb = &env->tlb->mmu.r4k.tlb[i];
            /* 1k pages are not supported. */
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
            tag = env->CP0_EntryHi & ~mask;
            VPN = tlb->VPN & ~mask;
A
Aurelien Jarno 已提交
1991 1992 1993
#if defined(TARGET_MIPS64)
            tag &= env->SEGMask;
#endif
A
aurel32 已提交
1994 1995
            /* Check ASID, virtual page number & size */
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1996
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
1997 1998 1999
                break;
            }
        }
2000

T
ths 已提交
2001
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
2002 2003 2004
    }
}

2005
void r4k_helper_tlbr(CPUMIPSState *env)
B
bellard 已提交
2006
{
A
Anthony Liguori 已提交
2007
    r4k_tlb_t *tlb;
2008
    uint8_t ASID;
A
aurel32 已提交
2009
    int idx;
B
bellard 已提交
2010

2011
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
2012 2013
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
2014 2015

    /* If this will change the current ASID, flush qemu's TLB.  */
2016 2017 2018
    if (ASID != tlb->ASID)
        cpu_mips_tlb_flush (env, 1);

2019
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
2020

L
Leon Alrae 已提交
2021 2022 2023 2024 2025 2026 2027 2028 2029
    if (tlb->EHINV) {
        env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
        env->CP0_PageMask = 0;
        env->CP0_EntryLo0 = 0;
        env->CP0_EntryLo1 = 0;
    } else {
        env->CP0_EntryHi = tlb->VPN | tlb->ASID;
        env->CP0_PageMask = tlb->PageMask;
        env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2030 2031
                        ((target_ulong)tlb->RI0 << CP0EnLo_RI) |
                        ((target_ulong)tlb->XI0 << CP0EnLo_XI) |
T
ths 已提交
2032
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
L
Leon Alrae 已提交
2033
        env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2034 2035
                        ((target_ulong)tlb->RI1 << CP0EnLo_RI) |
                        ((target_ulong)tlb->XI1 << CP0EnLo_XI) |
T
ths 已提交
2036
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
L
Leon Alrae 已提交
2037
    }
B
bellard 已提交
2038 2039
}

2040
void helper_tlbwi(CPUMIPSState *env)
P
pbrook 已提交
2041
{
2042
    env->tlb->helper_tlbwi(env);
P
pbrook 已提交
2043 2044
}

2045
void helper_tlbwr(CPUMIPSState *env)
P
pbrook 已提交
2046
{
2047
    env->tlb->helper_tlbwr(env);
P
pbrook 已提交
2048 2049
}

2050
void helper_tlbp(CPUMIPSState *env)
P
pbrook 已提交
2051
{
2052
    env->tlb->helper_tlbp(env);
P
pbrook 已提交
2053 2054
}

2055
void helper_tlbr(CPUMIPSState *env)
P
pbrook 已提交
2056
{
2057
    env->tlb->helper_tlbr(env);
P
pbrook 已提交
2058 2059
}

L
Leon Alrae 已提交
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069
void helper_tlbinv(CPUMIPSState *env)
{
    env->tlb->helper_tlbinv(env);
}

void helper_tlbinvf(CPUMIPSState *env)
{
    env->tlb->helper_tlbinvf(env);
}

2070
/* Specials */
2071
target_ulong helper_di(CPUMIPSState *env)
2072
{
2073 2074
    target_ulong t0 = env->CP0_Status;

2075 2076
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
    return t0;
2077 2078
}

2079
target_ulong helper_ei(CPUMIPSState *env)
2080
{
2081 2082
    target_ulong t0 = env->CP0_Status;

2083 2084
    env->CP0_Status = t0 | (1 << CP0St_IE);
    return t0;
2085 2086
}

2087
static void debug_pre_eret(CPUMIPSState *env)
B
bellard 已提交
2088
{
2089
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2090 2091 2092 2093 2094 2095 2096 2097
        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
                env->active_tc.PC, env->CP0_EPC);
        if (env->CP0_Status & (1 << CP0St_ERL))
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
        if (env->hflags & MIPS_HFLAG_DM)
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
        qemu_log("\n");
    }
2098 2099
}

2100
static void debug_post_eret(CPUMIPSState *env)
2101
{
2102 2103
    MIPSCPU *cpu = mips_env_get_cpu(env);

2104
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
                env->active_tc.PC, env->CP0_EPC);
        if (env->CP0_Status & (1 << CP0St_ERL))
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
        if (env->hflags & MIPS_HFLAG_DM)
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
        switch (env->hflags & MIPS_HFLAG_KSU) {
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
2115 2116 2117
        default:
            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
            break;
2118
        }
T
ths 已提交
2119
    }
B
bellard 已提交
2120 2121
}

2122
static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2123 2124 2125 2126 2127 2128 2129 2130 2131
{
    env->active_tc.PC = error_pc & ~(target_ulong)1;
    if (error_pc & 1) {
        env->hflags |= MIPS_HFLAG_M16;
    } else {
        env->hflags &= ~(MIPS_HFLAG_M16);
    }
}

2132
void helper_eret(CPUMIPSState *env)
2133
{
2134
    debug_pre_eret(env);
2135
    if (env->CP0_Status & (1 << CP0St_ERL)) {
2136
        set_pc(env, env->CP0_ErrorEPC);
2137 2138
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
2139
        set_pc(env, env->CP0_EPC);
2140 2141 2142
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
2143
    debug_post_eret(env);
2144
    env->lladdr = 1;
2145 2146
}

2147
void helper_deret(CPUMIPSState *env)
2148
{
2149 2150
    debug_pre_eret(env);
    set_pc(env, env->CP0_DEPC);
2151

2152 2153
    env->hflags &= MIPS_HFLAG_DM;
    compute_hflags(env);
2154
    debug_post_eret(env);
2155
    env->lladdr = 1;
2156
}
T
ths 已提交
2157
#endif /* !CONFIG_USER_ONLY */
2158

2159
target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2160 2161 2162
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 0)))
2163
        return env->CP0_EBase & 0x3ff;
2164
    else
2165
        helper_raise_exception(env, EXCP_RI);
2166

2167
    return 0;
2168 2169
}

2170
target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2171 2172 2173
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 1)))
2174
        return env->SYNCI_Step;
2175
    else
2176
        helper_raise_exception(env, EXCP_RI);
2177

2178
    return 0;
2179 2180
}

2181
target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2182 2183 2184
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 2)))
2185
        return env->CP0_Count;
2186
    else
2187
        helper_raise_exception(env, EXCP_RI);
2188

2189
    return 0;
2190 2191
}

2192
target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2193 2194 2195
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 3)))
2196
        return env->CCRes;
2197
    else
2198
        helper_raise_exception(env, EXCP_RI);
2199

2200
    return 0;
2201 2202
}

2203
void helper_pmon(CPUMIPSState *env, int function)
B
bellard 已提交
2204 2205 2206 2207
{
    function /= 2;
    switch (function) {
    case 2: /* TODO: char inbyte(int waitflag); */
2208 2209
        if (env->active_tc.gpr[4] == 0)
            env->active_tc.gpr[2] = -1;
B
bellard 已提交
2210 2211
        /* Fall through */
    case 11: /* TODO: char inbyte (void); */
2212
        env->active_tc.gpr[2] = -1;
B
bellard 已提交
2213 2214 2215
        break;
    case 3:
    case 12:
2216
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
B
bellard 已提交
2217 2218 2219 2220 2221
        break;
    case 17:
        break;
    case 158:
        {
2222
            unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
B
bellard 已提交
2223 2224 2225 2226 2227
            printf("%s", fmt);
        }
        break;
    }
}
2228

2229
void helper_wait(CPUMIPSState *env)
T
ths 已提交
2230
{
2231 2232 2233
    CPUState *cs = CPU(mips_env_get_cpu(env));

    cs->halted = 1;
2234
    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2235
    helper_raise_exception(env, EXCP_HLT);
T
ths 已提交
2236 2237
}

2238
#if !defined(CONFIG_USER_ONLY)
2239

2240 2241
void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                  int is_write, int is_user, uintptr_t retaddr)
B
bellard 已提交
2242
{
2243 2244 2245
    MIPSCPU *cpu = MIPS_CPU(cs);
    CPUMIPSState *env = &cpu->env;

B
bellard 已提交
2246
    env->CP0_BadVAddr = addr;
2247
    do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
B
bellard 已提交
2248 2249
}

2250
void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2251
              uintptr_t retaddr)
2252 2253 2254
{
    int ret;

2255
    ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
2256
    if (ret) {
2257 2258 2259
        MIPSCPU *cpu = MIPS_CPU(cs);
        CPUMIPSState *env = &cpu->env;

2260
        do_raise_exception_err(env, cs->exception_index,
2261
                               env->error_code, retaddr);
2262 2263 2264
    }
}

2265 2266 2267
void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
                                bool is_write, bool is_exec, int unused,
                                unsigned size)
T
ths 已提交
2268
{
2269 2270 2271
    MIPSCPU *cpu = MIPS_CPU(cs);
    CPUMIPSState *env = &cpu->env;

2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
    /*
     * Raising an exception with KVM enabled will crash because it won't be from
     * the main execution loop so the longjmp won't have a matching setjmp.
     * Until we can trigger a bus error exception through KVM lets just ignore
     * the access.
     */
    if (kvm_enabled()) {
        return;
    }

2282
    if (is_exec) {
2283
        helper_raise_exception(env, EXCP_IBE);
2284
    } else {
2285
        helper_raise_exception(env, EXCP_DBE);
2286
    }
T
ths 已提交
2287
}
2288
#endif /* !CONFIG_USER_ONLY */
2289 2290 2291

/* Complex FPU operations which may need stack space. */

P
pbrook 已提交
2292 2293
#define FLOAT_TWO32 make_float32(1 << 30)
#define FLOAT_TWO64 make_float64(1ULL << 62)
2294 2295
#define FP_TO_INT32_OVERFLOW 0x7fffffff
#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
T
ths 已提交
2296

2297
/* convert MIPS rounding mode in FCR31 to IEEE library */
B
Blue Swirl 已提交
2298
static unsigned int ieee_rm[] = {
2299 2300 2301 2302 2303 2304
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

2305 2306 2307 2308 2309
static inline void restore_rounding_mode(CPUMIPSState *env)
{
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
                            &env->active_fpu.fp_status);
}
2310

2311 2312 2313 2314 2315
static inline void restore_flush_mode(CPUMIPSState *env)
{
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
                      &env->active_fpu.fp_status);
}
2316

2317
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2318
{
2319
    target_ulong arg1 = 0;
2320

2321 2322
    switch (reg) {
    case 0:
2323
        arg1 = (int32_t)env->active_fpu.fcr0;
2324
        break;
2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
    case 1:
        /* UFR Support - Read Status FR */
        if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
            if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
                arg1 = (int32_t)
                       ((env->CP0_Status & (1  << CP0St_FR)) >> CP0St_FR);
            } else {
                helper_raise_exception(env, EXCP_RI);
            }
        }
        break;
2336
    case 25:
2337
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2338 2339
        break;
    case 26:
2340
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2341 2342
        break;
    case 28:
2343
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2344 2345
        break;
    default:
2346
        arg1 = (int32_t)env->active_fpu.fcr31;
2347 2348
        break;
    }
2349

2350
    return arg1;
2351 2352
}

2353
void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
2354
{
2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379
    switch (fs) {
    case 1:
        /* UFR Alias - Reset Status FR */
        if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
            return;
        }
        if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
            env->CP0_Status &= ~(1 << CP0St_FR);
            compute_hflags(env);
        } else {
            helper_raise_exception(env, EXCP_RI);
        }
        break;
    case 4:
        /* UNFR Alias - Set Status FR */
        if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
            return;
        }
        if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
            env->CP0_Status |= (1 << CP0St_FR);
            compute_hflags(env);
        } else {
            helper_raise_exception(env, EXCP_RI);
        }
        break;
2380
    case 25:
2381
        if (arg1 & 0xffffff00)
2382
            return;
2383 2384
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2385 2386
        break;
    case 26:
2387
        if (arg1 & 0x007c0000)
2388
            return;
2389
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2390 2391
        break;
    case 28:
2392
        if (arg1 & 0x007c0000)
2393
            return;
2394 2395
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2396 2397
        break;
    case 31:
2398
        if (arg1 & 0x007c0000)
2399
            return;
2400
        env->active_fpu.fcr31 = arg1;
2401 2402 2403 2404 2405
        break;
    default:
        return;
    }
    /* set rounding mode */
2406
    restore_rounding_mode(env);
2407
    /* set flush-to-zero mode */
2408
    restore_flush_mode(env);
2409 2410
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2411
        do_raise_exception(env, EXCP_FPE, GETPC());
2412 2413
}

2414
static inline int ieee_ex_to_mips(int xcpt)
2415
{
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
    int ret = 0;
    if (xcpt) {
        if (xcpt & float_flag_invalid) {
            ret |= FP_INVALID;
        }
        if (xcpt & float_flag_overflow) {
            ret |= FP_OVERFLOW;
        }
        if (xcpt & float_flag_underflow) {
            ret |= FP_UNDERFLOW;
        }
        if (xcpt & float_flag_divbyzero) {
            ret |= FP_DIV0;
        }
        if (xcpt & float_flag_inexact) {
            ret |= FP_INEXACT;
        }
    }
    return ret;
2435 2436
}

2437
static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2438
{
2439
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2440

2441
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2442 2443 2444 2445 2446

    if (tmp) {
        set_float_exception_flags(0, &env->active_fpu.fp_status);

        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2447
            do_raise_exception(env, EXCP_FPE, pc);
2448 2449 2450 2451
        } else {
            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
        }
    }
2452 2453
}

2454 2455 2456 2457 2458 2459
/* Float support.
   Single precition routines have a "s" suffix, double precision a
   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
   paired single lower "pl", paired single upper "pu".  */

/* unary operations, modifying fp status  */
2460
uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2461
{
A
Aurelien Jarno 已提交
2462
    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2463
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2464
    return fdt0;
2465 2466
}

2467
uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2468
{
A
Aurelien Jarno 已提交
2469
    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2470
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2471
    return fst0;
2472
}
2473

2474
uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2475
{
2476 2477
    uint64_t fdt2;

2478
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2479
    update_fcr31(env, GETPC());
2480
    return fdt2;
2481
}
2482

2483
uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2484
{
2485 2486
    uint64_t fdt2;

2487
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2488
    update_fcr31(env, GETPC());
2489
    return fdt2;
2490
}
2491

2492
uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2493
{
2494 2495
    uint64_t fdt2;

2496
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2497
    update_fcr31(env, GETPC());
2498
    return fdt2;
2499
}
2500

2501
uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
2502
{
2503 2504
    uint64_t dt2;

2505
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2506 2507
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2508
        dt2 = FP_TO_INT64_OVERFLOW;
2509
    }
2510
    update_fcr31(env, GETPC());
2511
    return dt2;
2512
}
2513

2514
uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
2515
{
2516 2517
    uint64_t dt2;

2518
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2519 2520
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2521
        dt2 = FP_TO_INT64_OVERFLOW;
2522
    }
2523
    update_fcr31(env, GETPC());
2524
    return dt2;
2525 2526
}

2527
uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2528
{
2529 2530 2531
    uint32_t fst2;
    uint32_t fsth2;

2532 2533
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2534
    update_fcr31(env, GETPC());
2535
    return ((uint64_t)fsth2 << 32) | fst2;
2536
}
2537

2538
uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2539
{
2540 2541
    uint32_t wt2;
    uint32_t wth2;
A
Aurelien Jarno 已提交
2542
    int excp, excph;
2543

2544
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
A
Aurelien Jarno 已提交
2545 2546
    excp = get_float_exception_flags(&env->active_fpu.fp_status);
    if (excp & (float_flag_overflow | float_flag_invalid)) {
2547
        wt2 = FP_TO_INT32_OVERFLOW;
A
Aurelien Jarno 已提交
2548 2549 2550 2551 2552 2553
    }

    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
    excph = get_float_exception_flags(&env->active_fpu.fp_status);
    if (excph & (float_flag_overflow | float_flag_invalid)) {
2554
        wth2 = FP_TO_INT32_OVERFLOW;
2555
    }
A
Aurelien Jarno 已提交
2556 2557

    set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
2558
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2559

2560
    return ((uint64_t)wth2 << 32) | wt2;
2561
}
2562

2563
uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2564
{
2565 2566
    uint32_t fst2;

2567
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2568
    update_fcr31(env, GETPC());
2569
    return fst2;
2570
}
2571

2572
uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2573
{
2574 2575
    uint32_t fst2;

2576
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2577
    update_fcr31(env, GETPC());
2578
    return fst2;
2579
}
2580

2581
uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2582
{
2583 2584
    uint32_t fst2;

2585
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2586
    update_fcr31(env, GETPC());
2587
    return fst2;
2588
}
2589

2590
uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2591
{
2592 2593 2594
    uint32_t wt2;

    wt2 = wt0;
2595
    update_fcr31(env, GETPC());
2596
    return wt2;
2597
}
2598

2599
uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2600
{
2601 2602 2603
    uint32_t wt2;

    wt2 = wth0;
2604
    update_fcr31(env, GETPC());
2605
    return wt2;
2606
}
2607

2608
uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
2609
{
2610 2611
    uint32_t wt2;

2612
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2613
    update_fcr31(env, GETPC());
2614 2615
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2616
        wt2 = FP_TO_INT32_OVERFLOW;
2617
    }
2618
    return wt2;
2619
}
2620

2621
uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
2622
{
2623 2624
    uint32_t wt2;

2625
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2626 2627
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2628
        wt2 = FP_TO_INT32_OVERFLOW;
2629
    }
2630
    update_fcr31(env, GETPC());
2631
    return wt2;
2632 2633
}

2634
uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
2635
{
2636 2637
    uint64_t dt2;

2638 2639
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2640
    restore_rounding_mode(env);
2641 2642
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2643
        dt2 = FP_TO_INT64_OVERFLOW;
2644
    }
2645
    update_fcr31(env, GETPC());
2646
    return dt2;
2647
}
2648

2649
uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
2650
{
2651 2652
    uint64_t dt2;

2653 2654
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2655
    restore_rounding_mode(env);
2656 2657
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2658
        dt2 = FP_TO_INT64_OVERFLOW;
2659
    }
2660
    update_fcr31(env, GETPC());
2661
    return dt2;
2662
}
2663

2664
uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
2665
{
2666 2667
    uint32_t wt2;

2668 2669
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2670
    restore_rounding_mode(env);
2671 2672
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2673
        wt2 = FP_TO_INT32_OVERFLOW;
2674
    }
2675
    update_fcr31(env, GETPC());
2676
    return wt2;
2677
}
2678

2679
uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
2680
{
2681 2682
    uint32_t wt2;

2683 2684
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2685
    restore_rounding_mode(env);
2686 2687
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2688
        wt2 = FP_TO_INT32_OVERFLOW;
2689
    }
2690
    update_fcr31(env, GETPC());
2691
    return wt2;
2692 2693
}

2694
uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
2695
{
2696 2697
    uint64_t dt2;

2698
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2699 2700
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2701
        dt2 = FP_TO_INT64_OVERFLOW;
2702
    }
2703
    update_fcr31(env, GETPC());
2704
    return dt2;
2705
}
2706

2707
uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
2708
{
2709 2710
    uint64_t dt2;

2711
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2712 2713
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2714
        dt2 = FP_TO_INT64_OVERFLOW;
2715
    }
2716
    update_fcr31(env, GETPC());
2717
    return dt2;
2718
}
2719

2720
uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
2721
{
2722 2723
    uint32_t wt2;

2724
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2725 2726
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2727
        wt2 = FP_TO_INT32_OVERFLOW;
2728
    }
2729
    update_fcr31(env, GETPC());
2730
    return wt2;
2731
}
2732

2733
uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
2734
{
2735 2736
    uint32_t wt2;

2737
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2738 2739
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2740
        wt2 = FP_TO_INT32_OVERFLOW;
2741
    }
2742
    update_fcr31(env, GETPC());
2743
    return wt2;
2744 2745
}

2746
uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
2747
{
2748 2749
    uint64_t dt2;

2750 2751
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2752
    restore_rounding_mode(env);
2753 2754
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2755
        dt2 = FP_TO_INT64_OVERFLOW;
2756
    }
2757
    update_fcr31(env, GETPC());
2758
    return dt2;
2759
}
2760

2761
uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
2762
{
2763 2764
    uint64_t dt2;

2765 2766
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2767
    restore_rounding_mode(env);
2768 2769
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2770
        dt2 = FP_TO_INT64_OVERFLOW;
2771
    }
2772
    update_fcr31(env, GETPC());
2773
    return dt2;
2774
}
2775

2776
uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
2777
{
2778 2779
    uint32_t wt2;

2780 2781
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2782
    restore_rounding_mode(env);
2783 2784
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2785
        wt2 = FP_TO_INT32_OVERFLOW;
2786
    }
2787
    update_fcr31(env, GETPC());
2788
    return wt2;
2789
}
2790

2791
uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
2792
{
2793 2794
    uint32_t wt2;

2795 2796
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2797
    restore_rounding_mode(env);
2798 2799
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2800
        wt2 = FP_TO_INT32_OVERFLOW;
2801
    }
2802
    update_fcr31(env, GETPC());
2803
    return wt2;
2804 2805
}

2806
uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
2807
{
2808 2809
    uint64_t dt2;

2810 2811
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2812
    restore_rounding_mode(env);
2813 2814
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2815
        dt2 = FP_TO_INT64_OVERFLOW;
2816
    }
2817
    update_fcr31(env, GETPC());
2818
    return dt2;
2819
}
2820

2821
uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
2822
{
2823 2824
    uint64_t dt2;

2825 2826
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2827
    restore_rounding_mode(env);
2828 2829
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2830
        dt2 = FP_TO_INT64_OVERFLOW;
2831
    }
2832
    update_fcr31(env, GETPC());
2833
    return dt2;
2834
}
2835

2836
uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
2837
{
2838 2839
    uint32_t wt2;

2840 2841
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2842
    restore_rounding_mode(env);
2843 2844
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2845
        wt2 = FP_TO_INT32_OVERFLOW;
2846
    }
2847
    update_fcr31(env, GETPC());
2848
    return wt2;
2849
}
2850

2851
uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
2852
{
2853 2854
    uint32_t wt2;

2855 2856
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2857
    restore_rounding_mode(env);
2858 2859
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2860
        wt2 = FP_TO_INT32_OVERFLOW;
2861
    }
2862
    update_fcr31(env, GETPC());
2863
    return wt2;
2864 2865
}

2866
/* unary operations, not modifying fp status  */
2867
#define FLOAT_UNOP(name)                                       \
2868
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2869 2870 2871
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2872
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2873 2874 2875
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2876
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2877 2878 2879 2880 2881 2882 2883
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2884 2885 2886 2887 2888
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992
#define FLOAT_FMADDSUB(name, bits, muladd_arg)                          \
uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
                                          uint ## bits ## _t fs,        \
                                          uint ## bits ## _t ft,        \
                                          uint ## bits ## _t fd)        \
{                                                                       \
    uint ## bits ## _t fdret;                                           \
                                                                        \
    fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg,            \
                                     &env->active_fpu.fp_status);       \
    update_fcr31(env, GETPC());                                         \
    return fdret;                                                       \
}

FLOAT_FMADDSUB(maddf_s, 32, 0)
FLOAT_FMADDSUB(maddf_d, 64, 0)
FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
#undef FLOAT_FMADDSUB

#define FLOAT_MINMAX(name, bits, minmaxfunc)                            \
uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
                                          uint ## bits ## _t fs,        \
                                          uint ## bits ## _t ft)        \
{                                                                       \
    uint ## bits ## _t fdret;                                           \
                                                                        \
    fdret = float ## bits ## _ ## minmaxfunc(fs, ft,                    \
                                           &env->active_fpu.fp_status); \
    update_fcr31(env, GETPC());                                         \
    return fdret;                                                       \
}

FLOAT_MINMAX(max_s, 32, maxnum)
FLOAT_MINMAX(max_d, 64, maxnum)
FLOAT_MINMAX(maxa_s, 32, maxnummag)
FLOAT_MINMAX(maxa_d, 64, maxnummag)

FLOAT_MINMAX(min_s, 32, minnum)
FLOAT_MINMAX(min_d, 64, minnum)
FLOAT_MINMAX(mina_s, 32, minnummag)
FLOAT_MINMAX(mina_d, 64, minnummag)
#undef FLOAT_MINMAX

#define FLOAT_RINT(name, bits)                                              \
uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,                \
                                          uint ## bits ## _t fs)            \
{                                                                           \
    uint ## bits ## _t fdret;                                               \
                                                                            \
    fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
    update_fcr31(env, GETPC());                                             \
    return fdret;                                                           \
}

FLOAT_RINT(rint_s, 32)
FLOAT_RINT(rint_d, 64)
#undef FLOAT_RINT

#define FLOAT_CLASS_SIGNALING_NAN      0x001
#define FLOAT_CLASS_QUIET_NAN          0x002
#define FLOAT_CLASS_NEGATIVE_INFINITY  0x004
#define FLOAT_CLASS_NEGATIVE_NORMAL    0x008
#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
#define FLOAT_CLASS_NEGATIVE_ZERO      0x020
#define FLOAT_CLASS_POSITIVE_INFINITY  0x040
#define FLOAT_CLASS_POSITIVE_NORMAL    0x080
#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
#define FLOAT_CLASS_POSITIVE_ZERO      0x200

#define FLOAT_CLASS(name, bits)                                      \
uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg)    \
{                                                                    \
    if (float ## bits ## _is_signaling_nan(arg)) {                   \
        return FLOAT_CLASS_SIGNALING_NAN;                            \
    } else if (float ## bits ## _is_quiet_nan(arg)) {                \
        return FLOAT_CLASS_QUIET_NAN;                                \
    } else if (float ## bits ## _is_neg(arg)) {                      \
        if (float ## bits ## _is_infinity(arg)) {                    \
            return FLOAT_CLASS_NEGATIVE_INFINITY;                    \
        } else if (float ## bits ## _is_zero(arg)) {                 \
            return FLOAT_CLASS_NEGATIVE_ZERO;                        \
        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
            return FLOAT_CLASS_NEGATIVE_SUBNORMAL;                   \
        } else {                                                     \
            return FLOAT_CLASS_NEGATIVE_NORMAL;                      \
        }                                                            \
    } else {                                                         \
        if (float ## bits ## _is_infinity(arg)) {                    \
            return FLOAT_CLASS_POSITIVE_INFINITY;                    \
        } else if (float ## bits ## _is_zero(arg)) {                 \
            return FLOAT_CLASS_POSITIVE_ZERO;                        \
        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
            return FLOAT_CLASS_POSITIVE_SUBNORMAL;                   \
        } else {                                                     \
            return FLOAT_CLASS_POSITIVE_NORMAL;                      \
        }                                                            \
    }                                                                \
}

FLOAT_CLASS(class_s, 32)
FLOAT_CLASS(class_d, 64)
#undef FLOAT_CLASS

T
ths 已提交
2993
/* MIPS specific unary operations */
2994
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2995
{
2996 2997
    uint64_t fdt2;

2998
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
2999
    update_fcr31(env, GETPC());
3000
    return fdt2;
T
ths 已提交
3001
}
3002

3003
uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3004
{
3005 3006
    uint32_t fst2;

3007
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3008
    update_fcr31(env, GETPC());
3009
    return fst2;
T
ths 已提交
3010 3011
}

3012
uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3013
{
3014 3015
    uint64_t fdt2;

3016
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3017
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3018
    update_fcr31(env, GETPC());
3019
    return fdt2;
T
ths 已提交
3020
}
3021

3022
uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3023
{
3024 3025
    uint32_t fst2;

3026
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3027
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3028
    update_fcr31(env, GETPC());
3029
    return fst2;
T
ths 已提交
3030 3031
}

3032
uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3033
{
3034 3035
    uint64_t fdt2;

3036
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3037
    update_fcr31(env, GETPC());
3038
    return fdt2;
T
ths 已提交
3039
}
3040

3041
uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3042
{
3043 3044
    uint32_t fst2;

3045
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3046
    update_fcr31(env, GETPC());
3047
    return fst2;
T
ths 已提交
3048
}
3049

3050
uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3051
{
3052 3053 3054
    uint32_t fst2;
    uint32_t fsth2;

3055 3056
    fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
3057
    update_fcr31(env, GETPC());
3058
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3059 3060
}

3061
uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3062
{
3063 3064
    uint64_t fdt2;

3065
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3066
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3067
    update_fcr31(env, GETPC());
3068
    return fdt2;
T
ths 已提交
3069
}
3070

3071
uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3072
{
3073 3074
    uint32_t fst2;

3075
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3076
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3077
    update_fcr31(env, GETPC());
3078
    return fst2;
T
ths 已提交
3079
}
3080

3081
uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3082
{
3083 3084 3085
    uint32_t fst2;
    uint32_t fsth2;

3086 3087
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3088 3089
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3090
    update_fcr31(env, GETPC());
3091
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3092 3093
}

3094
#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
3095

3096
/* binary operations */
3097
#define FLOAT_BINOP(name)                                          \
3098 3099
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
                                     uint64_t fdt0, uint64_t fdt1) \
3100 3101 3102
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
3103
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3104
    update_fcr31(env, GETPC());                                    \
3105 3106 3107
    return dt2;                                                    \
}                                                                  \
                                                                   \
3108 3109
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
                                     uint32_t fst0, uint32_t fst1) \
3110 3111 3112
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
3113
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3114
    update_fcr31(env, GETPC());                                    \
3115 3116 3117
    return wt2;                                                    \
}                                                                  \
                                                                   \
3118 3119 3120
uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
                                      uint64_t fdt0,               \
                                      uint64_t fdt1)               \
3121 3122 3123 3124 3125 3126 3127 3128
{                                                                  \
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
    uint32_t fsth0 = fdt0 >> 32;                                   \
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
    uint32_t fsth1 = fdt1 >> 32;                                   \
    uint32_t wt2;                                                  \
    uint32_t wth2;                                                 \
                                                                   \
3129 3130
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3131
    update_fcr31(env, GETPC());                                    \
3132
    return ((uint64_t)wth2 << 32) | wt2;                           \
3133
}
3134

3135 3136 3137 3138 3139 3140
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
#define UNFUSED_FMA(prefix, a, b, c, flags)                          \
{                                                                    \
    a = prefix##_mul(a, b, &env->active_fpu.fp_status);              \
    if ((flags) & float_muladd_negate_c) {                           \
        a = prefix##_sub(a, c, &env->active_fpu.fp_status);          \
    } else {                                                         \
        a = prefix##_add(a, c, &env->active_fpu.fp_status);          \
    }                                                                \
    if ((flags) & float_muladd_negate_result) {                      \
        a = prefix##_chs(a);                                         \
    }                                                                \
}

3154 3155 3156 3157 3158 3159
/* FMA based operations */
#define FLOAT_FMA(name, type)                                        \
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
                                     uint64_t fdt0, uint64_t fdt1,   \
                                     uint64_t fdt2)                  \
{                                                                    \
3160
    UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
3161
    update_fcr31(env, GETPC());                                      \
3162 3163 3164 3165 3166 3167 3168
    return fdt0;                                                     \
}                                                                    \
                                                                     \
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
                                     uint32_t fst0, uint32_t fst1,   \
                                     uint32_t fst2)                  \
{                                                                    \
3169
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3170
    update_fcr31(env, GETPC());                                      \
3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184
    return fst0;                                                     \
}                                                                    \
                                                                     \
uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
                                      uint64_t fdt0, uint64_t fdt1,  \
                                      uint64_t fdt2)                 \
{                                                                    \
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
    uint32_t fsth0 = fdt0 >> 32;                                     \
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
    uint32_t fsth1 = fdt1 >> 32;                                     \
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
    uint32_t fsth2 = fdt2 >> 32;                                     \
                                                                     \
3185 3186
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
    UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
3187
    update_fcr31(env, GETPC());                                      \
3188 3189 3190 3191 3192 3193 3194
    return ((uint64_t)fsth0 << 32) | fst0;                           \
}
FLOAT_FMA(madd, 0)
FLOAT_FMA(msub, float_muladd_negate_c)
FLOAT_FMA(nmadd, float_muladd_negate_result)
FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
#undef FLOAT_FMA
3195

T
ths 已提交
3196
/* MIPS specific binary operations */
3197
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3198
{
3199
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3200
    fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3201
    update_fcr31(env, GETPC());
3202
    return fdt2;
T
ths 已提交
3203
}
3204

3205
uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3206
{
3207
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3208
    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3209
    update_fcr31(env, GETPC());
3210
    return fst2;
T
ths 已提交
3211
}
3212

3213
uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3214
{
3215 3216 3217 3218 3219
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3220 3221
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3222 3223
    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
    fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
3224
    update_fcr31(env, GETPC());
3225
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3226 3227
}

3228
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3229
{
3230
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3231
    fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3232
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3233
    update_fcr31(env, GETPC());
3234
    return fdt2;
T
ths 已提交
3235
}
3236

3237
uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3238
{
3239
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3240
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3241
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3242
    update_fcr31(env, GETPC());
3243
    return fst2;
T
ths 已提交
3244
}
3245

3246
uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3247
{
3248 3249 3250 3251 3252
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3253 3254
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3255 3256
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
    fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3257 3258
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
3259
    update_fcr31(env, GETPC());
3260
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3261 3262
}

3263
uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3264
{
3265 3266 3267 3268 3269 3270 3271
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
    uint32_t fsth1 = fdt1 >> 32;
    uint32_t fst2;
    uint32_t fsth2;

3272 3273
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3274
    update_fcr31(env, GETPC());
3275
    return ((uint64_t)fsth2 << 32) | fst2;
3276 3277
}

3278
uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
3279
{
3280 3281 3282 3283 3284 3285 3286
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
    uint32_t fsth1 = fdt1 >> 32;
    uint32_t fst2;
    uint32_t fsth2;

3287 3288
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3289
    update_fcr31(env, GETPC());
3290
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3291 3292
}

T
ths 已提交
3293
/* compare operations */
3294
#define FOP_COND_D(op, cond)                                   \
3295 3296
void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                         uint64_t fdt1, int cc)                \
3297
{                                                              \
3298 3299
    int c;                                                     \
    c = cond;                                                  \
3300
    update_fcr31(env, GETPC());                                \
3301
    if (c)                                                     \
3302
        SET_FP_COND(cc, env->active_fpu);                      \
3303
    else                                                       \
3304
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3305
}                                                              \
3306 3307
void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                            uint64_t fdt1, int cc)             \
3308 3309 3310 3311 3312
{                                                              \
    int c;                                                     \
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
3313
    update_fcr31(env, GETPC());                                \
3314
    if (c)                                                     \
3315
        SET_FP_COND(cc, env->active_fpu);                      \
3316
    else                                                       \
3317
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3318 3319 3320
}

/* NOTE: the comma operator will make "cond" to eval to false,
3321 3322 3323
 * but float64_unordered_quiet() is still called. */
FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
3324
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3325
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3326 3327 3328 3329
FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3330
/* NOTE: the comma operator will make "cond" to eval to false,
3331 3332 3333
 * but float64_unordered() is still called. */
FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
3334 3335 3336
FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3337
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3338
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3339
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3340 3341

#define FOP_COND_S(op, cond)                                   \
3342 3343
void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
                         uint32_t fst1, int cc)                \
3344
{                                                              \
3345 3346
    int c;                                                     \
    c = cond;                                                  \
3347
    update_fcr31(env, GETPC());                                \
3348
    if (c)                                                     \
3349
        SET_FP_COND(cc, env->active_fpu);                      \
3350
    else                                                       \
3351
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3352
}                                                              \
3353 3354
void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
                            uint32_t fst1, int cc)             \
3355 3356 3357 3358 3359
{                                                              \
    int c;                                                     \
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
3360
    update_fcr31(env, GETPC());                                \
3361
    if (c)                                                     \
3362
        SET_FP_COND(cc, env->active_fpu);                      \
3363
    else                                                       \
3364
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3365 3366 3367
}

/* NOTE: the comma operator will make "cond" to eval to false,
3368 3369 3370
 * but float32_unordered_quiet() is still called. */
FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
3371
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3372
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3373 3374 3375 3376
FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3377
/* NOTE: the comma operator will make "cond" to eval to false,
3378 3379 3380
 * but float32_unordered() is still called. */
FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
3381 3382 3383
FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3384
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3385
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3386
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3387 3388

#define FOP_COND_PS(op, condl, condh)                           \
3389 3390
void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                          uint64_t fdt1, int cc)                \
3391
{                                                               \
3392 3393 3394 3395 3396 3397 3398 3399
    uint32_t fst0, fsth0, fst1, fsth1;                          \
    int ch, cl;                                                 \
    fst0 = fdt0 & 0XFFFFFFFF;                                   \
    fsth0 = fdt0 >> 32;                                         \
    fst1 = fdt1 & 0XFFFFFFFF;                                   \
    fsth1 = fdt1 >> 32;                                         \
    cl = condl;                                                 \
    ch = condh;                                                 \
3400
    update_fcr31(env, GETPC());                                 \
3401
    if (cl)                                                     \
3402
        SET_FP_COND(cc, env->active_fpu);                       \
3403
    else                                                        \
3404
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3405
    if (ch)                                                     \
3406
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3407
    else                                                        \
3408
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3409
}                                                               \
3410 3411
void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                             uint64_t fdt1, int cc)             \
3412
{                                                               \
3413 3414 3415 3416 3417 3418 3419 3420
    uint32_t fst0, fsth0, fst1, fsth1;                          \
    int ch, cl;                                                 \
    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
    fsth0 = float32_abs(fdt0 >> 32);                            \
    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
    fsth1 = float32_abs(fdt1 >> 32);                            \
    cl = condl;                                                 \
    ch = condh;                                                 \
3421
    update_fcr31(env, GETPC());                                 \
3422
    if (cl)                                                     \
3423
        SET_FP_COND(cc, env->active_fpu);                       \
3424
    else                                                        \
3425
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3426
    if (ch)                                                     \
3427
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3428
    else                                                        \
3429
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3430 3431 3432
}

/* NOTE: the comma operator will make "cond" to eval to false,
3433 3434 3435 3436 3437
 * but float32_unordered_quiet() is still called. */
FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
3438 3439
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3440 3441
FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3442 3443 3444 3445 3446 3447 3448 3449
FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3450
/* NOTE: the comma operator will make "cond" to eval to false,
3451 3452 3453 3454 3455
 * but float32_unordered() is still called. */
FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
3456 3457 3458 3459 3460 3461
FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3462 3463
FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3464 3465
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3466 3467
FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578

/* R6 compare operations */
#define FOP_CONDN_D(op, cond)                                       \
uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0,  \
                         uint64_t fdt1)                             \
{                                                                   \
    uint64_t c;                                                     \
    c = cond;                                                       \
    update_fcr31(env, GETPC());                                     \
    if (c) {                                                        \
        return -1;                                                  \
    } else {                                                        \
        return 0;                                                   \
    }                                                               \
}

/* NOTE: the comma operator will make "cond" to eval to false,
 * but float64_unordered_quiet() is still called. */
FOP_CONDN_D(af,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_CONDN_D(un,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
FOP_CONDN_D(eq,  (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(lt,  (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(le,  (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
/* NOTE: the comma operator will make "cond" to eval to false,
 * but float64_unordered() is still called. */
FOP_CONDN_D(saf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_CONDN_D(sun,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
FOP_CONDN_D(seq,  (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(slt,  (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sle,  (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(or,   (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(une,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(ne,   (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sor,  (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
FOP_CONDN_D(sne,  (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))

#define FOP_CONDN_S(op, cond)                                       \
uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0,  \
                         uint32_t fst1)                             \
{                                                                   \
    uint64_t c;                                                     \
    c = cond;                                                       \
    update_fcr31(env, GETPC());                                     \
    if (c) {                                                        \
        return -1;                                                  \
    } else {                                                        \
        return 0;                                                   \
    }                                                               \
}

/* NOTE: the comma operator will make "cond" to eval to false,
 * but float32_unordered_quiet() is still called. */
FOP_CONDN_S(af,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_CONDN_S(un,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
FOP_CONDN_S(eq,   (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(ueq,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(lt,   (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(ult,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(le,   (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(ule,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
/* NOTE: the comma operator will make "cond" to eval to false,
 * but float32_unordered() is still called. */
FOP_CONDN_S(saf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_CONDN_S(sun,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
FOP_CONDN_S(seq,  (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(slt,  (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sle,  (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(or,   (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(une,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(ne,   (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sor,  (float32_le(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
FOP_CONDN_S(sne,  (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))