op_helper.c 126.0 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 42
        qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
                      __func__, exception, error_code);
43
    }
44
    cs->exception_index = exception;
B
bellard 已提交
45
    env->error_code = error_code;
46 47 48

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

269 270
static inline target_ulong bitswap(target_ulong v)
{
271 272 273 274 275 276
    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);
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    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);
}

292
#ifndef CONFIG_USER_ONLY
293

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

    lladdr = cpu_mips_translate_address(env, address, rw);

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

309
#define HELPER_LD_ATOMIC(name, insn, almask)                                  \
310
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
311
{                                                                             \
312 313 314 315
    if (arg & almask) {                                                       \
        env->CP0_BadVAddr = arg;                                              \
        helper_raise_exception(env, EXCP_AdEL);                               \
    }                                                                         \
316 317
    env->lladdr = do_translate_address(env, arg, 0);                          \
    env->llval = do_##insn(env, arg, mem_idx);                                \
318 319
    return env->llval;                                                        \
}
320
HELPER_LD_ATOMIC(ll, lw, 0x3)
321
#ifdef TARGET_MIPS64
322
HELPER_LD_ATOMIC(lld, ld, 0x7)
323 324 325 326
#endif
#undef HELPER_LD_ATOMIC

#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
327 328
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
                           target_ulong arg2, int mem_idx)                    \
329 330 331 332 333
{                                                                             \
    target_long tmp;                                                          \
                                                                              \
    if (arg2 & almask) {                                                      \
        env->CP0_BadVAddr = arg2;                                             \
334
        helper_raise_exception(env, EXCP_AdES);                               \
335
    }                                                                         \
336 337
    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
        tmp = do_##ld_insn(env, arg2, mem_idx);                               \
338
        if (tmp == env->llval) {                                              \
339
            do_##st_insn(env, arg2, arg1, mem_idx);                           \
340 341 342 343 344 345 346 347 348 349 350 351
            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 已提交
352 353 354 355 356 357 358 359
#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

360 361
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
362
{
363
    do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
364

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

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

371
    if (GET_LMASK(arg2) == 0)
372
        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
T
ths 已提交
373 374
}

375 376
void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
377
{
378
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
379

380
    if (GET_LMASK(arg2) >= 1)
381
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
382

383
    if (GET_LMASK(arg2) >= 2)
384
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
385

386
    if (GET_LMASK(arg2) == 3)
387
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
388 389 390 391 392 393 394 395 396 397 398 399
}

#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

400 401
void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
402
{
403
    do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
404

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

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

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

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

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

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

423
    if (GET_LMASK64(arg2) <= 0)
424
        do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
T
ths 已提交
425 426
}

427 428
void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
429
{
430
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
431

432
    if (GET_LMASK64(arg2) >= 1)
433
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
434

435
    if (GET_LMASK64(arg2) >= 2)
436
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
437

438
    if (GET_LMASK64(arg2) >= 3)
439
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
440

441
    if (GET_LMASK64(arg2) >= 4)
442
        do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
443

444
    if (GET_LMASK64(arg2) >= 5)
445
        do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
446

447
    if (GET_LMASK64(arg2) >= 6)
448
        do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
449

450
    if (GET_LMASK64(arg2) == 7)
451
        do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
452 453 454
}
#endif /* TARGET_MIPS64 */

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

457 458
void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
459 460 461 462 463 464 465 466
{
    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++) {
467 468
            env->active_tc.gpr[multiple_regs[i]] =
                (target_long)do_lw(env, addr, mem_idx);
469 470 471 472 473
            addr += 4;
        }
    }

    if (do_r31) {
474
        env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
475 476 477
    }
}

478 479
void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
480 481 482 483 484 485 486 487
{
    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++) {
488
            do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
489 490 491 492 493
            addr += 4;
        }
    }

    if (do_r31) {
494
        do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
495 496 497 498
    }
}

#if defined(TARGET_MIPS64)
499 500
void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
501 502 503 504 505 506 507 508
{
    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++) {
509
            env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
510 511 512 513 514
            addr += 8;
        }
    }

    if (do_r31) {
515
        env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
516 517 518
    }
}

519 520
void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
521 522 523 524 525 526 527 528
{
    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++) {
529
            do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
530 531 532 533 534
            addr += 8;
        }
    }

    if (do_r31) {
535
        do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
536 537 538 539
    }
}
#endif

T
ths 已提交
540
#ifndef CONFIG_USER_ONLY
541
/* SMP helpers.  */
542
static bool mips_vpe_is_wfi(MIPSCPU *c)
543
{
544
    CPUState *cpu = CPU(c);
545 546
    CPUMIPSState *env = &c->env;

547 548
    /* If the VPE is halted but otherwise active, it means it's waiting for
       an interrupt.  */
549
    return cpu->halted && mips_vpe_active(env);
550 551
}

552
static inline void mips_vpe_wake(MIPSCPU *c)
553 554 555 556
{
    /* 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.  */
557
    cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
558 559
}

560
static inline void mips_vpe_sleep(MIPSCPU *cpu)
561
{
562
    CPUState *cs = CPU(cpu);
563

564 565
    /* The VPE was shut off, really go to bed.
       Reset any old _WAKE requests.  */
566
    cs->halted = 1;
567
    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
568 569
}

570
static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
571
{
572 573
    CPUMIPSState *c = &cpu->env;

574
    /* FIXME: TC reschedule.  */
575
    if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
576
        mips_vpe_wake(cpu);
577 578 579
    }
}

580
static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
581
{
582 583
    CPUMIPSState *c = &cpu->env;

584 585
    /* FIXME: TC reschedule.  */
    if (!mips_vpe_active(c)) {
586
        mips_vpe_sleep(cpu);
587 588 589
    }
}

590 591 592 593 594 595 596 597 598
/**
 * 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,
599
          which depends on runtime setup. Can probably be fixed by
600
          walking the list of CPUMIPSStates.  */
601
static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
602
{
603
    MIPSCPU *cpu;
604
    CPUState *cs;
605
    CPUState *other_cs;
606
    int vpe_idx;
607 608 609 610 611 612 613 614
    int tc_idx = *tc;

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

615 616 617
    cs = CPU(mips_env_get_cpu(env));
    vpe_idx = tc_idx / cs->nr_threads;
    *tc = tc_idx % cs->nr_threads;
618 619 620 621 622 623
    other_cs = qemu_get_cpu(vpe_idx);
    if (other_cs == NULL) {
        return env;
    }
    cpu = MIPS_CPU(other_cs);
    return &cpu->env;
624 625
}

626 627 628 629 630 631 632 633
/* 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.  */

634 635 636
/* Called for updates to CP0_Status.  Defined in "cpu.h" for gdbstub.c.  */
/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
                                     int tc);  */
637 638

/* Called for updates to CP0_TCStatus.  */
639 640
static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
                             target_ulong v)
641 642 643
{
    uint32_t status;
    uint32_t tcu, tmx, tasid, tksu;
644
    uint32_t mask = ((1U << CP0St_CU3)
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
                       | (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;
665
    cpu->CP0_EntryHi |= tasid;
666 667 668 669 670

    compute_hflags(cpu);
}

/* Called for updates to CP0_EntryHi.  */
671
static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
{
    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 已提交
688
/* CP0 helpers */
689
target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
690
{
691
    return env->mvp->CP0_MVPControl;
692 693
}

694
target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
695
{
696
    return env->mvp->CP0_MVPConf0;
697 698
}

699
target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
700
{
701
    return env->mvp->CP0_MVPConf1;
702 703
}

704
target_ulong helper_mfc0_random(CPUMIPSState *env)
B
bellard 已提交
705
{
706
    return (int32_t)cpu_mips_get_random(env);
707
}
B
bellard 已提交
708

709
target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
710
{
711
    return env->active_tc.CP0_TCStatus;
712 713
}

714
target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
715 716
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
717
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
718

719 720
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCStatus;
721
    else
722
        return other->tcs[other_tc].CP0_TCStatus;
723 724
}

725
target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
726
{
727
    return env->active_tc.CP0_TCBind;
728 729
}

730
target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
731 732
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
733
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
734

735 736
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCBind;
737
    else
738
        return other->tcs[other_tc].CP0_TCBind;
739 740
}

741
target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
742
{
743
    return env->active_tc.PC;
744 745
}

746
target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
747 748
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
749
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
750

751 752
    if (other_tc == other->current_tc)
        return other->active_tc.PC;
753
    else
754
        return other->tcs[other_tc].PC;
755 756
}

757
target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
758
{
759
    return env->active_tc.CP0_TCHalt;
760 761
}

762
target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
763 764
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
765
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
766

767 768
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCHalt;
769
    else
770
        return other->tcs[other_tc].CP0_TCHalt;
771 772
}

773
target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
774
{
775
    return env->active_tc.CP0_TCContext;
776 777
}

778
target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
779 780
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
781
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
782

783 784
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCContext;
785
    else
786
        return other->tcs[other_tc].CP0_TCContext;
787 788
}

789
target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
790
{
791
    return env->active_tc.CP0_TCSchedule;
792 793
}

794
target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
795 796
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
797
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
798

799 800
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCSchedule;
801
    else
802
        return other->tcs[other_tc].CP0_TCSchedule;
803 804
}

805
target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
806
{
807
    return env->active_tc.CP0_TCScheFBack;
808 809
}

810
target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
811 812
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
813
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
814

815 816
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCScheFBack;
817
    else
818
        return other->tcs[other_tc].CP0_TCScheFBack;
819 820
}

821
target_ulong helper_mfc0_count(CPUMIPSState *env)
822
{
823
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
824 825
}

826
target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
827 828
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
829
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
830

831
    return other->CP0_EntryHi;
832 833
}

834
target_ulong helper_mftc0_cause(CPUMIPSState *env)
835 836 837
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    int32_t tccause;
838
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
839 840 841 842 843 844 845 846 847 848

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

    return tccause;
}

849
target_ulong helper_mftc0_status(CPUMIPSState *env)
850 851
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
852
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
853

854
    return other->CP0_Status;
855 856
}

857
target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
858
{
859
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
860 861
}

862
target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
863
{
864
    return (int32_t)env->CP0_WatchLo[sel];
865 866
}

867
target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
868
{
869
    return env->CP0_WatchHi[sel];
870 871
}

872
target_ulong helper_mfc0_debug(CPUMIPSState *env)
873
{
874
    target_ulong t0 = env->CP0_Debug;
875
    if (env->hflags & MIPS_HFLAG_DM)
876 877 878
        t0 |= 1 << CP0DB_DM;

    return t0;
879 880
}

881
target_ulong helper_mftc0_debug(CPUMIPSState *env)
882 883
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
884
    int32_t tcstatus;
885
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
886

887 888
    if (other_tc == other->current_tc)
        tcstatus = other->active_tc.CP0_Debug_tcstatus;
889
    else
890
        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
891 892

    /* XXX: Might be wrong, check with EJTAG spec. */
893
    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
894
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
895 896 897
}

#if defined(TARGET_MIPS64)
898
target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
899
{
900
    return env->active_tc.PC;
901 902
}

903
target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
904
{
905
    return env->active_tc.CP0_TCHalt;
906 907
}

908
target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
909
{
910
    return env->active_tc.CP0_TCContext;
911 912
}

913
target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
914
{
915
    return env->active_tc.CP0_TCSchedule;
916 917
}

918
target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
919
{
920
    return env->active_tc.CP0_TCScheFBack;
921 922
}

923
target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
924
{
925
    return env->lladdr >> env->CP0_LLAddr_shift;
926 927
}

928
target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
929
{
930
    return env->CP0_WatchLo[sel];
931 932 933
}
#endif /* TARGET_MIPS64 */

934
void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
935
{
936 937 938 939 940 941 942 943
    uint32_t index_p = env->CP0_Index & 0x80000000;
    uint32_t tlb_index = arg1 & 0x7fffffff;
    if (tlb_index < env->tlb->nb_tlb) {
        if (env->insn_flags & ISA_MIPS32R6) {
            index_p |= arg1 & 0x80000000;
        }
        env->CP0_Index = index_p | tlb_index;
    }
944 945
}

946
void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
947 948 949 950 951 952 953 954 955
{
    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);
956
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
957 958 959 960 961 962

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

    env->mvp->CP0_MVPControl = newval;
}

963
void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
964 965 966 967 968 969
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
970
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
971 972 973 974 975 976 977 978 979

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

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

980
void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
981 982
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
983
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
984 985 986 987 988 989 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);
    newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);

    /* TODO: Enable/disable TCs.  */

    other->CP0_VPEControl = newval;
}

996
target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
997 998
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
999
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1000 1001 1002 1003
    /* FIXME: Mask away return zero on read bits.  */
    return other->CP0_VPEControl;
}

1004
target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1005 1006
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1007
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1008 1009 1010 1011

    return other->CP0_VPEConf0;
}

1012
void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1013 1014 1015 1016 1017 1018 1019 1020 1021
{
    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);
    }
1022
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1023 1024 1025 1026 1027 1028

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

    env->CP0_VPEConf0 = newval;
}

1029
void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1030 1031
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1032
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
    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;
}

1043
void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1044 1045 1046 1047 1048 1049 1050
{
    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);
1051
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1052 1053 1054 1055 1056 1057 1058 1059 1060

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

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

1061
void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1062 1063 1064 1065 1066
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

1067
void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1068
{
1069
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1070 1071
}

1072 1073
#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)

1074
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1075 1076
{
    /* 1k pages not implemented */
1077
    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1078 1079
    env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
                        | (rxi << (CP0EnLo_XI - 30));
1080 1081
}

1082
#if defined(TARGET_MIPS64)
1083 1084
#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)

1085 1086 1087
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
{
    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1088
    env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1089 1090 1091
}
#endif

1092
void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1093 1094 1095 1096
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

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

1099
    env->active_tc.CP0_TCStatus = newval;
1100
    sync_c0_tcstatus(env, env->current_tc, newval);
1101 1102
}

1103
void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1104 1105
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1106
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1107

1108 1109
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCStatus = arg1;
1110
    else
1111
        other->tcs[other_tc].CP0_TCStatus = arg1;
1112
    sync_c0_tcstatus(other, other_tc, arg1);
1113 1114
}

1115
void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1116 1117 1118 1119 1120 1121
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
1122
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1123
    env->active_tc.CP0_TCBind = newval;
1124 1125
}

1126
void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1127 1128 1129 1130
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;
1131
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1132

1133
    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1134
        mask |= (1 << CP0TCBd_CurVPE);
1135 1136 1137
    if (other_tc == other->current_tc) {
        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
        other->active_tc.CP0_TCBind = newval;
1138
    } else {
1139 1140
        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
        other->tcs[other_tc].CP0_TCBind = newval;
1141
    }
1142 1143
}

1144
void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1145
{
1146
    env->active_tc.PC = arg1;
1147
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1148
    env->lladdr = 0ULL;
1149 1150 1151
    /* MIPS16 not implemented. */
}

1152
void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1153 1154
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1155
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1156

1157 1158 1159 1160
    if (other_tc == other->current_tc) {
        other->active_tc.PC = arg1;
        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1161 1162
        /* MIPS16 not implemented. */
    } else {
1163 1164 1165
        other->tcs[other_tc].PC = arg1;
        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1166 1167
        /* MIPS16 not implemented. */
    }
1168 1169
}

1170
void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1171
{
1172 1173
    MIPSCPU *cpu = mips_env_get_cpu(env);

1174
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1175 1176

    // TODO: Halt TC / Restart (if allocated+active) TC.
1177
    if (env->active_tc.CP0_TCHalt & 1) {
1178
        mips_tc_sleep(cpu, env->current_tc);
1179
    } else {
1180
        mips_tc_wake(cpu, env->current_tc);
1181
    }
1182 1183
}

1184
void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1185 1186
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1187
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1188
    MIPSCPU *other_cpu = mips_env_get_cpu(other);
1189 1190 1191

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

1192 1193
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCHalt = arg1;
1194
    else
1195
        other->tcs[other_tc].CP0_TCHalt = arg1;
1196 1197

    if (arg1 & 1) {
1198
        mips_tc_sleep(other_cpu, other_tc);
1199
    } else {
1200
        mips_tc_wake(other_cpu, other_tc);
1201
    }
1202 1203
}

1204
void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1205
{
1206
    env->active_tc.CP0_TCContext = arg1;
1207 1208
}

1209
void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1210 1211
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1212
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1213

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

1220
void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1221
{
1222
    env->active_tc.CP0_TCSchedule = arg1;
1223 1224
}

1225
void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1226 1227
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1228
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1229

1230 1231
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCSchedule = arg1;
1232
    else
1233
        other->tcs[other_tc].CP0_TCSchedule = arg1;
1234 1235
}

1236
void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1237
{
1238
    env->active_tc.CP0_TCScheFBack = arg1;
1239 1240
}

1241
void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1242 1243
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1244
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1245

1246 1247
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCScheFBack = arg1;
1248
    else
1249
        other->tcs[other_tc].CP0_TCScheFBack = arg1;
1250 1251
}

1252
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1253 1254
{
    /* 1k pages not implemented */
1255
    target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1256 1257
    env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
                        | (rxi << (CP0EnLo_XI - 30));
1258 1259
}

1260 1261 1262 1263
#if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
{
    uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1264
    env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1265 1266 1267
}
#endif

1268
void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1269
{
1270
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1271 1272
}

1273
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1274
{
1275 1276 1277 1278 1279 1280 1281
    uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
    if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
        (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
         mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
         mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
        env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
    }
1282 1283
}

1284
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1285 1286 1287
{
    /* SmartMIPS not implemented */
    /* 1k pages not implemented */
1288 1289
    env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
                         (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
1290 1291
    compute_hflags(env);
    restore_pamask(env);
1292 1293
}

1294
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1295
{
1296 1297 1298 1299 1300 1301 1302
    if (env->insn_flags & ISA_MIPS32R6) {
        if (arg1 < env->tlb->nb_tlb) {
            env->CP0_Wired = arg1;
        }
    } else {
        env->CP0_Wired = arg1 % env->tlb->nb_tlb;
    }
1303 1304
}

1305
void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1306
{
1307
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1308 1309
}

1310
void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1311
{
1312
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1313 1314
}

1315
void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1316
{
1317
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1318 1319
}

1320
void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1321
{
1322
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1323 1324
}

1325
void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1326
{
1327
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1328 1329
}

1330
void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1331
{
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    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;
1345 1346
}

1347
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1348
{
1349
    cpu_mips_store_count(env, arg1);
1350 1351
}

1352
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1353
{
L
Leon Alrae 已提交
1354 1355 1356 1357 1358
    target_ulong old, val, mask;
    mask = (TARGET_PAGE_MASK << 1) | 0xFF;
    if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
        mask |= 1 << CP0EnHi_EHINV;
    }
1359 1360 1361

    /* 1k pages not implemented */
#if defined(TARGET_MIPS64)
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
    if (env->insn_flags & ISA_MIPS32R6) {
        int entryhi_r = extract64(arg1, 62, 2);
        int config0_at = extract32(env->CP0_Config0, 13, 2);
        bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
        if ((entryhi_r == 2) ||
            (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
            /* skip EntryHi.R field if new value is reserved */
            mask &= ~(0x3ull << 62);
        }
    }
    mask &= env->SEGMask;
1373 1374
#endif
    old = env->CP0_EntryHi;
1375
    val = (arg1 & mask) | (old & ~mask);
1376 1377
    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
    uint32_t val, old;
1403

1404
    old = env->CP0_Status;
1405 1406
    cpu_mips_store_status(env, arg1);
    val = env->CP0_Status;
1407

1408 1409 1410 1411 1412 1413 1414 1415 1416
    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;
1417 1418 1419
        default:
            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
            break;
A
Aurelien Jarno 已提交
1420
        }
1421
    }
1422 1423
}

1424
void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1425 1426
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1427
    uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
1428
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1429

1430
    other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
1431
    sync_c0_status(env, other, other_tc);
1432 1433
}

1434
void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1435
{
1436
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1437 1438
}

1439
void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1440 1441
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1442
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1443 1444
}

1445
void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1446
{
1447
    cpu_mips_store_cause(env, arg1);
1448 1449
}

1450
void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1451 1452
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1453
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1454

1455
    cpu_mips_store_cause(other, arg1);
1456 1457
}

1458
target_ulong helper_mftc0_epc(CPUMIPSState *env)
1459 1460
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1461
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1462 1463 1464 1465

    return other->CP0_EPC;
}

1466
target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1467 1468
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1469
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1470 1471 1472 1473

    return other->CP0_EBase;
}

1474
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1475
{
1476
    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1477 1478
}

1479
void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1480 1481
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1482
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1483 1484 1485
    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}

1486
target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1487 1488
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1489
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504

    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;
}

1505
void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1506
{
1507
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1508 1509
}

1510
void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1511 1512 1513 1514 1515
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1516 1517 1518 1519 1520 1521 1522 1523
void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
{
    if (env->insn_flags & ASE_MICROMIPS) {
        env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
                           (arg1 & (1 << CP0C3_ISA_ON_EXC));
    }
}

1524 1525 1526 1527 1528 1529
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);
}

1530 1531 1532 1533
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);
1534
    compute_hflags(env);
1535 1536
}

1537
void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1538 1539 1540 1541 1542 1543
{
    target_long mask = env->CP0_LLAddr_rw_bitmask;
    arg1 = arg1 << env->CP0_LLAddr_shift;
    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
}

1544
void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1545 1546 1547
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1548
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1549 1550
}

1551
void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1552
{
1553 1554
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1555 1556
}

1557
void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1558 1559
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1560
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1561 1562
}

1563
void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1564
{
1565
    env->CP0_Framemask = arg1; /* XXX */
1566 1567
}

1568
void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1569
{
1570 1571
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1572 1573 1574 1575 1576
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1577
void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1578 1579
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1580
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1581
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1582 1583

    /* XXX: Might be wrong, check with EJTAG spec. */
1584 1585
    if (other_tc == other->current_tc)
        other->active_tc.CP0_Debug_tcstatus = val;
1586
    else
1587 1588 1589
        other->tcs[other_tc].CP0_Debug_tcstatus = val;
    other->CP0_Debug = (other->CP0_Debug &
                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1590
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1591 1592
}

1593
void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1594
{
1595
    env->CP0_Performance0 = arg1 & 0x000007ff;
1596 1597
}

1598
void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1599
{
1600
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1601 1602
}

1603
void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1604
{
1605
    env->CP0_DataLo = arg1; /* XXX */
1606 1607
}

1608
void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1609
{
1610
    env->CP0_TagHi = arg1; /* XXX */
1611 1612
}

1613
void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1614
{
1615
    env->CP0_DataHi = arg1; /* XXX */
1616 1617 1618
}

/* MIPS MT functions */
1619
target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1620 1621
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1622
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1623

1624 1625
    if (other_tc == other->current_tc)
        return other->active_tc.gpr[sel];
1626
    else
1627
        return other->tcs[other_tc].gpr[sel];
1628 1629
}

1630
target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1631 1632
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1633
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1634

1635 1636
    if (other_tc == other->current_tc)
        return other->active_tc.LO[sel];
1637
    else
1638
        return other->tcs[other_tc].LO[sel];
1639 1640
}

1641
target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1642 1643
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1644
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1645

1646 1647
    if (other_tc == other->current_tc)
        return other->active_tc.HI[sel];
1648
    else
1649
        return other->tcs[other_tc].HI[sel];
1650 1651
}

1652
target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1653 1654
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1655
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1656

1657 1658
    if (other_tc == other->current_tc)
        return other->active_tc.ACX[sel];
1659
    else
1660
        return other->tcs[other_tc].ACX[sel];
1661 1662
}

1663
target_ulong helper_mftdsp(CPUMIPSState *env)
1664 1665
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1666
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1667

1668 1669
    if (other_tc == other->current_tc)
        return other->active_tc.DSPControl;
1670
    else
1671
        return other->tcs[other_tc].DSPControl;
1672
}
B
bellard 已提交
1673

1674
void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1675 1676
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1677
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1678

1679 1680
    if (other_tc == other->current_tc)
        other->active_tc.gpr[sel] = arg1;
1681
    else
1682
        other->tcs[other_tc].gpr[sel] = arg1;
1683 1684
}

1685
void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1686 1687
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1688
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1689

1690 1691
    if (other_tc == other->current_tc)
        other->active_tc.LO[sel] = arg1;
1692
    else
1693
        other->tcs[other_tc].LO[sel] = arg1;
1694 1695
}

1696
void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1697 1698
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1699
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1700

1701 1702
    if (other_tc == other->current_tc)
        other->active_tc.HI[sel] = arg1;
1703
    else
1704
        other->tcs[other_tc].HI[sel] = arg1;
1705 1706
}

1707
void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1708 1709
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1710
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1711

1712 1713
    if (other_tc == other->current_tc)
        other->active_tc.ACX[sel] = arg1;
1714
    else
1715
        other->tcs[other_tc].ACX[sel] = arg1;
1716 1717
}

1718
void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1719 1720
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1721
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1722

1723 1724
    if (other_tc == other->current_tc)
        other->active_tc.DSPControl = arg1;
1725
    else
1726
        other->tcs[other_tc].DSPControl = arg1;
1727 1728 1729
}

/* MIPS MT functions */
1730
target_ulong helper_dmt(void)
1731 1732
{
    // TODO
1733
     return 0;
1734 1735
}

1736
target_ulong helper_emt(void)
1737 1738
{
    // TODO
1739
    return 0;
1740 1741
}

1742
target_ulong helper_dvpe(CPUMIPSState *env)
1743
{
1744
    CPUState *other_cs = first_cpu;
1745 1746
    target_ulong prev = env->mvp->CP0_MVPControl;

A
Andreas Färber 已提交
1747
    CPU_FOREACH(other_cs) {
1748
        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1749
        /* Turn off all VPEs except the one executing the dvpe.  */
1750 1751
        if (&other_cpu->env != env) {
            other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1752
            mips_vpe_sleep(other_cpu);
1753
        }
A
Andreas Färber 已提交
1754
    }
1755
    return prev;
1756 1757
}

1758
target_ulong helper_evpe(CPUMIPSState *env)
1759
{
1760
    CPUState *other_cs = first_cpu;
1761 1762
    target_ulong prev = env->mvp->CP0_MVPControl;

A
Andreas Färber 已提交
1763
    CPU_FOREACH(other_cs) {
1764
        MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1765

1766
        if (&other_cpu->env != env
1767
            /* If the VPE is WFI, don't disturb its sleep.  */
1768
            && !mips_vpe_is_wfi(other_cpu)) {
1769
            /* Enable the VPE.  */
1770
            other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1771
            mips_vpe_wake(other_cpu); /* And wake it up.  */
1772
        }
A
Andreas Färber 已提交
1773
    }
1774
    return prev;
1775
}
1776
#endif /* !CONFIG_USER_ONLY */
1777

1778
void helper_fork(target_ulong arg1, target_ulong arg2)
1779
{
1780
    // arg1 = rt, arg2 = rs
1781 1782 1783
    // TODO: store to TC register
}

1784
target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
1785
{
B
Blue Swirl 已提交
1786 1787
    target_long arg1 = arg;

1788
    if (arg1 < 0) {
1789
        /* No scheduling policy implemented. */
1790
        if (arg1 != -2) {
1791
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1792
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1793 1794
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1795
                helper_raise_exception(env, EXCP_THREAD);
1796 1797
            }
        }
1798
    } else if (arg1 == 0) {
A
aurel32 已提交
1799
        if (0 /* TODO: TC underflow */) {
1800
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1801
            helper_raise_exception(env, EXCP_THREAD);
1802 1803 1804
        } else {
            // TODO: Deallocate TC
        }
1805
    } else if (arg1 > 0) {
1806 1807 1808
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1809
        helper_raise_exception(env, EXCP_THREAD);
1810
    }
1811
    return env->CP0_YQMask;
1812 1813 1814
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1815
/* TLB management */
1816
static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1817
{
1818 1819
    MIPSCPU *cpu = mips_env_get_cpu(env);

1820
    /* Flush qemu's TLB and discard all shadowed entries.  */
1821
    tlb_flush(CPU(cpu), flush_global);
1822
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1823 1824
}

1825
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1826 1827
{
    /* Discard entries from env->tlb[first] onwards.  */
1828 1829
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1830 1831 1832
    }
}

1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
{
#if defined(TARGET_MIPS64)
    return extract64(entrylo, 6, 54);
#else
    return extract64(entrylo, 6, 24) | /* PFN */
           (extract64(entrylo, 32, 32) << 24); /* PFNX */
#endif
}

1843
static void r4k_fill_tlb(CPUMIPSState *env, int idx)
B
bellard 已提交
1844
{
A
Anthony Liguori 已提交
1845
    r4k_tlb_t *tlb;
B
bellard 已提交
1846 1847

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1848
    tlb = &env->tlb->mmu.r4k.tlb[idx];
L
Leon Alrae 已提交
1849 1850 1851 1852 1853
    if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
        tlb->EHINV = 1;
        return;
    }
    tlb->EHINV = 0;
T
ths 已提交
1854
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1855
#if defined(TARGET_MIPS64)
T
ths 已提交
1856
    tlb->VPN &= env->SEGMask;
1857
#endif
1858
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
1859
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
1860
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1861 1862 1863
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1864 1865
    tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
    tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
1866
    tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12;
1867 1868 1869
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1870 1871
    tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
    tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
1872
    tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12;
B
bellard 已提交
1873 1874
}

L
Leon Alrae 已提交
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
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);
}

1900
void r4k_helper_tlbwi(CPUMIPSState *env)
B
bellard 已提交
1901
{
1902
    r4k_tlb_t *tlb;
A
aurel32 已提交
1903
    int idx;
1904 1905 1906
    target_ulong VPN;
    uint8_t ASID;
    bool G, V0, D0, V1, D1;
A
aurel32 已提交
1907 1908

    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
    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);
    }
1928

A
aurel32 已提交
1929
    r4k_invalidate_tlb(env, idx, 0);
1930
    r4k_fill_tlb(env, idx);
B
bellard 已提交
1931 1932
}

1933
void r4k_helper_tlbwr(CPUMIPSState *env)
B
bellard 已提交
1934 1935 1936
{
    int r = cpu_mips_get_random(env);

1937
    r4k_invalidate_tlb(env, r, 1);
1938
    r4k_fill_tlb(env, r);
B
bellard 已提交
1939 1940
}

1941
void r4k_helper_tlbp(CPUMIPSState *env)
B
bellard 已提交
1942
{
A
Anthony Liguori 已提交
1943
    r4k_tlb_t *tlb;
T
ths 已提交
1944
    target_ulong mask;
B
bellard 已提交
1945
    target_ulong tag;
T
ths 已提交
1946
    target_ulong VPN;
B
bellard 已提交
1947 1948 1949
    uint8_t ASID;
    int i;

B
bellard 已提交
1950
    ASID = env->CP0_EntryHi & 0xFF;
1951 1952
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
1953 1954 1955 1956
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
A
Aurelien Jarno 已提交
1957 1958 1959
#if defined(TARGET_MIPS64)
        tag &= env->SEGMask;
#endif
B
bellard 已提交
1960
        /* Check ASID, virtual page number & size */
L
Leon Alrae 已提交
1961
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
B
bellard 已提交
1962
            /* TLB match */
T
ths 已提交
1963
            env->CP0_Index = i;
B
bellard 已提交
1964 1965 1966
            break;
        }
    }
1967
    if (i == env->tlb->nb_tlb) {
1968
        /* No match.  Discard any shadow entries, if any of them match.  */
1969
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
1970 1971 1972 1973 1974
            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 已提交
1975 1976 1977
#if defined(TARGET_MIPS64)
            tag &= env->SEGMask;
#endif
A
aurel32 已提交
1978 1979
            /* Check ASID, virtual page number & size */
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1980
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
1981 1982 1983
                break;
            }
        }
1984

T
ths 已提交
1985
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
1986 1987 1988
    }
}

1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
{
#if defined(TARGET_MIPS64)
    return tlb_pfn << 6;
#else
    return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
           (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
#endif
}

1999
void r4k_helper_tlbr(CPUMIPSState *env)
B
bellard 已提交
2000
{
A
Anthony Liguori 已提交
2001
    r4k_tlb_t *tlb;
2002
    uint8_t ASID;
A
aurel32 已提交
2003
    int idx;
B
bellard 已提交
2004

2005
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
2006 2007
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
2008 2009

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

2013
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
2014

L
Leon Alrae 已提交
2015 2016 2017 2018 2019 2020 2021 2022 2023
    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) |
2024
                        ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
2025 2026
                        ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
                        get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
L
Leon Alrae 已提交
2027
        env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2028
                        ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
2029 2030
                        ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
                        get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
L
Leon Alrae 已提交
2031
    }
B
bellard 已提交
2032 2033
}

2034
void helper_tlbwi(CPUMIPSState *env)
P
pbrook 已提交
2035
{
2036
    env->tlb->helper_tlbwi(env);
P
pbrook 已提交
2037 2038
}

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

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

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

L
Leon Alrae 已提交
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
void helper_tlbinv(CPUMIPSState *env)
{
    env->tlb->helper_tlbinv(env);
}

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

2064
/* Specials */
2065
target_ulong helper_di(CPUMIPSState *env)
2066
{
2067 2068
    target_ulong t0 = env->CP0_Status;

2069 2070
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
    return t0;
2071 2072
}

2073
target_ulong helper_ei(CPUMIPSState *env)
2074
{
2075 2076
    target_ulong t0 = env->CP0_Status;

2077 2078
    env->CP0_Status = t0 | (1 << CP0St_IE);
    return t0;
2079 2080
}

2081
static void debug_pre_eret(CPUMIPSState *env)
B
bellard 已提交
2082
{
2083
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2084 2085 2086 2087 2088 2089 2090 2091
        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");
    }
2092 2093
}

2094
static void debug_post_eret(CPUMIPSState *env)
2095
{
2096 2097
    MIPSCPU *cpu = mips_env_get_cpu(env);

2098
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
        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;
2109 2110 2111
        default:
            cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
            break;
2112
        }
T
ths 已提交
2113
    }
B
bellard 已提交
2114 2115
}

2116
static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2117 2118 2119 2120 2121 2122 2123 2124 2125
{
    env->active_tc.PC = error_pc & ~(target_ulong)1;
    if (error_pc & 1) {
        env->hflags |= MIPS_HFLAG_M16;
    } else {
        env->hflags &= ~(MIPS_HFLAG_M16);
    }
}

2126
static inline void exception_return(CPUMIPSState *env)
2127
{
2128
    debug_pre_eret(env);
2129
    if (env->CP0_Status & (1 << CP0St_ERL)) {
2130
        set_pc(env, env->CP0_ErrorEPC);
2131 2132
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
2133
        set_pc(env, env->CP0_EPC);
2134 2135 2136
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
2137
    debug_post_eret(env);
2138 2139 2140 2141 2142
}

void helper_eret(CPUMIPSState *env)
{
    exception_return(env);
2143
    env->lladdr = 1;
2144 2145
}

2146 2147 2148 2149 2150
void helper_eretnc(CPUMIPSState *env)
{
    exception_return(env);
}

2151
void helper_deret(CPUMIPSState *env)
2152
{
2153 2154
    debug_pre_eret(env);
    set_pc(env, env->CP0_DEPC);
2155

2156
    env->hflags &= ~MIPS_HFLAG_DM;
2157
    compute_hflags(env);
2158
    debug_post_eret(env);
2159
}
T
ths 已提交
2160
#endif /* !CONFIG_USER_ONLY */
2161

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

2170
    return 0;
2171 2172
}

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

2181
    return 0;
2182 2183
}

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

2192
    return 0;
2193 2194
}

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

2203
    return 0;
2204 2205
}

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

2232
void helper_wait(CPUMIPSState *env)
T
ths 已提交
2233
{
2234 2235 2236
    CPUState *cs = CPU(mips_env_get_cpu(env));

    cs->halted = 1;
2237
    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2238
    helper_raise_exception(env, EXCP_HLT);
T
ths 已提交
2239 2240
}

2241
#if !defined(CONFIG_USER_ONLY)
2242

2243
void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
2244 2245
                                  int access_type, int is_user,
                                  uintptr_t retaddr)
B
bellard 已提交
2246
{
2247 2248
    MIPSCPU *cpu = MIPS_CPU(cs);
    CPUMIPSState *env = &cpu->env;
2249 2250
    int error_code = 0;
    int excp;
2251

B
bellard 已提交
2252
    env->CP0_BadVAddr = addr;
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263

    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 已提交
2264 2265
}

2266
void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2267
              uintptr_t retaddr)
2268 2269 2270
{
    int ret;

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

2276
        do_raise_exception_err(env, cs->exception_index,
2277
                               env->error_code, retaddr);
2278 2279 2280
    }
}

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

2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
    /*
     * 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;
    }

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

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

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

2313
/* convert MIPS rounding mode in FCR31 to IEEE library */
2314
unsigned int ieee_rm[] = {
2315 2316 2317 2318 2319 2320
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

2321
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2322
{
2323
    target_ulong arg1 = 0;
2324

2325 2326
    switch (reg) {
    case 0:
2327
        arg1 = (int32_t)env->active_fpu.fcr0;
2328
        break;
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339
    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;
2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
    case 5:
        /* FRE Support - read Config5.FRE bit */
        if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
            if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
                arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
            } else {
                helper_raise_exception(env, EXCP_RI);
            }
        }
        break;
2350
    case 25:
2351
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2352 2353
        break;
    case 26:
2354
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2355 2356
        break;
    case 28:
2357
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2358 2359
        break;
    default:
2360
        arg1 = (int32_t)env->active_fpu.fcr31;
2361 2362
        break;
    }
2363

2364
    return arg1;
2365 2366
}

2367
void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
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 2393
    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;
2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
    case 5:
        /* FRE Support - clear Config5.FRE bit */
        if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
            return;
        }
        if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
            env->CP0_Config5 &= ~(1 << CP0C5_FRE);
            compute_hflags(env);
        } else {
            helper_raise_exception(env, EXCP_RI);
        }
        break;
    case 6:
        /* FRE Support - set Config5.FRE bit */
        if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
            return;
        }
        if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
            env->CP0_Config5 |= (1 << CP0C5_FRE);
            compute_hflags(env);
        } else {
            helper_raise_exception(env, EXCP_RI);
        }
        break;
2418
    case 25:
2419
        if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
2420
            return;
2421
        }
2422 2423
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2424 2425
        break;
    case 26:
2426
        if (arg1 & 0x007c0000)
2427
            return;
2428
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2429 2430
        break;
    case 28:
2431
        if (arg1 & 0x007c0000)
2432
            return;
2433 2434
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2435 2436
        break;
    case 31:
2437 2438 2439 2440 2441 2442 2443
        if (env->insn_flags & ISA_MIPS32R6) {
            uint32_t mask = 0xfefc0000;
            env->active_fpu.fcr31 = (arg1 & ~mask) |
                (env->active_fpu.fcr31 & mask);
        } else if (!(arg1 & 0x007c0000)) {
            env->active_fpu.fcr31 = arg1;
        }
2444 2445 2446 2447 2448
        break;
    default:
        return;
    }
    /* set rounding mode */
2449
    restore_rounding_mode(env);
2450
    /* set flush-to-zero mode */
2451
    restore_flush_mode(env);
2452 2453
    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))
2454
        do_raise_exception(env, EXCP_FPE, GETPC());
2455 2456
}

2457
int ieee_ex_to_mips(int xcpt)
2458
{
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477
    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;
2478 2479
}

2480
static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2481
{
2482
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2483

2484
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2485 2486 2487 2488 2489

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

        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2490
            do_raise_exception(env, EXCP_FPE, pc);
2491 2492 2493 2494
        } else {
            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
        }
    }
2495 2496
}

2497 2498 2499 2500 2501 2502
/* 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  */
2503
uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2504
{
A
Aurelien Jarno 已提交
2505
    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2506
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2507
    return fdt0;
2508 2509
}

2510
uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2511
{
A
Aurelien Jarno 已提交
2512
    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2513
    update_fcr31(env, GETPC());
A
Aurelien Jarno 已提交
2514
    return fst0;
2515
}
2516

2517
uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2518
{
2519 2520
    uint64_t fdt2;

2521
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2522
    update_fcr31(env, GETPC());
2523
    return fdt2;
2524
}
2525

2526
uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2527
{
2528 2529
    uint64_t fdt2;

2530
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2531
    update_fcr31(env, GETPC());
2532
    return fdt2;
2533
}
2534

2535
uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2536
{
2537 2538
    uint64_t fdt2;

2539
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2540
    update_fcr31(env, GETPC());
2541
    return fdt2;
2542
}
2543

2544
uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
2545
{
2546 2547
    uint64_t dt2;

2548
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2549 2550
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2551
        dt2 = FP_TO_INT64_OVERFLOW;
2552
    }
2553
    update_fcr31(env, GETPC());
2554
    return dt2;
2555
}
2556

2557
uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
2558
{
2559 2560
    uint64_t dt2;

2561
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2562 2563
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2564
        dt2 = FP_TO_INT64_OVERFLOW;
2565
    }
2566
    update_fcr31(env, GETPC());
2567
    return dt2;
2568 2569
}

2570
uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2571
{
2572 2573 2574
    uint32_t fst2;
    uint32_t fsth2;

2575 2576
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2577
    update_fcr31(env, GETPC());
2578
    return ((uint64_t)fsth2 << 32) | fst2;
2579
}
2580

2581
uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2582
{
2583 2584
    uint32_t wt2;
    uint32_t wth2;
A
Aurelien Jarno 已提交
2585
    int excp, excph;
2586

2587
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
A
Aurelien Jarno 已提交
2588 2589
    excp = get_float_exception_flags(&env->active_fpu.fp_status);
    if (excp & (float_flag_overflow | float_flag_invalid)) {
2590
        wt2 = FP_TO_INT32_OVERFLOW;
A
Aurelien Jarno 已提交
2591 2592 2593 2594 2595 2596
    }

    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)) {
2597
        wth2 = FP_TO_INT32_OVERFLOW;
2598
    }
A
Aurelien Jarno 已提交
2599 2600

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

2603
    return ((uint64_t)wth2 << 32) | wt2;
2604
}
2605

2606
uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2607
{
2608 2609
    uint32_t fst2;

2610
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2611
    update_fcr31(env, GETPC());
2612
    return fst2;
2613
}
2614

2615
uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2616
{
2617 2618
    uint32_t fst2;

2619
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2620
    update_fcr31(env, GETPC());
2621
    return fst2;
2622
}
2623

2624
uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2625
{
2626 2627
    uint32_t fst2;

2628
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2629
    update_fcr31(env, GETPC());
2630
    return fst2;
2631
}
2632

2633
uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2634
{
2635 2636 2637
    uint32_t wt2;

    wt2 = wt0;
2638
    update_fcr31(env, GETPC());
2639
    return wt2;
2640
}
2641

2642
uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2643
{
2644 2645 2646
    uint32_t wt2;

    wt2 = wth0;
2647
    update_fcr31(env, GETPC());
2648
    return wt2;
2649
}
2650

2651
uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
2652
{
2653 2654
    uint32_t wt2;

2655
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2656 2657
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2658
        wt2 = FP_TO_INT32_OVERFLOW;
2659
    }
2660
    update_fcr31(env, GETPC());
2661
    return wt2;
2662
}
2663

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

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

2677
uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
2678
{
2679 2680
    uint64_t dt2;

2681 2682
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2687
    }
2688
    update_fcr31(env, GETPC());
2689
    return dt2;
2690
}
2691

2692
uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
2693
{
2694 2695
    uint64_t dt2;

2696 2697
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2702
    }
2703
    update_fcr31(env, GETPC());
2704
    return dt2;
2705
}
2706

2707
uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
2708
{
2709 2710
    uint32_t wt2;

2711 2712
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2713
    restore_rounding_mode(env);
2714 2715
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2716
        wt2 = FP_TO_INT32_OVERFLOW;
2717
    }
2718
    update_fcr31(env, GETPC());
2719
    return wt2;
2720
}
2721

2722
uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
2723
{
2724 2725
    uint32_t wt2;

2726 2727
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2728
    restore_rounding_mode(env);
2729 2730
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2731
        wt2 = FP_TO_INT32_OVERFLOW;
2732
    }
2733
    update_fcr31(env, GETPC());
2734
    return wt2;
2735 2736
}

2737
uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
2738
{
2739 2740
    uint64_t dt2;

2741
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2742 2743
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2744
        dt2 = FP_TO_INT64_OVERFLOW;
2745
    }
2746
    update_fcr31(env, GETPC());
2747
    return dt2;
2748
}
2749

2750
uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
2751
{
2752 2753
    uint64_t dt2;

2754
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2755 2756
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2757
        dt2 = FP_TO_INT64_OVERFLOW;
2758
    }
2759
    update_fcr31(env, GETPC());
2760
    return dt2;
2761
}
2762

2763
uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
2764
{
2765 2766
    uint32_t wt2;

2767
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2768 2769
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2770
        wt2 = FP_TO_INT32_OVERFLOW;
2771
    }
2772
    update_fcr31(env, GETPC());
2773
    return wt2;
2774
}
2775

2776
uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
2777
{
2778 2779
    uint32_t wt2;

2780
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2781 2782
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2783
        wt2 = FP_TO_INT32_OVERFLOW;
2784
    }
2785
    update_fcr31(env, GETPC());
2786
    return wt2;
2787 2788
}

2789
uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
2790
{
2791 2792
    uint64_t dt2;

2793 2794
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2799
    }
2800
    update_fcr31(env, GETPC());
2801
    return dt2;
2802
}
2803

2804
uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
2805
{
2806 2807
    uint64_t dt2;

2808 2809
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2814
    }
2815
    update_fcr31(env, GETPC());
2816
    return dt2;
2817
}
2818

2819
uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
2820
{
2821 2822
    uint32_t wt2;

2823 2824
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(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
        wt2 = FP_TO_INT32_OVERFLOW;
2829
    }
2830
    update_fcr31(env, GETPC());
2831
    return wt2;
2832
}
2833

2834
uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
2835
{
2836 2837
    uint32_t wt2;

2838 2839
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(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
        wt2 = FP_TO_INT32_OVERFLOW;
2844
    }
2845
    update_fcr31(env, GETPC());
2846
    return wt2;
2847 2848
}

2849
uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
2850
{
2851 2852
    uint64_t dt2;

2853 2854
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2859
    }
2860
    update_fcr31(env, GETPC());
2861
    return dt2;
2862
}
2863

2864
uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
2865
{
2866 2867
    uint64_t dt2;

2868 2869
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(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
        dt2 = FP_TO_INT64_OVERFLOW;
2874
    }
2875
    update_fcr31(env, GETPC());
2876
    return dt2;
2877
}
2878

2879
uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
2880
{
2881 2882
    uint32_t wt2;

2883 2884
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2885
    restore_rounding_mode(env);
2886 2887
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2888
        wt2 = FP_TO_INT32_OVERFLOW;
2889
    }
2890
    update_fcr31(env, GETPC());
2891
    return wt2;
2892
}
2893

2894
uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
2895
{
2896 2897
    uint32_t wt2;

2898 2899
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2900
    restore_rounding_mode(env);
2901 2902
    if (get_float_exception_flags(&env->active_fpu.fp_status)
        & (float_flag_invalid | float_flag_overflow)) {
2903
        wt2 = FP_TO_INT32_OVERFLOW;
2904
    }
2905
    update_fcr31(env, GETPC());
2906
    return wt2;
2907 2908
}

2909
/* unary operations, not modifying fp status  */
2910
#define FLOAT_UNOP(name)                                       \
2911
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2912 2913 2914
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2915
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2916 2917 2918
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2919
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2920 2921 2922 2923 2924 2925 2926
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2927 2928 2929 2930 2931
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

T
ths 已提交
2932
/* MIPS specific unary operations */
2933
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2934
{
2935 2936
    uint64_t fdt2;

2937
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
2938
    update_fcr31(env, GETPC());
2939
    return fdt2;
T
ths 已提交
2940
}
2941

2942
uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2943
{
2944 2945
    uint32_t fst2;

2946
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
2947
    update_fcr31(env, GETPC());
2948
    return fst2;
T
ths 已提交
2949 2950
}

2951
uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2952
{
2953 2954
    uint64_t fdt2;

2955
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2956
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
2957
    update_fcr31(env, GETPC());
2958
    return fdt2;
T
ths 已提交
2959
}
2960

2961
uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2962
{
2963 2964
    uint32_t fst2;

2965
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2966
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2967
    update_fcr31(env, GETPC());
2968
    return fst2;
T
ths 已提交
2969 2970
}

2971
uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2972
{
2973 2974
    uint64_t fdt2;

2975
    fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
2976
    update_fcr31(env, GETPC());
2977
    return fdt2;
T
ths 已提交
2978
}
2979

2980
uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2981
{
2982 2983
    uint32_t fst2;

2984
    fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
2985
    update_fcr31(env, GETPC());
2986
    return fst2;
T
ths 已提交
2987
}
2988

2989
uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2990
{
2991 2992 2993
    uint32_t fst2;
    uint32_t fsth2;

2994 2995
    fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
2996
    update_fcr31(env, GETPC());
2997
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2998 2999
}

3000
uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3001
{
3002 3003
    uint64_t fdt2;

3004
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3005
    fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3006
    update_fcr31(env, GETPC());
3007
    return fdt2;
T
ths 已提交
3008
}
3009

3010
uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
3011
{
3012 3013
    uint32_t fst2;

3014
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3015
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3016
    update_fcr31(env, GETPC());
3017
    return fst2;
T
ths 已提交
3018
}
3019

3020
uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
3021
{
3022 3023 3024
    uint32_t fst2;
    uint32_t fsth2;

3025 3026
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3027 3028
    fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3029
    update_fcr31(env, GETPC());
3030
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3031 3032
}

3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092
#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

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

3132 3133 3134 3135 3136 3137
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

T
ths 已提交
3138
/* MIPS specific binary operations */
3139
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3140
{
3141
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3142
    fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3143
    update_fcr31(env, GETPC());
3144
    return fdt2;
T
ths 已提交
3145
}
3146

3147
uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3148
{
3149
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3150
    fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3151
    update_fcr31(env, GETPC());
3152
    return fst2;
T
ths 已提交
3153
}
3154

3155
uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3156
{
3157 3158 3159 3160 3161
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3162 3163
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3164 3165
    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));
3166
    update_fcr31(env, GETPC());
3167
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3168 3169
}

3170
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3171
{
3172
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3173
    fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3174
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3175
    update_fcr31(env, GETPC());
3176
    return fdt2;
T
ths 已提交
3177
}
3178

3179
uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3180
{
3181
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3182
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3183
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3184
    update_fcr31(env, GETPC());
3185
    return fst2;
T
ths 已提交
3186
}
3187

3188
uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3189
{
3190 3191 3192 3193 3194
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3195 3196
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3197 3198
    fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
    fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3199 3200
    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));
3201
    update_fcr31(env, GETPC());
3202
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3203 3204
}

3205
uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3206
{
3207 3208 3209 3210 3211 3212 3213
    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;

3214 3215
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3216
    update_fcr31(env, GETPC());
3217
    return ((uint64_t)fsth2 << 32) | fst2;
3218 3219
}

3220
uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
3221
{
3222 3223 3224 3225 3226 3227 3228
    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;

3229 3230
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3231
    update_fcr31(env, GETPC());
3232
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3233 3234
}

3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334
#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

/* ternary operations */
#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);                                         \
    }                                                                \
}

/* 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)                  \
{                                                                    \
    UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
    update_fcr31(env, GETPC());                                      \
    return fdt0;                                                     \
}                                                                    \
                                                                     \
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
                                     uint32_t fst0, uint32_t fst1,   \
                                     uint32_t fst2)                  \
{                                                                    \
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
    update_fcr31(env, GETPC());                                      \
    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;                                     \
                                                                     \
    UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
    UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
    update_fcr31(env, GETPC());                                      \
    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

#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

T
ths 已提交
3335
/* compare operations */
3336
#define FOP_COND_D(op, cond)                                   \
3337 3338
void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                         uint64_t fdt1, int cc)                \
3339
{                                                              \
3340 3341
    int c;                                                     \
    c = cond;                                                  \
3342
    update_fcr31(env, GETPC());                                \
3343
    if (c)                                                     \
3344
        SET_FP_COND(cc, env->active_fpu);                      \
3345
    else                                                       \
3346
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3347
}                                                              \
3348 3349
void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                            uint64_t fdt1, int cc)             \
3350 3351 3352 3353 3354
{                                                              \
    int c;                                                     \
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
3355
    update_fcr31(env, GETPC());                                \
3356
    if (c)                                                     \
3357
        SET_FP_COND(cc, env->active_fpu);                      \
3358
    else                                                       \
3359
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3360 3361 3362
}

/* NOTE: the comma operator will make "cond" to eval to false,
3363 3364 3365
 * 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))
3366
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3367
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3368 3369 3370 3371
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))
3372
/* NOTE: the comma operator will make "cond" to eval to false,
3373 3374 3375
 * 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))
3376 3377 3378
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))
3379
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3380
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3381
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3382 3383

#define FOP_COND_S(op, cond)                                   \
3384 3385
void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
                         uint32_t fst1, int cc)                \
3386
{                                                              \
3387 3388
    int c;                                                     \
    c = cond;                                                  \
3389
    update_fcr31(env, GETPC());                                \
3390
    if (c)                                                     \
3391
        SET_FP_COND(cc, env->active_fpu);                      \
3392
    else                                                       \
3393
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3394
}                                                              \
3395 3396
void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
                            uint32_t fst1, int cc)             \
3397 3398 3399 3400 3401
{                                                              \
    int c;                                                     \
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
3402
    update_fcr31(env, GETPC());                                \
3403
    if (c)                                                     \
3404
        SET_FP_COND(cc, env->active_fpu);                      \
3405
    else                                                       \
3406
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3407 3408 3409
}

/* NOTE: the comma operator will make "cond" to eval to false,
3410 3411 3412
 * 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))
3413
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3414
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3415 3416 3417 3418
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))
3419
/* NOTE: the comma operator will make "cond" to eval to false,
3420 3421 3422
 * 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))
3423 3424 3425
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))
3426
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3427
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3428
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3429 3430

#define FOP_COND_PS(op, condl, condh)                           \
3431 3432
void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                          uint64_t fdt1, int cc)                \
3433
{                                                               \
3434 3435 3436 3437 3438 3439 3440 3441
    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;                                                 \
3442
    update_fcr31(env, GETPC());                                 \
3443
    if (cl)                                                     \
3444
        SET_FP_COND(cc, env->active_fpu);                       \
3445
    else                                                        \
3446
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3447
    if (ch)                                                     \
3448
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3449
    else                                                        \
3450
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3451
}                                                               \
3452 3453
void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                             uint64_t fdt1, int cc)             \
3454
{                                                               \
3455 3456 3457 3458 3459 3460 3461 3462
    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;                                                 \
3463
    update_fcr31(env, GETPC());                                 \
3464
    if (cl)                                                     \
3465
        SET_FP_COND(cc, env->active_fpu);                       \
3466
    else                                                        \
3467
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3468
    if (ch)                                                     \
3469
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3470
    else                                                        \
3471
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3472 3473 3474
}

/* NOTE: the comma operator will make "cond" to eval to false,
3475 3476 3477 3478 3479
 * 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))
3480 3481
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3482 3483
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))
3484 3485 3486 3487 3488 3489 3490 3491
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))
3492
/* NOTE: the comma operator will make "cond" to eval to false,
3493 3494 3495 3496 3497
 * 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))
3498 3499 3500 3501 3502 3503
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))
3504 3505
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))
3506 3507
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3508 3509
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))
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 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620

/* 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)))
3621 3622 3623 3624 3625 3626 3627 3628

/* MSA */
/* Data format min and max values */
#define DF_BITS(df) (1 << ((df) + 3))

/* Element-by-element access macros */
#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))

3629 3630 3631
#if !defined(CONFIG_USER_ONLY)
#define MEMOP_IDX(DF)                                           \
        TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN,  \
3632
                                        cpu_mmu_index(env, false));
3633 3634 3635
#else
#define MEMOP_IDX(DF)
#endif
3636

3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
#define MSA_LD_DF(DF, TYPE, LD_INSN, ...)                               \
void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
                            target_ulong addr)                          \
{                                                                       \
    wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
    wr_t wx;                                                            \
    int i;                                                              \
    MEMOP_IDX(DF)                                                       \
    for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
        wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__);     \
    }                                                                   \
    memcpy(pwd, &wx, sizeof(wr_t));                                     \
3649 3650
}

3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661
#if !defined(CONFIG_USER_ONLY)
MSA_LD_DF(DF_BYTE,   b, helper_ret_ldub_mmu, oi, GETRA())
MSA_LD_DF(DF_HALF,   h, helper_ret_lduw_mmu, oi, GETRA())
MSA_LD_DF(DF_WORD,   w, helper_ret_ldul_mmu, oi, GETRA())
MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu,  oi, GETRA())
#else
MSA_LD_DF(DF_BYTE,   b, cpu_ldub_data)
MSA_LD_DF(DF_HALF,   h, cpu_lduw_data)
MSA_LD_DF(DF_WORD,   w, cpu_ldl_data)
MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
#endif
3662

3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678
#define MSA_PAGESPAN(x) \
        ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)

static inline void ensure_writable_pages(CPUMIPSState *env,
                                         target_ulong addr,
                                         int mmu_idx,
                                         uintptr_t retaddr)
{
#if !defined(CONFIG_USER_ONLY)
    target_ulong page_addr;
    if (unlikely(MSA_PAGESPAN(addr))) {
        /* first page */
        probe_write(env, addr, mmu_idx, retaddr);
        /* second page */
        page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
        probe_write(env, page_addr, mmu_idx, retaddr);
3679
    }
3680
#endif
3681
}
3682 3683 3684 3685 3686 3687

#define MSA_ST_DF(DF, TYPE, ST_INSN, ...)                               \
void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
                            target_ulong addr)                          \
{                                                                       \
    wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
3688
    int mmu_idx = cpu_mmu_index(env, false);				\
3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707
    int i;                                                              \
    MEMOP_IDX(DF)                                                       \
    ensure_writable_pages(env, addr, mmu_idx, GETRA());                 \
    for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
        ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__);    \
    }                                                                   \
}

#if !defined(CONFIG_USER_ONLY)
MSA_ST_DF(DF_BYTE,   b, helper_ret_stb_mmu, oi, GETRA())
MSA_ST_DF(DF_HALF,   h, helper_ret_stw_mmu, oi, GETRA())
MSA_ST_DF(DF_WORD,   w, helper_ret_stl_mmu, oi, GETRA())
MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA())
#else
MSA_ST_DF(DF_BYTE,   b, cpu_stb_data)
MSA_ST_DF(DF_HALF,   h, cpu_stw_data)
MSA_ST_DF(DF_WORD,   w, cpu_stl_data)
MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
#endif