op_helper.c 120.8 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
void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
2241 2242
                                  int access_type, int is_user,
                                  uintptr_t retaddr)
B
bellard 已提交
2243
{
2244 2245
    MIPSCPU *cpu = MIPS_CPU(cs);
    CPUMIPSState *env = &cpu->env;
2246 2247
    int error_code = 0;
    int excp;
2248

B
bellard 已提交
2249
    env->CP0_BadVAddr = addr;
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260

    if (access_type == MMU_DATA_STORE) {
        excp = EXCP_AdES;
    } else {
        excp = EXCP_AdEL;
        if (access_type == MMU_INST_FETCH) {
            error_code |= EXCP_INST_NOTAVAIL;
        }
    }

    do_raise_exception_err(env, excp, error_code, retaddr);
B
bellard 已提交
2261 2262
}

2263
void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2264
              uintptr_t retaddr)
2265 2266 2267
{
    int ret;

2268
    ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
2269
    if (ret) {
2270 2271 2272
        MIPSCPU *cpu = MIPS_CPU(cs);
        CPUMIPSState *env = &cpu->env;

2273
        do_raise_exception_err(env, cs->exception_index,
2274
                               env->error_code, retaddr);
2275 2276 2277
    }
}

2278 2279 2280
void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
                                bool is_write, bool is_exec, int unused,
                                unsigned size)
T
ths 已提交
2281
{
2282 2283 2284
    MIPSCPU *cpu = MIPS_CPU(cs);
    CPUMIPSState *env = &cpu->env;

2285 2286 2287 2288 2289 2290 2291 2292 2293 2294
    /*
     * 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;
    }

2295
    if (is_exec) {
2296
        helper_raise_exception(env, EXCP_IBE);
2297
    } else {
2298
        helper_raise_exception(env, EXCP_DBE);
2299
    }
T
ths 已提交
2300
}
2301
#endif /* !CONFIG_USER_ONLY */
2302 2303 2304

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

P
pbrook 已提交
2305 2306
#define FLOAT_TWO32 make_float32(1 << 30)
#define FLOAT_TWO64 make_float64(1ULL << 62)
2307 2308
#define FP_TO_INT32_OVERFLOW 0x7fffffff
#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
T
ths 已提交
2309

2310
/* convert MIPS rounding mode in FCR31 to IEEE library */
B
Blue Swirl 已提交
2311
static unsigned int ieee_rm[] = {
2312 2313 2314 2315 2316 2317
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

2318 2319 2320 2321 2322
static inline void restore_rounding_mode(CPUMIPSState *env)
{
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
                            &env->active_fpu.fp_status);
}
2323

2324 2325 2326 2327 2328
static inline void restore_flush_mode(CPUMIPSState *env)
{
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
                      &env->active_fpu.fp_status);
}
2329

2330
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2331
{
2332
    target_ulong arg1 = 0;
2333

2334 2335
    switch (reg) {
    case 0:
2336
        arg1 = (int32_t)env->active_fpu.fcr0;
2337
        break;
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348
    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;
2349
    case 25:
2350
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2351 2352
        break;
    case 26:
2353
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2354 2355
        break;
    case 28:
2356
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2357 2358
        break;
    default:
2359
        arg1 = (int32_t)env->active_fpu.fcr31;
2360 2361
        break;
    }
2362

2363
    return arg1;
2364 2365
}

2366
void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
2367
{
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392
    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;
2393
    case 25:
2394
        if (arg1 & 0xffffff00)
2395
            return;
2396 2397
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2398 2399
        break;
    case 26:
2400
        if (arg1 & 0x007c0000)
2401
            return;
2402
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2403 2404
        break;
    case 28:
2405
        if (arg1 & 0x007c0000)
2406
            return;
2407 2408
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2409 2410
        break;
    case 31:
2411
        if (arg1 & 0x007c0000)
2412
            return;
2413
        env->active_fpu.fcr31 = arg1;
2414 2415 2416 2417 2418
        break;
    default:
        return;
    }
    /* set rounding mode */
2419
    restore_rounding_mode(env);
2420
    /* set flush-to-zero mode */
2421
    restore_flush_mode(env);
2422 2423
    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))
2424
        do_raise_exception(env, EXCP_FPE, GETPC());
2425 2426
}

2427
static inline int ieee_ex_to_mips(int xcpt)
2428
{
2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447
    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;
2448 2449
}

2450
static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2451
{
2452
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2453

2454
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2455 2456 2457 2458 2459

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

        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2460
            do_raise_exception(env, EXCP_FPE, pc);
2461 2462 2463 2464
        } else {
            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
        }
    }
2465 2466
}

2467 2468 2469 2470 2471 2472
/* 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  */
2473
uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2474
{
A
Aurelien Jarno 已提交
2475
    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2476
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2477
    return fdt0;
2478 2479
}

2480
uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2481
{
A
Aurelien Jarno 已提交
2482
    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2483
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2484
    return fst0;
2485
}
2486

2487
uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2488
{
2489 2490
    uint64_t fdt2;

2491
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2492
    update_fcr31(env, GETPC());
2493
    return fdt2;
2494
}
2495

2496
uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2497
{
2498 2499
    uint64_t fdt2;

2500
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2501
    update_fcr31(env, GETPC());
2502
    return fdt2;
2503
}
2504

2505
uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2506
{
2507 2508
    uint64_t fdt2;

2509
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2510
    update_fcr31(env, GETPC());
2511
    return fdt2;
2512
}
2513

2514
uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
2515
{
2516 2517
    uint64_t dt2;

2518
    dt2 = float64_to_int64(fdt0, &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_cvtl_s(CPUMIPSState *env, uint32_t fst0)
2528
{
2529 2530
    uint64_t dt2;

2531
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2532 2533
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2534
        dt2 = FP_TO_INT64_OVERFLOW;
2535
    }
2536
    update_fcr31(env, GETPC());
2537
    return dt2;
2538 2539
}

2540
uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2541
{
2542 2543 2544
    uint32_t fst2;
    uint32_t fsth2;

2545 2546
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2547
    update_fcr31(env, GETPC());
2548
    return ((uint64_t)fsth2 << 32) | fst2;
2549
}
2550

2551
uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2552
{
2553 2554
    uint32_t wt2;
    uint32_t wth2;
A
Aurelien Jarno 已提交
2555
    int excp, excph;
2556

2557
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
A
Aurelien Jarno 已提交
2558 2559
    excp = get_float_exception_flags(&env->active_fpu.fp_status);
    if (excp & (float_flag_overflow | float_flag_invalid)) {
2560
        wt2 = FP_TO_INT32_OVERFLOW;
A
Aurelien Jarno 已提交
2561 2562 2563 2564 2565 2566
    }

    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)) {
2567
        wth2 = FP_TO_INT32_OVERFLOW;
2568
    }
A
Aurelien Jarno 已提交
2569 2570

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

2573
    return ((uint64_t)wth2 << 32) | wt2;
2574
}
2575

2576
uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2577
{
2578 2579
    uint32_t fst2;

2580
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2581
    update_fcr31(env, GETPC());
2582
    return fst2;
2583
}
2584

2585
uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2586
{
2587 2588
    uint32_t fst2;

2589
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2590
    update_fcr31(env, GETPC());
2591
    return fst2;
2592
}
2593

2594
uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2595
{
2596 2597
    uint32_t fst2;

2598
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2599
    update_fcr31(env, GETPC());
2600
    return fst2;
2601
}
2602

2603
uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2604
{
2605 2606 2607
    uint32_t wt2;

    wt2 = wt0;
2608
    update_fcr31(env, GETPC());
2609
    return wt2;
2610
}
2611

2612
uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2613
{
2614 2615 2616
    uint32_t wt2;

    wt2 = wth0;
2617
    update_fcr31(env, GETPC());
2618
    return wt2;
2619
}
2620

2621
uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
2622
{
2623 2624
    uint32_t wt2;

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

2634
uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
2635
{
2636 2637
    uint32_t wt2;

2638
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2639 2640
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2641
        wt2 = FP_TO_INT32_OVERFLOW;
2642
    }
2643
    update_fcr31(env, GETPC());
2644
    return wt2;
2645 2646
}

2647
uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
2648
{
2649 2650
    uint64_t dt2;

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

2662
uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
2663
{
2664 2665
    uint64_t dt2;

2666 2667
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2668
    restore_rounding_mode(env);
2669 2670
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2671
        dt2 = FP_TO_INT64_OVERFLOW;
2672
    }
2673
    update_fcr31(env, GETPC());
2674
    return dt2;
2675
}
2676

2677
uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
2678
{
2679 2680
    uint32_t wt2;

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

2692
uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
2693
{
2694 2695
    uint32_t wt2;

2696 2697
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2698
    restore_rounding_mode(env);
2699 2700
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2701
        wt2 = FP_TO_INT32_OVERFLOW;
2702
    }
2703
    update_fcr31(env, GETPC());
2704
    return wt2;
2705 2706
}

2707
uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
2708
{
2709 2710
    uint64_t dt2;

2711
    dt2 = float64_to_int64_round_to_zero(fdt0, &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
uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
2721
{
2722 2723
    uint64_t dt2;

2724
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2725 2726
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2727
        dt2 = FP_TO_INT64_OVERFLOW;
2728
    }
2729
    update_fcr31(env, GETPC());
2730
    return dt2;
2731
}
2732

2733
uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
2734
{
2735 2736
    uint32_t wt2;

2737
    wt2 = float64_to_int32_round_to_zero(fdt0, &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
uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
2747
{
2748 2749
    uint32_t wt2;

2750
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2751 2752
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2753
        wt2 = FP_TO_INT32_OVERFLOW;
2754
    }
2755
    update_fcr31(env, GETPC());
2756
    return wt2;
2757 2758
}

2759
uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
2760
{
2761 2762
    uint64_t dt2;

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

2774
uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
2775
{
2776 2777
    uint64_t dt2;

2778 2779
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2780
    restore_rounding_mode(env);
2781 2782
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2783
        dt2 = FP_TO_INT64_OVERFLOW;
2784
    }
2785
    update_fcr31(env, GETPC());
2786
    return dt2;
2787
}
2788

2789
uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
2790
{
2791 2792
    uint32_t wt2;

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

2804
uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
2805
{
2806 2807
    uint32_t wt2;

2808 2809
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2810
    restore_rounding_mode(env);
2811 2812
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2813
        wt2 = FP_TO_INT32_OVERFLOW;
2814
    }
2815
    update_fcr31(env, GETPC());
2816
    return wt2;
2817 2818
}

2819
uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
2820
{
2821 2822
    uint64_t dt2;

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

2834
uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
2835
{
2836 2837
    uint64_t dt2;

2838 2839
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2840
    restore_rounding_mode(env);
2841 2842
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2843
        dt2 = FP_TO_INT64_OVERFLOW;
2844
    }
2845
    update_fcr31(env, GETPC());
2846
    return dt2;
2847
}
2848

2849
uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
2850
{
2851 2852
    uint32_t wt2;

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

2864
uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
2865
{
2866 2867
    uint32_t wt2;

2868 2869
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2870
    restore_rounding_mode(env);
2871 2872
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2873
        wt2 = FP_TO_INT32_OVERFLOW;
2874
    }
2875
    update_fcr31(env, GETPC());
2876
    return wt2;
2877 2878
}

2879
/* unary operations, not modifying fp status  */
2880
#define FLOAT_UNOP(name)                                       \
2881
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2882 2883 2884
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2885
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2886 2887 2888
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2889
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2890 2891 2892 2893 2894 2895 2896
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2897 2898 2899 2900 2901
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

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 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
#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 已提交
3006
/* MIPS specific unary operations */
3007
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3008
{
3009 3010
    uint64_t fdt2;

3011
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3012
    update_fcr31(env, GETPC());
3013
    return fdt2;
T
ths 已提交
3014
}
3015

3016
uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3017
{
3018 3019
    uint32_t fst2;

3020
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3021
    update_fcr31(env, GETPC());
3022
    return fst2;
T
ths 已提交
3023 3024
}

3025
uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3026
{
3027 3028
    uint64_t fdt2;

3029
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3030
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3031
    update_fcr31(env, GETPC());
3032
    return fdt2;
T
ths 已提交
3033
}
3034

3035
uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3036
{
3037 3038
    uint32_t fst2;

3039
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3040
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3041
    update_fcr31(env, GETPC());
3042
    return fst2;
T
ths 已提交
3043 3044
}

3045
uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3046
{
3047 3048
    uint64_t fdt2;

3049
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3050
    update_fcr31(env, GETPC());
3051
    return fdt2;
T
ths 已提交
3052
}
3053

3054
uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3055
{
3056 3057
    uint32_t fst2;

3058
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3059
    update_fcr31(env, GETPC());
3060
    return fst2;
T
ths 已提交
3061
}
3062

3063
uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3064
{
3065 3066 3067
    uint32_t fst2;
    uint32_t fsth2;

3068 3069
    fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
3070
    update_fcr31(env, GETPC());
3071
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3072 3073
}

3074
uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3075
{
3076 3077
    uint64_t fdt2;

3078
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3079
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3080
    update_fcr31(env, GETPC());
3081
    return fdt2;
T
ths 已提交
3082
}
3083

3084
uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3085
{
3086 3087
    uint32_t fst2;

3088
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3089
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3090
    update_fcr31(env, GETPC());
3091
    return fst2;
T
ths 已提交
3092
}
3093

3094
uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3095
{
3096 3097 3098
    uint32_t fst2;
    uint32_t fsth2;

3099 3100
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3101 3102
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3103
    update_fcr31(env, GETPC());
3104
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3105 3106
}

3107
#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
3108

3109
/* binary operations */
3110
#define FLOAT_BINOP(name)                                          \
3111 3112
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
                                     uint64_t fdt0, uint64_t fdt1) \
3113 3114 3115
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
3116
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3117
    update_fcr31(env, GETPC());                                    \
3118 3119 3120
    return dt2;                                                    \
}                                                                  \
                                                                   \
3121 3122
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
                                     uint32_t fst0, uint32_t fst1) \
3123 3124 3125
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
3126
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3127
    update_fcr31(env, GETPC());                                    \
3128 3129 3130
    return wt2;                                                    \
}                                                                  \
                                                                   \
3131 3132 3133
uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
                                      uint64_t fdt0,               \
                                      uint64_t fdt1)               \
3134 3135 3136 3137 3138 3139 3140 3141
{                                                                  \
    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;                                                 \
                                                                   \
3142 3143
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3144
    update_fcr31(env, GETPC());                                    \
3145
    return ((uint64_t)wth2 << 32) | wt2;                           \
3146
}
3147

3148 3149 3150 3151 3152 3153
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
#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);                                         \
    }                                                                \
}

3167 3168 3169 3170 3171 3172
/* 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)                  \
{                                                                    \
3173
    UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
3174
    update_fcr31(env, GETPC());                                      \
3175 3176 3177 3178 3179 3180 3181
    return fdt0;                                                     \
}                                                                    \
                                                                     \
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
                                     uint32_t fst0, uint32_t fst1,   \
                                     uint32_t fst2)                  \
{                                                                    \
3182
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3183
    update_fcr31(env, GETPC());                                      \
3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197
    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;                                     \
                                                                     \
3198 3199
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
    UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
3200
    update_fcr31(env, GETPC());                                      \
3201 3202 3203 3204 3205 3206 3207
    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
3208

T
ths 已提交
3209
/* MIPS specific binary operations */
3210
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3211
{
3212
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3213
    fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3214
    update_fcr31(env, GETPC());
3215
    return fdt2;
T
ths 已提交
3216
}
3217

3218
uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3219
{
3220
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3221
    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3222
    update_fcr31(env, GETPC());
3223
    return fst2;
T
ths 已提交
3224
}
3225

3226
uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3227
{
3228 3229 3230 3231 3232
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3233 3234
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3235 3236
    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));
3237
    update_fcr31(env, GETPC());
3238
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3239 3240
}

3241
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3242
{
3243
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3244
    fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3245
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3246
    update_fcr31(env, GETPC());
3247
    return fdt2;
T
ths 已提交
3248
}
3249

3250
uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3251
{
3252
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3253
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3254
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3255
    update_fcr31(env, GETPC());
3256
    return fst2;
T
ths 已提交
3257
}
3258

3259
uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3260
{
3261 3262 3263 3264 3265
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3266 3267
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3268 3269
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
    fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3270 3271
    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));
3272
    update_fcr31(env, GETPC());
3273
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3274 3275
}

3276
uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3277
{
3278 3279 3280 3281 3282 3283 3284
    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;

3285 3286
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3287
    update_fcr31(env, GETPC());
3288
    return ((uint64_t)fsth2 << 32) | fst2;
3289 3290
}

3291
uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
3292
{
3293 3294 3295 3296 3297 3298 3299
    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;

3300 3301
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3302
    update_fcr31(env, GETPC());
3303
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3304 3305
}

T
ths 已提交
3306
/* compare operations */
3307
#define FOP_COND_D(op, cond)                                   \
3308 3309
void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                         uint64_t fdt1, int cc)                \
3310
{                                                              \
3311 3312
    int c;                                                     \
    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
void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                            uint64_t fdt1, int cc)             \
3321 3322 3323 3324 3325
{                                                              \
    int c;                                                     \
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
3326
    update_fcr31(env, GETPC());                                \
3327
    if (c)                                                     \
3328
        SET_FP_COND(cc, env->active_fpu);                      \
3329
    else                                                       \
3330
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3331 3332 3333
}

/* NOTE: the comma operator will make "cond" to eval to false,
3334 3335 3336
 * 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))
3337
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3338
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3339 3340 3341 3342
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))
3343
/* NOTE: the comma operator will make "cond" to eval to false,
3344 3345 3346
 * 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))
3347 3348 3349
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))
3350
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3351
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3352
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3353 3354

#define FOP_COND_S(op, cond)                                   \
3355 3356
void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
                         uint32_t fst1, int cc)                \
3357
{                                                              \
3358 3359
    int c;                                                     \
    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
void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
                            uint32_t fst1, int cc)             \
3368 3369 3370 3371 3372
{                                                              \
    int c;                                                     \
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
3373
    update_fcr31(env, GETPC());                                \
3374
    if (c)                                                     \
3375
        SET_FP_COND(cc, env->active_fpu);                      \
3376
    else                                                       \
3377
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3378 3379 3380
}

/* NOTE: the comma operator will make "cond" to eval to false,
3381 3382 3383
 * 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))
3384
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3385
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3386 3387 3388 3389
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))
3390
/* NOTE: the comma operator will make "cond" to eval to false,
3391 3392 3393
 * 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))
3394 3395 3396
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))
3397
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3398
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3399
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3400 3401

#define FOP_COND_PS(op, condl, condh)                           \
3402 3403
void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                          uint64_t fdt1, int cc)                \
3404
{                                                               \
3405 3406 3407 3408 3409 3410 3411 3412
    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;                                                 \
3413
    update_fcr31(env, GETPC());                                 \
3414
    if (cl)                                                     \
3415
        SET_FP_COND(cc, env->active_fpu);                       \
3416
    else                                                        \
3417
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3418
    if (ch)                                                     \
3419
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3420
    else                                                        \
3421
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3422
}                                                               \
3423 3424
void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                             uint64_t fdt1, int cc)             \
3425
{                                                               \
3426 3427 3428 3429 3430 3431 3432 3433
    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;                                                 \
3434
    update_fcr31(env, GETPC());                                 \
3435
    if (cl)                                                     \
3436
        SET_FP_COND(cc, env->active_fpu);                       \
3437
    else                                                        \
3438
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3439
    if (ch)                                                     \
3440
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3441
    else                                                        \
3442
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3443 3444 3445
}

/* NOTE: the comma operator will make "cond" to eval to false,
3446 3447 3448 3449 3450
 * 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))
3451 3452
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3453 3454
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))
3455 3456 3457 3458 3459 3460 3461 3462
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))
3463
/* NOTE: the comma operator will make "cond" to eval to false,
3464 3465 3466 3467 3468
 * 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))
3469 3470 3471 3472 3473 3474
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))
3475 3476
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))
3477 3478
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3479 3480
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))
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 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591

/* 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)))