op_helper.c 105.5 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  MIPS emulation helpers for qemu.
3
 *
B
bellard 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16
 *  Copyright (c) 2004-2005 Jocelyn Mayer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
18
 */
19
#include <stdlib.h>
B
Blue Swirl 已提交
20 21
#include "cpu.h"
#include "dyngen-exec.h"
B
bellard 已提交
22

23 24
#include "host-utils.h"

P
pbrook 已提交
25
#include "helper.h"
26

B
Blue Swirl 已提交
27 28 29 30
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */

31
#ifndef CONFIG_USER_ONLY
32
static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
33 34
#endif

35
static inline void compute_hflags(CPUMIPSState *env)
B
Blue Swirl 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
{
    env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
                     MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
                     MIPS_HFLAG_UX);
    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
        !(env->CP0_Status & (1 << CP0St_ERL)) &&
        !(env->hflags & MIPS_HFLAG_DM)) {
        env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
    }
#if defined(TARGET_MIPS64)
    if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
        (env->CP0_Status & (1 << CP0St_PX)) ||
        (env->CP0_Status & (1 << CP0St_UX))) {
        env->hflags |= MIPS_HFLAG_64;
    }
    if (env->CP0_Status & (1 << CP0St_UX)) {
        env->hflags |= MIPS_HFLAG_UX;
    }
#endif
    if ((env->CP0_Status & (1 << CP0St_CU0)) ||
        !(env->hflags & MIPS_HFLAG_KSU)) {
        env->hflags |= MIPS_HFLAG_CP0;
    }
    if (env->CP0_Status & (1 << CP0St_CU1)) {
        env->hflags |= MIPS_HFLAG_FPU;
    }
    if (env->CP0_Status & (1 << CP0St_FR)) {
        env->hflags |= MIPS_HFLAG_F64;
    }
    if (env->insn_flags & ISA_MIPS32R2) {
        if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
            env->hflags |= MIPS_HFLAG_COP1X;
        }
    } else if (env->insn_flags & ISA_MIPS32) {
        if (env->hflags & MIPS_HFLAG_64) {
            env->hflags |= MIPS_HFLAG_COP1X;
        }
    } else if (env->insn_flags & ISA_MIPS4) {
        /* All supported MIPS IV CPUs use the XX (CU3) to enable
           and disable the MIPS IV extensions to the MIPS III ISA.
           Some other MIPS IV CPUs ignore the bit, so the check here
           would be too restrictive for them.  */
        if (env->CP0_Status & (1 << CP0St_CU3)) {
            env->hflags |= MIPS_HFLAG_COP1X;
        }
    }
}

B
bellard 已提交
84 85 86
/*****************************************************************************/
/* Exceptions processing helpers */

87
void helper_raise_exception_err (uint32_t exception, int error_code)
B
bellard 已提交
88 89
{
#if 1
90 91
    if (exception < 0x100)
        qemu_log("%s: %d %d\n", __func__, exception, error_code);
B
bellard 已提交
92 93 94
#endif
    env->exception_index = exception;
    env->error_code = error_code;
B
Blue Swirl 已提交
95
    cpu_loop_exit(env);
B
bellard 已提交
96 97
}

98
void helper_raise_exception (uint32_t exception)
B
bellard 已提交
99
{
100
    helper_raise_exception_err(exception, 0);
B
bellard 已提交
101 102
}

103
#if !defined(CONFIG_USER_ONLY)
104
static void do_restore_state(uintptr_t pc)
B
bellard 已提交
105
{
B
bellard 已提交
106
    TranslationBlock *tb;
107

B
bellard 已提交
108 109
    tb = tb_find_pc (pc);
    if (tb) {
110
        cpu_restore_state(tb, env, pc);
B
bellard 已提交
111
    }
B
bellard 已提交
112
}
113
#endif
B
bellard 已提交
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
#if defined(CONFIG_USER_ONLY)
#define HELPER_LD(name, insn, type)                                     \
static inline type do_##name(target_ulong addr, int mem_idx)            \
{                                                                       \
    return (type) insn##_raw(addr);                                     \
}
#else
#define HELPER_LD(name, insn, type)                                     \
static inline type do_##name(target_ulong addr, int mem_idx)            \
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
    case 0: return (type) insn##_kernel(addr); break;                   \
    case 1: return (type) insn##_super(addr); break;                    \
    default:                                                            \
    case 2: return (type) insn##_user(addr); break;                     \
    }                                                                   \
}
#endif
HELPER_LD(lbu, ldub, uint8_t)
HELPER_LD(lw, ldl, int32_t)
#ifdef TARGET_MIPS64
HELPER_LD(ld, ldq, int64_t)
#endif
#undef HELPER_LD

#if defined(CONFIG_USER_ONLY)
#define HELPER_ST(name, insn, type)                                     \
static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
{                                                                       \
    insn##_raw(addr, val);                                              \
}
#else
#define HELPER_ST(name, insn, type)                                     \
static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
    case 0: insn##_kernel(addr, val); break;                            \
    case 1: insn##_super(addr, val); break;                             \
    default:                                                            \
    case 2: insn##_user(addr, val); break;                              \
    }                                                                   \
}
#endif
HELPER_ST(sb, stb, uint8_t)
HELPER_ST(sw, stl, uint32_t)
#ifdef TARGET_MIPS64
HELPER_ST(sd, stq, uint64_t)
#endif
#undef HELPER_ST

167
target_ulong helper_clo (target_ulong arg1)
168
{
169
    return clo32(arg1);
170 171
}

172
target_ulong helper_clz (target_ulong arg1)
173
{
174
    return clz32(arg1);
175 176
}

177
#if defined(TARGET_MIPS64)
178
target_ulong helper_dclo (target_ulong arg1)
179
{
180
    return clo64(arg1);
181 182
}

183
target_ulong helper_dclz (target_ulong arg1)
184
{
185
    return clz64(arg1);
186
}
187
#endif /* TARGET_MIPS64 */
188

B
bellard 已提交
189
/* 64 bits arithmetic for 32 bits hosts */
T
ths 已提交
190
static inline uint64_t get_HILO (void)
B
bellard 已提交
191
{
192
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
B
bellard 已提交
193 194
}

195
static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
196
{
197
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
198
    arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
199 200
}

201
static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
202
{
203
    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
204
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
205 206 207
}

/* Multiplication variants of the vr54xx. */
208
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
209
{
210
    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
211

212
    return arg1;
213 214
}

215
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
216
{
217
    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
218

219
    return arg1;
220 221
}

222
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
223
{
224
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
225

226
    return arg1;
227 228
}

229
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
230
{
231
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
232

233
    return arg1;
234 235
}

236
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
237
{
238
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
239

240
    return arg1;
241 242
}

243
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
244
{
245
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
246

247
    return arg1;
248 249
}

250
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
251
{
252
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
253

254
    return arg1;
255 256
}

257
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
258
{
259
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
260

261
    return arg1;
262 263
}

264
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
265
{
266
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
267

268
    return arg1;
269 270
}

271
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
272
{
273
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
274

275
    return arg1;
276 277
}

278
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
279
{
280
    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
281

282
    return arg1;
283 284
}

285
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
286
{
287
    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
288

289
    return arg1;
290 291
}

292
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
293
{
294
    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
295

296
    return arg1;
297 298
}

299
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
300
{
301
    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
302

303
    return arg1;
304
}
B
bellard 已提交
305

306
#ifdef TARGET_MIPS64
307
void helper_dmult (target_ulong arg1, target_ulong arg2)
308
{
309
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
310 311
}

312
void helper_dmultu (target_ulong arg1, target_ulong arg2)
313
{
314
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
315 316 317
}
#endif

318
#ifndef CONFIG_USER_ONLY
319 320 321 322 323 324 325 326

static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
{
    target_phys_addr_t lladdr;

    lladdr = cpu_mips_translate_address(env, address, rw);

    if (lladdr == -1LL) {
B
Blue Swirl 已提交
327
        cpu_loop_exit(env);
328 329 330 331 332
    } else {
        return lladdr;
    }
}

333 334 335
#define HELPER_LD_ATOMIC(name, insn)                                          \
target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
{                                                                             \
336
    env->lladdr = do_translate_address(arg, 0);                               \
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
    env->llval = do_##insn(arg, mem_idx);                                     \
    return env->llval;                                                        \
}
HELPER_LD_ATOMIC(ll, lw)
#ifdef TARGET_MIPS64
HELPER_LD_ATOMIC(lld, ld)
#endif
#undef HELPER_LD_ATOMIC

#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
{                                                                             \
    target_long tmp;                                                          \
                                                                              \
    if (arg2 & almask) {                                                      \
        env->CP0_BadVAddr = arg2;                                             \
        helper_raise_exception(EXCP_AdES);                                    \
    }                                                                         \
355
    if (do_translate_address(arg2, 1) == env->lladdr) {                       \
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
        tmp = do_##ld_insn(arg2, mem_idx);                                    \
        if (tmp == env->llval) {                                              \
            do_##st_insn(arg2, arg1, mem_idx);                                \
            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 已提交
371 372 373 374 375 376 377 378
#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

379
target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
380 381 382
{
    target_ulong tmp;

383
    tmp = do_lbu(arg2, mem_idx);
384
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
385

386
    if (GET_LMASK(arg2) <= 2) {
387
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
388
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
389 390
    }

391
    if (GET_LMASK(arg2) <= 1) {
392
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
393
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
394 395
    }

396
    if (GET_LMASK(arg2) == 0) {
397
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
398
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
399
    }
400
    return (int32_t)arg1;
T
ths 已提交
401 402
}

403
target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
404 405 406
{
    target_ulong tmp;

407
    tmp = do_lbu(arg2, mem_idx);
408
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
409

410
    if (GET_LMASK(arg2) >= 1) {
411
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
412
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
413 414
    }

415
    if (GET_LMASK(arg2) >= 2) {
416
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
417
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
418 419
    }

420
    if (GET_LMASK(arg2) == 3) {
421
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
422
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
423
    }
424
    return (int32_t)arg1;
T
ths 已提交
425 426
}

427
void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
428
{
429
    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
430

431
    if (GET_LMASK(arg2) <= 2)
432
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
433

434
    if (GET_LMASK(arg2) <= 1)
435
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
436

437
    if (GET_LMASK(arg2) == 0)
438
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
T
ths 已提交
439 440
}

441
void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
442
{
443
    do_sb(arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
444

445
    if (GET_LMASK(arg2) >= 1)
446
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
447

448
    if (GET_LMASK(arg2) >= 2)
449
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
450

451
    if (GET_LMASK(arg2) == 3)
452
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
453 454 455 456 457 458 459 460 461 462 463 464
}

#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

465
target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
466 467 468
{
    uint64_t tmp;

469
    tmp = do_lbu(arg2, mem_idx);
470
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
471

472
    if (GET_LMASK64(arg2) <= 6) {
473
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
474
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
475 476
    }

477
    if (GET_LMASK64(arg2) <= 5) {
478
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
479
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
480 481
    }

482
    if (GET_LMASK64(arg2) <= 4) {
483
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
484
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
485 486
    }

487
    if (GET_LMASK64(arg2) <= 3) {
488
        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
489
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
490 491
    }

492
    if (GET_LMASK64(arg2) <= 2) {
493
        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
494
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
495 496
    }

497
    if (GET_LMASK64(arg2) <= 1) {
498
        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
499
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
T
ths 已提交
500 501
    }

502
    if (GET_LMASK64(arg2) == 0) {
503
        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
504
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
505
    }
506

507
    return arg1;
T
ths 已提交
508 509
}

510
target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
511 512 513
{
    uint64_t tmp;

514
    tmp = do_lbu(arg2, mem_idx);
515
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
516

517
    if (GET_LMASK64(arg2) >= 1) {
518
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
519
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
T
ths 已提交
520 521
    }

522
    if (GET_LMASK64(arg2) >= 2) {
523
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
524
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
525 526
    }

527
    if (GET_LMASK64(arg2) >= 3) {
528
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
529
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
530 531
    }

532
    if (GET_LMASK64(arg2) >= 4) {
533
        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
534
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
535 536
    }

537
    if (GET_LMASK64(arg2) >= 5) {
538
        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
539
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
540 541
    }

542
    if (GET_LMASK64(arg2) >= 6) {
543
        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
544
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
545 546
    }

547
    if (GET_LMASK64(arg2) == 7) {
548
        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
549
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
550
    }
551

552
    return arg1;
T
ths 已提交
553 554
}

555
void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
556
{
557
    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
558

559
    if (GET_LMASK64(arg2) <= 6)
560
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
561

562
    if (GET_LMASK64(arg2) <= 5)
563
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
564

565
    if (GET_LMASK64(arg2) <= 4)
566
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
567

568
    if (GET_LMASK64(arg2) <= 3)
569
        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
570

571
    if (GET_LMASK64(arg2) <= 2)
572
        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
573

574
    if (GET_LMASK64(arg2) <= 1)
575
        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
576

577
    if (GET_LMASK64(arg2) <= 0)
578
        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
T
ths 已提交
579 580
}

581
void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
582
{
583
    do_sb(arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
584

585
    if (GET_LMASK64(arg2) >= 1)
586
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
587

588
    if (GET_LMASK64(arg2) >= 2)
589
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
590

591
    if (GET_LMASK64(arg2) >= 3)
592
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
593

594
    if (GET_LMASK64(arg2) >= 4)
595
        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
596

597
    if (GET_LMASK64(arg2) >= 5)
598
        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
599

600
    if (GET_LMASK64(arg2) >= 6)
601
        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
602

603
    if (GET_LMASK64(arg2) == 7)
604
        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
605 606 607
}
#endif /* TARGET_MIPS64 */

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };

void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef ldfun
#define ldfun ldl_raw
#else
    uint32_t (*ldfun)(target_ulong);

    switch (mem_idx)
    {
    case 0: ldfun = ldl_kernel; break;
    case 1: ldfun = ldl_super; break;
    default:
    case 2: ldfun = ldl_user; break;
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
            addr += 4;
        }
    }

    if (do_r31) {
        env->active_tc.gpr[31] = (target_long) ldfun(addr);
    }
}

void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef stfun
#define stfun stl_raw
#else
    void (*stfun)(target_ulong, uint32_t);

    switch (mem_idx)
    {
    case 0: stfun = stl_kernel; break;
    case 1: stfun = stl_super; break;
     default:
    case 2: stfun = stl_user; break;
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
            addr += 4;
        }
    }

    if (do_r31) {
        stfun(addr, env->active_tc.gpr[31]);
    }
}

#if defined(TARGET_MIPS64)
void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef ldfun
#define ldfun ldq_raw
#else
    uint64_t (*ldfun)(target_ulong);

    switch (mem_idx)
    {
    case 0: ldfun = ldq_kernel; break;
    case 1: ldfun = ldq_super; break;
    default:
    case 2: ldfun = ldq_user; break;
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
            addr += 8;
        }
    }

    if (do_r31) {
        env->active_tc.gpr[31] = ldfun(addr);
    }
}

void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef stfun
#define stfun stq_raw
#else
    void (*stfun)(target_ulong, uint64_t);

    switch (mem_idx)
    {
    case 0: stfun = stq_kernel; break;
    case 1: stfun = stq_super; break;
     default:
    case 2: stfun = stq_user; break;
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
            addr += 8;
        }
    }

    if (do_r31) {
        stfun(addr, env->active_tc.gpr[31]);
    }
}
#endif

T
ths 已提交
744
#ifndef CONFIG_USER_ONLY
745
/* SMP helpers.  */
746
static int mips_vpe_is_wfi(CPUMIPSState *c)
747 748 749 750 751 752
{
    /* If the VPE is halted but otherwise active, it means it's waiting for
       an interrupt.  */
    return c->halted && mips_vpe_active(c);
}

753
static inline void mips_vpe_wake(CPUMIPSState *c)
754 755 756 757 758 759 760
{
    /* 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.  */
    cpu_interrupt(c, CPU_INTERRUPT_WAKE);
}

761
static inline void mips_vpe_sleep(CPUMIPSState *c)
762 763 764 765 766 767 768
{
    /* The VPE was shut off, really go to bed.
       Reset any old _WAKE requests.  */
    c->halted = 1;
    cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
}

769
static inline void mips_tc_wake(CPUMIPSState *c, int tc)
770 771 772 773 774 775 776
{
    /* FIXME: TC reschedule.  */
    if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) {
        mips_vpe_wake(c);
    }
}

777
static inline void mips_tc_sleep(CPUMIPSState *c, int tc)
778 779 780 781 782 783 784
{
    /* FIXME: TC reschedule.  */
    if (!mips_vpe_active(c)) {
        mips_vpe_sleep(c);
    }
}

785 786
/* tc should point to an int with the value of the global TC index.
   This function will transform it into a local index within the
787
   returned CPUMIPSState.
788 789 790

   FIXME: This code assumes that all VPEs have the same number of TCs,
          which depends on runtime setup. Can probably be fixed by
791 792
          walking the list of CPUMIPSStates.  */
static CPUMIPSState *mips_cpu_map_tc(int *tc)
793
{
794
    CPUMIPSState *other;
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
    int vpe_idx, nr_threads = env->nr_threads;
    int tc_idx = *tc;

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

    vpe_idx = tc_idx / nr_threads;
    *tc = tc_idx % nr_threads;
    other = qemu_get_cpu(vpe_idx);
    return other ? other : env;
}

810 811 812 813 814 815 816 817 818
/* The per VPE CP0_Status register shares some fields with the per TC
   CP0_TCStatus registers. These fields are wired to the same registers,
   so changes to either of them should be reflected on both registers.

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

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

/* Called for updates to CP0_Status.  */
819
static void sync_c0_status(CPUMIPSState *cpu, int tc)
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
{
    int32_t tcstatus, *tcst;
    uint32_t v = cpu->CP0_Status;
    uint32_t cu, mx, asid, ksu;
    uint32_t mask = ((1 << CP0TCSt_TCU3)
                       | (1 << CP0TCSt_TCU2)
                       | (1 << CP0TCSt_TCU1)
                       | (1 << CP0TCSt_TCU0)
                       | (1 << CP0TCSt_TMX)
                       | (3 << CP0TCSt_TKSU)
                       | (0xff << CP0TCSt_TASID));

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

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

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

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

/* Called for updates to CP0_TCStatus.  */
854
static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, target_ulong v)
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
{
    uint32_t status;
    uint32_t tcu, tmx, tasid, tksu;
    uint32_t mask = ((1 << CP0St_CU3)
                       | (1 << CP0St_CU2)
                       | (1 << CP0St_CU1)
                       | (1 << CP0St_CU0)
                       | (1 << CP0St_MX)
                       | (3 << CP0St_KSU));

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

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

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

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

    compute_hflags(cpu);
}

/* Called for updates to CP0_EntryHi.  */
885
static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
{
    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 已提交
902
/* CP0 helpers */
903
target_ulong helper_mfc0_mvpcontrol (void)
904
{
905
    return env->mvp->CP0_MVPControl;
906 907
}

908
target_ulong helper_mfc0_mvpconf0 (void)
909
{
910
    return env->mvp->CP0_MVPConf0;
911 912
}

913
target_ulong helper_mfc0_mvpconf1 (void)
914
{
915
    return env->mvp->CP0_MVPConf1;
916 917
}

918
target_ulong helper_mfc0_random (void)
B
bellard 已提交
919
{
920
    return (int32_t)cpu_mips_get_random(env);
921
}
B
bellard 已提交
922

923
target_ulong helper_mfc0_tcstatus (void)
924
{
925
    return env->active_tc.CP0_TCStatus;
926 927
}

928
target_ulong helper_mftc0_tcstatus(void)
929 930
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
931
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
932

933 934
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCStatus;
935
    else
936
        return other->tcs[other_tc].CP0_TCStatus;
937 938
}

939
target_ulong helper_mfc0_tcbind (void)
940
{
941
    return env->active_tc.CP0_TCBind;
942 943
}

944
target_ulong helper_mftc0_tcbind(void)
945 946
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
947
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
948

949 950
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCBind;
951
    else
952
        return other->tcs[other_tc].CP0_TCBind;
953 954
}

955
target_ulong helper_mfc0_tcrestart (void)
956
{
957
    return env->active_tc.PC;
958 959
}

960
target_ulong helper_mftc0_tcrestart(void)
961 962
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
963
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
964

965 966
    if (other_tc == other->current_tc)
        return other->active_tc.PC;
967
    else
968
        return other->tcs[other_tc].PC;
969 970
}

971
target_ulong helper_mfc0_tchalt (void)
972
{
973
    return env->active_tc.CP0_TCHalt;
974 975
}

976
target_ulong helper_mftc0_tchalt(void)
977 978
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
979
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
980

981 982
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCHalt;
983
    else
984
        return other->tcs[other_tc].CP0_TCHalt;
985 986
}

987
target_ulong helper_mfc0_tccontext (void)
988
{
989
    return env->active_tc.CP0_TCContext;
990 991
}

992
target_ulong helper_mftc0_tccontext(void)
993 994
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
995
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
996

997 998
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCContext;
999
    else
1000
        return other->tcs[other_tc].CP0_TCContext;
1001 1002
}

1003
target_ulong helper_mfc0_tcschedule (void)
1004
{
1005
    return env->active_tc.CP0_TCSchedule;
1006 1007
}

1008
target_ulong helper_mftc0_tcschedule(void)
1009 1010
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1011
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1012

1013 1014
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCSchedule;
1015
    else
1016
        return other->tcs[other_tc].CP0_TCSchedule;
1017 1018
}

1019
target_ulong helper_mfc0_tcschefback (void)
1020
{
1021
    return env->active_tc.CP0_TCScheFBack;
1022 1023
}

1024
target_ulong helper_mftc0_tcschefback(void)
1025 1026
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1027
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1028

1029 1030
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCScheFBack;
1031
    else
1032
        return other->tcs[other_tc].CP0_TCScheFBack;
1033 1034
}

1035
target_ulong helper_mfc0_count (void)
1036
{
1037
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
1038 1039
}

1040
target_ulong helper_mftc0_entryhi(void)
1041 1042
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1043
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1044

1045
    return other->CP0_EntryHi;
1046 1047
}

1048 1049 1050 1051
target_ulong helper_mftc0_cause(void)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    int32_t tccause;
1052
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062

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

    return tccause;
}

1063
target_ulong helper_mftc0_status(void)
1064 1065
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1066
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1067

1068
    return other->CP0_Status;
1069 1070
}

1071
target_ulong helper_mfc0_lladdr (void)
1072
{
1073
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
1074 1075
}

1076
target_ulong helper_mfc0_watchlo (uint32_t sel)
1077
{
1078
    return (int32_t)env->CP0_WatchLo[sel];
1079 1080
}

1081
target_ulong helper_mfc0_watchhi (uint32_t sel)
1082
{
1083
    return env->CP0_WatchHi[sel];
1084 1085
}

1086
target_ulong helper_mfc0_debug (void)
1087
{
1088
    target_ulong t0 = env->CP0_Debug;
1089
    if (env->hflags & MIPS_HFLAG_DM)
1090 1091 1092
        t0 |= 1 << CP0DB_DM;

    return t0;
1093 1094
}

1095
target_ulong helper_mftc0_debug(void)
1096 1097
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1098
    int32_t tcstatus;
1099
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1100

1101 1102
    if (other_tc == other->current_tc)
        tcstatus = other->active_tc.CP0_Debug_tcstatus;
1103
    else
1104
        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
1105 1106

    /* XXX: Might be wrong, check with EJTAG spec. */
1107
    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1108
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1109 1110 1111
}

#if defined(TARGET_MIPS64)
1112
target_ulong helper_dmfc0_tcrestart (void)
1113
{
1114
    return env->active_tc.PC;
1115 1116
}

1117
target_ulong helper_dmfc0_tchalt (void)
1118
{
1119
    return env->active_tc.CP0_TCHalt;
1120 1121
}

1122
target_ulong helper_dmfc0_tccontext (void)
1123
{
1124
    return env->active_tc.CP0_TCContext;
1125 1126
}

1127
target_ulong helper_dmfc0_tcschedule (void)
1128
{
1129
    return env->active_tc.CP0_TCSchedule;
1130 1131
}

1132
target_ulong helper_dmfc0_tcschefback (void)
1133
{
1134
    return env->active_tc.CP0_TCScheFBack;
1135 1136
}

1137
target_ulong helper_dmfc0_lladdr (void)
1138
{
1139
    return env->lladdr >> env->CP0_LLAddr_shift;
1140 1141
}

1142
target_ulong helper_dmfc0_watchlo (uint32_t sel)
1143
{
1144
    return env->CP0_WatchLo[sel];
1145 1146 1147
}
#endif /* TARGET_MIPS64 */

1148
void helper_mtc0_index (target_ulong arg1)
1149 1150 1151 1152 1153 1154 1155 1156
{
    int num = 1;
    unsigned int tmp = env->tlb->nb_tlb;

    do {
        tmp >>= 1;
        num <<= 1;
    } while (tmp);
1157
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
1158 1159
}

1160
void helper_mtc0_mvpcontrol (target_ulong arg1)
1161 1162 1163 1164 1165 1166 1167 1168 1169
{
    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);
1170
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1171 1172 1173 1174 1175 1176

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

    env->mvp->CP0_MVPControl = newval;
}

1177
void helper_mtc0_vpecontrol (target_ulong arg1)
1178 1179 1180 1181 1182 1183
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1184
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1185 1186 1187 1188 1189 1190 1191 1192 1193

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

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

1194 1195 1196
void helper_mttc0_vpecontrol(target_ulong arg1)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1197
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
    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;
}

target_ulong helper_mftc0_vpecontrol(void)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1213
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1214 1215 1216 1217 1218 1219 1220
    /* FIXME: Mask away return zero on read bits.  */
    return other->CP0_VPEControl;
}

target_ulong helper_mftc0_vpeconf0(void)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1221
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1222 1223 1224 1225

    return other->CP0_VPEConf0;
}

1226
void helper_mtc0_vpeconf0 (target_ulong arg1)
1227 1228 1229 1230 1231 1232 1233 1234 1235
{
    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);
    }
1236
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1237 1238 1239 1240 1241 1242

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

    env->CP0_VPEConf0 = newval;
}

1243 1244 1245
void helper_mttc0_vpeconf0(target_ulong arg1)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1246
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
    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;
}

1257
void helper_mtc0_vpeconf1 (target_ulong arg1)
1258 1259 1260 1261 1262 1263 1264
{
    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);
1265
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1266 1267 1268 1269 1270 1271 1272 1273 1274

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

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

1275
void helper_mtc0_yqmask (target_ulong arg1)
1276 1277 1278 1279 1280
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

1281
void helper_mtc0_vpeopt (target_ulong arg1)
1282
{
1283
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1284 1285
}

1286
void helper_mtc0_entrylo0 (target_ulong arg1)
1287 1288 1289
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1290
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1291 1292
}

1293
void helper_mtc0_tcstatus (target_ulong arg1)
1294 1295 1296 1297
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

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

1300
    env->active_tc.CP0_TCStatus = newval;
1301
    sync_c0_tcstatus(env, env->current_tc, newval);
1302 1303
}

1304
void helper_mttc0_tcstatus (target_ulong arg1)
1305 1306
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1307
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1308

1309 1310
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCStatus = arg1;
1311
    else
1312
        other->tcs[other_tc].CP0_TCStatus = arg1;
1313
    sync_c0_tcstatus(other, other_tc, arg1);
1314 1315
}

1316
void helper_mtc0_tcbind (target_ulong arg1)
1317 1318 1319 1320 1321 1322
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
1323
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1324
    env->active_tc.CP0_TCBind = newval;
1325 1326
}

1327
void helper_mttc0_tcbind (target_ulong arg1)
1328 1329 1330 1331
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;
1332
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1333

1334
    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1335
        mask |= (1 << CP0TCBd_CurVPE);
1336 1337 1338
    if (other_tc == other->current_tc) {
        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
        other->active_tc.CP0_TCBind = newval;
1339
    } else {
1340 1341
        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
        other->tcs[other_tc].CP0_TCBind = newval;
1342
    }
1343 1344
}

1345
void helper_mtc0_tcrestart (target_ulong arg1)
1346
{
1347
    env->active_tc.PC = arg1;
1348
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1349
    env->lladdr = 0ULL;
1350 1351 1352
    /* MIPS16 not implemented. */
}

1353
void helper_mttc0_tcrestart (target_ulong arg1)
1354 1355
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1356
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1357

1358 1359 1360 1361
    if (other_tc == other->current_tc) {
        other->active_tc.PC = arg1;
        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1362 1363
        /* MIPS16 not implemented. */
    } else {
1364 1365 1366
        other->tcs[other_tc].PC = arg1;
        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1367 1368
        /* MIPS16 not implemented. */
    }
1369 1370
}

1371
void helper_mtc0_tchalt (target_ulong arg1)
1372
{
1373
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1374 1375

    // TODO: Halt TC / Restart (if allocated+active) TC.
1376 1377 1378 1379 1380
    if (env->active_tc.CP0_TCHalt & 1) {
        mips_tc_sleep(env, env->current_tc);
    } else {
        mips_tc_wake(env, env->current_tc);
    }
1381 1382
}

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

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

1390 1391
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCHalt = arg1;
1392
    else
1393
        other->tcs[other_tc].CP0_TCHalt = arg1;
1394 1395 1396 1397 1398 1399

    if (arg1 & 1) {
        mips_tc_sleep(other, other_tc);
    } else {
        mips_tc_wake(other, other_tc);
    }
1400 1401
}

1402
void helper_mtc0_tccontext (target_ulong arg1)
1403
{
1404
    env->active_tc.CP0_TCContext = arg1;
1405 1406
}

1407
void helper_mttc0_tccontext (target_ulong arg1)
1408 1409
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1410
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1411

1412 1413
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCContext = arg1;
1414
    else
1415
        other->tcs[other_tc].CP0_TCContext = arg1;
1416 1417
}

1418
void helper_mtc0_tcschedule (target_ulong arg1)
1419
{
1420
    env->active_tc.CP0_TCSchedule = arg1;
1421 1422
}

1423
void helper_mttc0_tcschedule (target_ulong arg1)
1424 1425
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1426
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1427

1428 1429
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCSchedule = arg1;
1430
    else
1431
        other->tcs[other_tc].CP0_TCSchedule = arg1;
1432 1433
}

1434
void helper_mtc0_tcschefback (target_ulong arg1)
1435
{
1436
    env->active_tc.CP0_TCScheFBack = arg1;
1437 1438
}

1439
void helper_mttc0_tcschefback (target_ulong arg1)
1440 1441
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1442
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1443

1444 1445
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCScheFBack = arg1;
1446
    else
1447
        other->tcs[other_tc].CP0_TCScheFBack = arg1;
1448 1449
}

1450
void helper_mtc0_entrylo1 (target_ulong arg1)
1451 1452 1453
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1454
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1455 1456
}

1457
void helper_mtc0_context (target_ulong arg1)
1458
{
1459
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1460 1461
}

1462
void helper_mtc0_pagemask (target_ulong arg1)
1463 1464
{
    /* 1k pages not implemented */
1465
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1466 1467
}

1468
void helper_mtc0_pagegrain (target_ulong arg1)
1469 1470 1471 1472 1473 1474 1475
{
    /* SmartMIPS not implemented */
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
    env->CP0_PageGrain = 0;
}

1476
void helper_mtc0_wired (target_ulong arg1)
1477
{
1478
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1479 1480
}

1481
void helper_mtc0_srsconf0 (target_ulong arg1)
1482
{
1483
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1484 1485
}

1486
void helper_mtc0_srsconf1 (target_ulong arg1)
1487
{
1488
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1489 1490
}

1491
void helper_mtc0_srsconf2 (target_ulong arg1)
1492
{
1493
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1494 1495
}

1496
void helper_mtc0_srsconf3 (target_ulong arg1)
1497
{
1498
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1499 1500
}

1501
void helper_mtc0_srsconf4 (target_ulong arg1)
1502
{
1503
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1504 1505
}

1506
void helper_mtc0_hwrena (target_ulong arg1)
1507
{
1508
    env->CP0_HWREna = arg1 & 0x0000000F;
1509 1510
}

1511
void helper_mtc0_count (target_ulong arg1)
1512
{
1513
    cpu_mips_store_count(env, arg1);
1514 1515
}

1516
void helper_mtc0_entryhi (target_ulong arg1)
1517 1518 1519 1520
{
    target_ulong old, val;

    /* 1k pages not implemented */
1521
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1522 1523 1524 1525 1526 1527
#if defined(TARGET_MIPS64)
    val &= env->SEGMask;
#endif
    old = env->CP0_EntryHi;
    env->CP0_EntryHi = val;
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1528
        sync_c0_entryhi(env, env->current_tc);
1529 1530 1531 1532 1533 1534
    }
    /* If the ASID changes, flush qemu's TLB.  */
    if ((old & 0xFF) != (val & 0xFF))
        cpu_mips_tlb_flush(env, 1);
}

1535
void helper_mttc0_entryhi(target_ulong arg1)
1536 1537
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1538
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1539

1540 1541
    other->CP0_EntryHi = arg1;
    sync_c0_entryhi(other, other_tc);
1542 1543
}

1544
void helper_mtc0_compare (target_ulong arg1)
1545
{
1546
    cpu_mips_store_compare(env, arg1);
1547 1548
}

1549
void helper_mtc0_status (target_ulong arg1)
1550 1551 1552 1553
{
    uint32_t val, old;
    uint32_t mask = env->CP0_Status_rw_bitmask;

1554
    val = arg1 & mask;
1555 1556
    old = env->CP0_Status;
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1557 1558 1559 1560 1561 1562
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
        sync_c0_status(env, env->current_tc);
    } else {
        compute_hflags(env);
    }

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
    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;
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
A
Aurelien Jarno 已提交
1573
        }
1574
    }
1575 1576
}

1577
void helper_mttc0_status(target_ulong arg1)
1578 1579
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1580
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1581

1582
    other->CP0_Status = arg1 & ~0xf1000018;
1583
    sync_c0_status(other, other_tc);
1584 1585
}

1586
void helper_mtc0_intctl (target_ulong arg1)
1587 1588
{
    /* vectored interrupts not implemented, no performance counters. */
1589
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1590 1591
}

1592
void helper_mtc0_srsctl (target_ulong arg1)
1593 1594
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1595
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1596 1597
}

1598
static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
1599 1600
{
    uint32_t mask = 0x00C00300;
1601
    uint32_t old = cpu->CP0_Cause;
1602
    int i;
1603

1604
    if (cpu->insn_flags & ISA_MIPS32R2) {
1605
        mask |= 1 << CP0Ca_DC;
1606
    }
1607

1608
    cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
1609

1610 1611 1612 1613 1614 1615
    if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
        if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
            cpu_mips_stop_count(cpu);
        } else {
            cpu_mips_start_count(cpu);
        }
1616
    }
1617 1618 1619

    /* Set/reset software interrupts */
    for (i = 0 ; i < 2 ; i++) {
1620 1621
        if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
            cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
1622 1623
        }
    }
1624 1625
}

1626 1627 1628 1629 1630 1631 1632 1633
void helper_mtc0_cause(target_ulong arg1)
{
    mtc0_cause(env, arg1);
}

void helper_mttc0_cause(target_ulong arg1)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1634
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1635 1636 1637 1638 1639 1640 1641

    mtc0_cause(other, arg1);
}

target_ulong helper_mftc0_epc(void)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1642
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1643 1644 1645 1646 1647 1648 1649

    return other->CP0_EPC;
}

target_ulong helper_mftc0_ebase(void)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1650
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1651 1652 1653 1654

    return other->CP0_EBase;
}

1655
void helper_mtc0_ebase (target_ulong arg1)
1656 1657
{
    /* vectored interrupts not implemented */
1658
    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1659 1660
}

1661 1662 1663
void helper_mttc0_ebase(target_ulong arg1)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1664
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1665 1666 1667 1668 1669 1670
    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}

target_ulong helper_mftc0_configx(target_ulong idx)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1671
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686

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

1687
void helper_mtc0_config0 (target_ulong arg1)
1688
{
1689
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1690 1691
}

1692
void helper_mtc0_config2 (target_ulong arg1)
1693 1694 1695 1696 1697
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1698 1699 1700 1701 1702 1703 1704
void helper_mtc0_lladdr (target_ulong arg1)
{
    target_long mask = env->CP0_LLAddr_rw_bitmask;
    arg1 = arg1 << env->CP0_LLAddr_shift;
    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
}

1705
void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1706 1707 1708
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1709
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1710 1711
}

1712
void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1713
{
1714 1715
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1716 1717
}

1718
void helper_mtc0_xcontext (target_ulong arg1)
1719 1720
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1721
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1722 1723
}

1724
void helper_mtc0_framemask (target_ulong arg1)
1725
{
1726
    env->CP0_Framemask = arg1; /* XXX */
1727 1728
}

1729
void helper_mtc0_debug (target_ulong arg1)
1730
{
1731 1732
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1733 1734 1735 1736 1737
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1738
void helper_mttc0_debug(target_ulong arg1)
1739 1740
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1741
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1742
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1743 1744

    /* XXX: Might be wrong, check with EJTAG spec. */
1745 1746
    if (other_tc == other->current_tc)
        other->active_tc.CP0_Debug_tcstatus = val;
1747
    else
1748 1749 1750
        other->tcs[other_tc].CP0_Debug_tcstatus = val;
    other->CP0_Debug = (other->CP0_Debug &
                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1751
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1752 1753
}

1754
void helper_mtc0_performance0 (target_ulong arg1)
1755
{
1756
    env->CP0_Performance0 = arg1 & 0x000007ff;
1757 1758
}

1759
void helper_mtc0_taglo (target_ulong arg1)
1760
{
1761
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1762 1763
}

1764
void helper_mtc0_datalo (target_ulong arg1)
1765
{
1766
    env->CP0_DataLo = arg1; /* XXX */
1767 1768
}

1769
void helper_mtc0_taghi (target_ulong arg1)
1770
{
1771
    env->CP0_TagHi = arg1; /* XXX */
1772 1773
}

1774
void helper_mtc0_datahi (target_ulong arg1)
1775
{
1776
    env->CP0_DataHi = arg1; /* XXX */
1777 1778 1779
}

/* MIPS MT functions */
1780
target_ulong helper_mftgpr(uint32_t sel)
1781 1782
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1783
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1784

1785 1786
    if (other_tc == other->current_tc)
        return other->active_tc.gpr[sel];
1787
    else
1788
        return other->tcs[other_tc].gpr[sel];
1789 1790
}

1791
target_ulong helper_mftlo(uint32_t sel)
1792 1793
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1794
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1795

1796 1797
    if (other_tc == other->current_tc)
        return other->active_tc.LO[sel];
1798
    else
1799
        return other->tcs[other_tc].LO[sel];
1800 1801
}

1802
target_ulong helper_mfthi(uint32_t sel)
1803 1804
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1805
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1806

1807 1808
    if (other_tc == other->current_tc)
        return other->active_tc.HI[sel];
1809
    else
1810
        return other->tcs[other_tc].HI[sel];
1811 1812
}

1813
target_ulong helper_mftacx(uint32_t sel)
1814 1815
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1816
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1817

1818 1819
    if (other_tc == other->current_tc)
        return other->active_tc.ACX[sel];
1820
    else
1821
        return other->tcs[other_tc].ACX[sel];
1822 1823
}

1824
target_ulong helper_mftdsp(void)
1825 1826
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1827
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1828

1829 1830
    if (other_tc == other->current_tc)
        return other->active_tc.DSPControl;
1831
    else
1832
        return other->tcs[other_tc].DSPControl;
1833
}
B
bellard 已提交
1834

1835
void helper_mttgpr(target_ulong arg1, uint32_t sel)
1836 1837
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1838
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1839

1840 1841
    if (other_tc == other->current_tc)
        other->active_tc.gpr[sel] = arg1;
1842
    else
1843
        other->tcs[other_tc].gpr[sel] = arg1;
1844 1845
}

1846
void helper_mttlo(target_ulong arg1, uint32_t sel)
1847 1848
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1849
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1850

1851 1852
    if (other_tc == other->current_tc)
        other->active_tc.LO[sel] = arg1;
1853
    else
1854
        other->tcs[other_tc].LO[sel] = arg1;
1855 1856
}

1857
void helper_mtthi(target_ulong arg1, uint32_t sel)
1858 1859
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1860
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1861

1862 1863
    if (other_tc == other->current_tc)
        other->active_tc.HI[sel] = arg1;
1864
    else
1865
        other->tcs[other_tc].HI[sel] = arg1;
1866 1867
}

1868
void helper_mttacx(target_ulong arg1, uint32_t sel)
1869 1870
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1871
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1872

1873 1874
    if (other_tc == other->current_tc)
        other->active_tc.ACX[sel] = arg1;
1875
    else
1876
        other->tcs[other_tc].ACX[sel] = arg1;
1877 1878
}

1879
void helper_mttdsp(target_ulong arg1)
1880 1881
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1882
    CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1883

1884 1885
    if (other_tc == other->current_tc)
        other->active_tc.DSPControl = arg1;
1886
    else
1887
        other->tcs[other_tc].DSPControl = arg1;
1888 1889 1890
}

/* MIPS MT functions */
1891
target_ulong helper_dmt(void)
1892 1893
{
    // TODO
1894
     return 0;
1895 1896
}

1897
target_ulong helper_emt(void)
1898 1899
{
    // TODO
1900
    return 0;
1901 1902
}

1903
target_ulong helper_dvpe(void)
1904
{
1905
    CPUMIPSState *other_cpu = first_cpu;
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916
    target_ulong prev = env->mvp->CP0_MVPControl;

    do {
        /* Turn off all VPEs except the one executing the dvpe.  */
        if (other_cpu != env) {
            other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
            mips_vpe_sleep(other_cpu);
        }
        other_cpu = other_cpu->next_cpu;
    } while (other_cpu);
    return prev;
1917 1918
}

1919
target_ulong helper_evpe(void)
1920
{
1921
    CPUMIPSState *other_cpu = first_cpu;
1922 1923 1924 1925
    target_ulong prev = env->mvp->CP0_MVPControl;

    do {
        if (other_cpu != env
1926
           /* If the VPE is WFI, don't disturb its sleep.  */
1927 1928 1929 1930 1931 1932 1933 1934
           && !mips_vpe_is_wfi(other_cpu)) {
            /* Enable the VPE.  */
            other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
            mips_vpe_wake(other_cpu); /* And wake it up.  */
        }
        other_cpu = other_cpu->next_cpu;
    } while (other_cpu);
    return prev;
1935
}
1936
#endif /* !CONFIG_USER_ONLY */
1937

1938
void helper_fork(target_ulong arg1, target_ulong arg2)
1939
{
1940 1941
    // arg1 = rt, arg2 = rs
    arg1 = 0;
1942 1943 1944
    // TODO: store to TC register
}

B
Blue Swirl 已提交
1945
target_ulong helper_yield(target_ulong arg)
1946
{
B
Blue Swirl 已提交
1947 1948
    target_long arg1 = arg;

1949
    if (arg1 < 0) {
1950
        /* No scheduling policy implemented. */
1951
        if (arg1 != -2) {
1952
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1953
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1954 1955
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1956
                helper_raise_exception(EXCP_THREAD);
1957 1958
            }
        }
1959
    } else if (arg1 == 0) {
A
aurel32 已提交
1960
        if (0 /* TODO: TC underflow */) {
1961
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1962
            helper_raise_exception(EXCP_THREAD);
1963 1964 1965
        } else {
            // TODO: Deallocate TC
        }
1966
    } else if (arg1 > 0) {
1967 1968 1969
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1970
        helper_raise_exception(EXCP_THREAD);
1971
    }
1972
    return env->CP0_YQMask;
1973 1974 1975
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1976
/* TLB management */
1977
static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1978 1979 1980
{
    /* Flush qemu's TLB and discard all shadowed entries.  */
    tlb_flush (env, flush_global);
1981
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1982 1983
}

1984
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1985 1986
{
    /* Discard entries from env->tlb[first] onwards.  */
1987 1988
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1989 1990 1991
    }
}

1992
static void r4k_fill_tlb (int idx)
B
bellard 已提交
1993
{
A
Anthony Liguori 已提交
1994
    r4k_tlb_t *tlb;
B
bellard 已提交
1995 1996

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1997
    tlb = &env->tlb->mmu.r4k.tlb[idx];
T
ths 已提交
1998
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1999
#if defined(TARGET_MIPS64)
T
ths 已提交
2000
    tlb->VPN &= env->SEGMask;
2001
#endif
2002
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
2003
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
2004
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2005 2006 2007
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
B
bellard 已提交
2008
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
2009 2010 2011
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
B
bellard 已提交
2012 2013 2014
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}

2015
void r4k_helper_tlbwi (void)
B
bellard 已提交
2016
{
A
aurel32 已提交
2017 2018 2019 2020
    int idx;

    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;

2021 2022 2023
    /* Discard cached TLB entries.  We could avoid doing this if the
       tlbwi is just upgrading access permissions on the current entry;
       that might be a further win.  */
2024
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
2025

A
aurel32 已提交
2026 2027
    r4k_invalidate_tlb(env, idx, 0);
    r4k_fill_tlb(idx);
B
bellard 已提交
2028 2029
}

2030
void r4k_helper_tlbwr (void)
B
bellard 已提交
2031 2032 2033
{
    int r = cpu_mips_get_random(env);

2034 2035
    r4k_invalidate_tlb(env, r, 1);
    r4k_fill_tlb(r);
B
bellard 已提交
2036 2037
}

2038
void r4k_helper_tlbp (void)
B
bellard 已提交
2039
{
A
Anthony Liguori 已提交
2040
    r4k_tlb_t *tlb;
T
ths 已提交
2041
    target_ulong mask;
B
bellard 已提交
2042
    target_ulong tag;
T
ths 已提交
2043
    target_ulong VPN;
B
bellard 已提交
2044 2045 2046
    uint8_t ASID;
    int i;

B
bellard 已提交
2047
    ASID = env->CP0_EntryHi & 0xFF;
2048 2049
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
2050 2051 2052 2053
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
B
bellard 已提交
2054
        /* Check ASID, virtual page number & size */
T
ths 已提交
2055
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
B
bellard 已提交
2056
            /* TLB match */
T
ths 已提交
2057
            env->CP0_Index = i;
B
bellard 已提交
2058 2059 2060
            break;
        }
    }
2061
    if (i == env->tlb->nb_tlb) {
2062
        /* No match.  Discard any shadow entries, if any of them match.  */
2063
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
2064 2065 2066 2067 2068 2069 2070
            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;
            /* Check ASID, virtual page number & size */
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2071
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
2072 2073 2074
                break;
            }
        }
2075

T
ths 已提交
2076
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
2077 2078 2079
    }
}

2080
void r4k_helper_tlbr (void)
B
bellard 已提交
2081
{
A
Anthony Liguori 已提交
2082
    r4k_tlb_t *tlb;
2083
    uint8_t ASID;
A
aurel32 已提交
2084
    int idx;
B
bellard 已提交
2085

2086
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
2087 2088
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
2089 2090

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

2094
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
2095

B
bellard 已提交
2096
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
T
ths 已提交
2097
    env->CP0_PageMask = tlb->PageMask;
T
ths 已提交
2098 2099 2100 2101
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
B
bellard 已提交
2102 2103
}

2104
void helper_tlbwi(void)
P
pbrook 已提交
2105
{
2106
    env->tlb->helper_tlbwi();
P
pbrook 已提交
2107 2108
}

2109
void helper_tlbwr(void)
P
pbrook 已提交
2110
{
2111
    env->tlb->helper_tlbwr();
P
pbrook 已提交
2112 2113
}

2114
void helper_tlbp(void)
P
pbrook 已提交
2115
{
2116
    env->tlb->helper_tlbp();
P
pbrook 已提交
2117 2118
}

2119
void helper_tlbr(void)
P
pbrook 已提交
2120
{
2121
    env->tlb->helper_tlbr();
P
pbrook 已提交
2122 2123
}

2124
/* Specials */
2125
target_ulong helper_di (void)
2126
{
2127 2128
    target_ulong t0 = env->CP0_Status;

2129 2130
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
    return t0;
2131 2132
}

2133
target_ulong helper_ei (void)
2134
{
2135 2136
    target_ulong t0 = env->CP0_Status;

2137 2138
    env->CP0_Status = t0 | (1 << CP0St_IE);
    return t0;
2139 2140
}

A
aurel32 已提交
2141
static void debug_pre_eret (void)
B
bellard 已提交
2142
{
2143
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2144 2145 2146 2147 2148 2149 2150 2151
        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");
    }
2152 2153
}

A
aurel32 已提交
2154
static void debug_post_eret (void)
2155
{
2156
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
        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;
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
        }
T
ths 已提交
2169
    }
B
bellard 已提交
2170 2171
}

2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
static void set_pc (target_ulong error_pc)
{
    env->active_tc.PC = error_pc & ~(target_ulong)1;
    if (error_pc & 1) {
        env->hflags |= MIPS_HFLAG_M16;
    } else {
        env->hflags &= ~(MIPS_HFLAG_M16);
    }
}

2182
void helper_eret (void)
2183
{
2184
    debug_pre_eret();
2185
    if (env->CP0_Status & (1 << CP0St_ERL)) {
2186
        set_pc(env->CP0_ErrorEPC);
2187 2188
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
2189
        set_pc(env->CP0_EPC);
2190 2191 2192
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
2193
    debug_post_eret();
2194
    env->lladdr = 1;
2195 2196
}

2197
void helper_deret (void)
2198
{
2199
    debug_pre_eret();
2200 2201
    set_pc(env->CP0_DEPC);

2202 2203
    env->hflags &= MIPS_HFLAG_DM;
    compute_hflags(env);
2204
    debug_post_eret();
2205
    env->lladdr = 1;
2206
}
T
ths 已提交
2207
#endif /* !CONFIG_USER_ONLY */
2208

2209
target_ulong helper_rdhwr_cpunum(void)
2210 2211 2212
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 0)))
2213
        return env->CP0_EBase & 0x3ff;
2214
    else
2215
        helper_raise_exception(EXCP_RI);
2216

2217
    return 0;
2218 2219
}

2220
target_ulong helper_rdhwr_synci_step(void)
2221 2222 2223
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 1)))
2224
        return env->SYNCI_Step;
2225
    else
2226
        helper_raise_exception(EXCP_RI);
2227

2228
    return 0;
2229 2230
}

2231
target_ulong helper_rdhwr_cc(void)
2232 2233 2234
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 2)))
2235
        return env->CP0_Count;
2236
    else
2237
        helper_raise_exception(EXCP_RI);
2238

2239
    return 0;
2240 2241
}

2242
target_ulong helper_rdhwr_ccres(void)
2243 2244 2245
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 3)))
2246
        return env->CCRes;
2247
    else
2248
        helper_raise_exception(EXCP_RI);
2249

2250
    return 0;
2251 2252
}

2253
void helper_pmon (int function)
B
bellard 已提交
2254 2255 2256 2257
{
    function /= 2;
    switch (function) {
    case 2: /* TODO: char inbyte(int waitflag); */
2258 2259
        if (env->active_tc.gpr[4] == 0)
            env->active_tc.gpr[2] = -1;
B
bellard 已提交
2260 2261
        /* Fall through */
    case 11: /* TODO: char inbyte (void); */
2262
        env->active_tc.gpr[2] = -1;
B
bellard 已提交
2263 2264 2265
        break;
    case 3:
    case 12:
2266
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
B
bellard 已提交
2267 2268 2269 2270 2271
        break;
    case 17:
        break;
    case 158:
        {
2272
            unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
B
bellard 已提交
2273 2274 2275 2276 2277
            printf("%s", fmt);
        }
        break;
    }
}
2278

2279
void helper_wait (void)
T
ths 已提交
2280 2281
{
    env->halted = 1;
2282
    cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
2283
    helper_raise_exception(EXCP_HLT);
T
ths 已提交
2284 2285
}

2286
#if !defined(CONFIG_USER_ONLY)
2287

2288
static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
2289
                                              int is_user, uintptr_t retaddr);
B
bellard 已提交
2290

2291
#define MMUSUFFIX _mmu
B
bellard 已提交
2292
#define ALIGNED_ONLY
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305

#define SHIFT 0
#include "softmmu_template.h"

#define SHIFT 1
#include "softmmu_template.h"

#define SHIFT 2
#include "softmmu_template.h"

#define SHIFT 3
#include "softmmu_template.h"

2306 2307
static void do_unaligned_access(target_ulong addr, int is_write,
                                int is_user, uintptr_t retaddr)
B
bellard 已提交
2308 2309 2310
{
    env->CP0_BadVAddr = addr;
    do_restore_state (retaddr);
2311
    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
B
bellard 已提交
2312 2313
}

2314
void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
2315
              uintptr_t retaddr)
2316 2317
{
    TranslationBlock *tb;
2318
    CPUMIPSState *saved_env;
2319 2320 2321
    int ret;

    saved_env = env;
2322
    env = env1;
2323
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
2324 2325 2326
    if (ret) {
        if (retaddr) {
            /* now we have a real cpu fault */
2327
            tb = tb_find_pc(retaddr);
2328 2329 2330
            if (tb) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
2331
                cpu_restore_state(tb, env, retaddr);
2332 2333
            }
        }
2334
        helper_raise_exception_err(env->exception_index, env->error_code);
2335 2336 2337 2338
    }
    env = saved_env;
}

2339
void cpu_unassigned_access(CPUMIPSState *env1, target_phys_addr_t addr,
2340
                           int is_write, int is_exec, int unused, int size)
T
ths 已提交
2341
{
2342 2343
    env = env1;

T
ths 已提交
2344
    if (is_exec)
2345
        helper_raise_exception(EXCP_IBE);
T
ths 已提交
2346
    else
2347
        helper_raise_exception(EXCP_DBE);
T
ths 已提交
2348
}
2349
#endif /* !CONFIG_USER_ONLY */
2350 2351 2352

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

P
pbrook 已提交
2353 2354 2355 2356
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
#define FLOAT_TWO32 make_float32(1 << 30)
#define FLOAT_TWO64 make_float64(1ULL << 62)
T
ths 已提交
2357 2358 2359 2360
#define FLOAT_QNAN32 0x7fbfffff
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
#define FLOAT_SNAN32 0x7fffffff
#define FLOAT_SNAN64 0x7fffffffffffffffULL
T
ths 已提交
2361

2362
/* convert MIPS rounding mode in FCR31 to IEEE library */
B
Blue Swirl 已提交
2363
static unsigned int ieee_rm[] = {
2364 2365 2366 2367 2368 2369 2370
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

#define RESTORE_ROUNDING_MODE \
2371
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
2372

2373 2374 2375
#define RESTORE_FLUSH_MODE \
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);

2376
target_ulong helper_cfc1 (uint32_t reg)
2377
{
2378
    target_ulong arg1;
2379

2380 2381
    switch (reg) {
    case 0:
2382
        arg1 = (int32_t)env->active_fpu.fcr0;
2383 2384
        break;
    case 25:
2385
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2386 2387
        break;
    case 26:
2388
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2389 2390
        break;
    case 28:
2391
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2392 2393
        break;
    default:
2394
        arg1 = (int32_t)env->active_fpu.fcr31;
2395 2396
        break;
    }
2397

2398
    return arg1;
2399 2400
}

2401
void helper_ctc1 (target_ulong arg1, uint32_t reg)
2402 2403
{
    switch(reg) {
2404
    case 25:
2405
        if (arg1 & 0xffffff00)
2406
            return;
2407 2408
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2409 2410
        break;
    case 26:
2411
        if (arg1 & 0x007c0000)
2412
            return;
2413
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2414 2415
        break;
    case 28:
2416
        if (arg1 & 0x007c0000)
2417
            return;
2418 2419
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2420 2421
        break;
    case 31:
2422
        if (arg1 & 0x007c0000)
2423
            return;
2424
        env->active_fpu.fcr31 = arg1;
2425 2426 2427 2428 2429 2430
        break;
    default:
        return;
    }
    /* set rounding mode */
    RESTORE_ROUNDING_MODE;
2431 2432
    /* set flush-to-zero mode */
    RESTORE_FLUSH_MODE;
2433 2434
    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))
2435
        helper_raise_exception(EXCP_FPE);
2436 2437
}

2438
static inline int ieee_ex_to_mips(int xcpt)
2439
{
2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458
    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;
2459 2460
}

T
ths 已提交
2461
static inline void update_fcr31(void)
2462
{
2463
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2464

2465 2466
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
2467
        helper_raise_exception(EXCP_FPE);
2468
    else
2469
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2470 2471
}

2472 2473 2474 2475 2476 2477
/* 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  */
2478
uint64_t helper_float_sqrt_d(uint64_t fdt0)
2479
{
2480
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2481 2482
}

2483
uint32_t helper_float_sqrt_s(uint32_t fst0)
2484
{
2485
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
2486
}
2487

2488
uint64_t helper_float_cvtd_s(uint32_t fst0)
2489
{
2490 2491
    uint64_t fdt2;

2492 2493
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2494
    update_fcr31();
2495
    return fdt2;
2496
}
2497

2498
uint64_t helper_float_cvtd_w(uint32_t wt0)
2499
{
2500 2501
    uint64_t fdt2;

2502 2503
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2504
    update_fcr31();
2505
    return fdt2;
2506
}
2507

2508
uint64_t helper_float_cvtd_l(uint64_t dt0)
2509
{
2510 2511
    uint64_t fdt2;

2512 2513
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2514
    update_fcr31();
2515
    return fdt2;
2516
}
2517

2518
uint64_t helper_float_cvtl_d(uint64_t fdt0)
2519
{
2520 2521
    uint64_t dt2;

2522 2523
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2524
    update_fcr31();
2525
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2526 2527
        dt2 = FLOAT_SNAN64;
    return dt2;
2528
}
2529

2530
uint64_t helper_float_cvtl_s(uint32_t fst0)
2531
{
2532 2533
    uint64_t dt2;

2534 2535
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2536
    update_fcr31();
2537
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2538 2539
        dt2 = FLOAT_SNAN64;
    return dt2;
2540 2541
}

2542
uint64_t helper_float_cvtps_pw(uint64_t dt0)
2543
{
2544 2545 2546
    uint32_t fst2;
    uint32_t fsth2;

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

2554
uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2555
{
2556 2557 2558
    uint32_t wt2;
    uint32_t wth2;

2559 2560 2561
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2562
    update_fcr31();
2563
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2564 2565 2566 2567
        wt2 = FLOAT_SNAN32;
        wth2 = FLOAT_SNAN32;
    }
    return ((uint64_t)wth2 << 32) | wt2;
2568
}
2569

2570
uint32_t helper_float_cvts_d(uint64_t fdt0)
2571
{
2572 2573
    uint32_t fst2;

2574 2575
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2576
    update_fcr31();
2577
    return fst2;
2578
}
2579

2580
uint32_t helper_float_cvts_w(uint32_t wt0)
2581
{
2582 2583
    uint32_t fst2;

2584 2585
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2586
    update_fcr31();
2587
    return fst2;
2588
}
2589

2590
uint32_t helper_float_cvts_l(uint64_t dt0)
2591
{
2592 2593
    uint32_t fst2;

2594 2595
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2596
    update_fcr31();
2597
    return fst2;
2598
}
2599

2600
uint32_t helper_float_cvts_pl(uint32_t wt0)
2601
{
2602 2603
    uint32_t wt2;

2604
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2605
    wt2 = wt0;
2606
    update_fcr31();
2607
    return wt2;
2608
}
2609

2610
uint32_t helper_float_cvts_pu(uint32_t wth0)
2611
{
2612 2613
    uint32_t wt2;

2614
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2615
    wt2 = wth0;
2616
    update_fcr31();
2617
    return wt2;
2618
}
2619

2620
uint32_t helper_float_cvtw_s(uint32_t fst0)
2621
{
2622 2623
    uint32_t wt2;

2624 2625
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2626
    update_fcr31();
2627
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2628 2629
        wt2 = FLOAT_SNAN32;
    return wt2;
2630
}
2631

2632
uint32_t helper_float_cvtw_d(uint64_t fdt0)
2633
{
2634 2635
    uint32_t wt2;

2636 2637
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2638
    update_fcr31();
2639
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2640 2641
        wt2 = FLOAT_SNAN32;
    return wt2;
2642 2643
}

2644
uint64_t helper_float_roundl_d(uint64_t fdt0)
2645
{
2646 2647
    uint64_t dt2;

2648
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2649 2650
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2651 2652
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2653
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2654 2655
        dt2 = FLOAT_SNAN64;
    return dt2;
2656
}
2657

2658
uint64_t helper_float_roundl_s(uint32_t fst0)
2659
{
2660 2661
    uint64_t dt2;

2662
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2663 2664
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2665 2666
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2667
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2668 2669
        dt2 = FLOAT_SNAN64;
    return dt2;
2670
}
2671

2672
uint32_t helper_float_roundw_d(uint64_t fdt0)
2673
{
2674 2675
    uint32_t wt2;

2676
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2677 2678
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2679 2680
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2681
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2682 2683
        wt2 = FLOAT_SNAN32;
    return wt2;
2684
}
2685

2686
uint32_t helper_float_roundw_s(uint32_t fst0)
2687
{
2688 2689
    uint32_t wt2;

2690
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2691 2692
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2693 2694
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2695
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2696 2697
        wt2 = FLOAT_SNAN32;
    return wt2;
2698 2699
}

2700
uint64_t helper_float_truncl_d(uint64_t fdt0)
2701
{
2702 2703
    uint64_t dt2;

2704
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2705
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2706
    update_fcr31();
2707
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2708 2709
        dt2 = FLOAT_SNAN64;
    return dt2;
2710
}
2711

2712
uint64_t helper_float_truncl_s(uint32_t fst0)
2713
{
2714 2715
    uint64_t dt2;

2716
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2717
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2718
    update_fcr31();
2719
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2720 2721
        dt2 = FLOAT_SNAN64;
    return dt2;
2722
}
2723

2724
uint32_t helper_float_truncw_d(uint64_t fdt0)
2725
{
2726 2727
    uint32_t wt2;

2728
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2729
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2730
    update_fcr31();
2731
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2732 2733
        wt2 = FLOAT_SNAN32;
    return wt2;
2734
}
2735

2736
uint32_t helper_float_truncw_s(uint32_t fst0)
2737
{
2738 2739
    uint32_t wt2;

2740
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2741
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2742
    update_fcr31();
2743
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2744 2745
        wt2 = FLOAT_SNAN32;
    return wt2;
2746 2747
}

2748
uint64_t helper_float_ceill_d(uint64_t fdt0)
2749
{
2750 2751
    uint64_t dt2;

2752
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2753 2754
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2755 2756
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2757
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2758 2759
        dt2 = FLOAT_SNAN64;
    return dt2;
2760
}
2761

2762
uint64_t helper_float_ceill_s(uint32_t fst0)
2763
{
2764 2765
    uint64_t dt2;

2766
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2767 2768
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2769 2770
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2771
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2772 2773
        dt2 = FLOAT_SNAN64;
    return dt2;
2774
}
2775

2776
uint32_t helper_float_ceilw_d(uint64_t fdt0)
2777
{
2778 2779
    uint32_t wt2;

2780
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2781 2782
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2783 2784
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2785
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2786 2787
        wt2 = FLOAT_SNAN32;
    return wt2;
2788
}
2789

2790
uint32_t helper_float_ceilw_s(uint32_t fst0)
2791
{
2792 2793
    uint32_t wt2;

2794
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2795 2796
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2797 2798
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2799
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2800 2801
        wt2 = FLOAT_SNAN32;
    return wt2;
2802 2803
}

2804
uint64_t helper_float_floorl_d(uint64_t fdt0)
2805
{
2806 2807
    uint64_t dt2;

2808
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2809 2810
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2811 2812
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2813
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2814 2815
        dt2 = FLOAT_SNAN64;
    return dt2;
2816
}
2817

2818
uint64_t helper_float_floorl_s(uint32_t fst0)
2819
{
2820 2821
    uint64_t dt2;

2822
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2823 2824
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2825 2826
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2827
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2828 2829
        dt2 = FLOAT_SNAN64;
    return dt2;
2830
}
2831

2832
uint32_t helper_float_floorw_d(uint64_t fdt0)
2833
{
2834 2835
    uint32_t wt2;

2836
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2837 2838
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2839 2840
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2841
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2842 2843
        wt2 = FLOAT_SNAN32;
    return wt2;
2844
}
2845

2846
uint32_t helper_float_floorw_s(uint32_t fst0)
2847
{
2848 2849
    uint32_t wt2;

2850
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2851 2852
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2853 2854
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2855
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2856 2857
        wt2 = FLOAT_SNAN32;
    return wt2;
2858 2859
}

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

T
ths 已提交
2883
/* MIPS specific unary operations */
2884
uint64_t helper_float_recip_d(uint64_t fdt0)
T
ths 已提交
2885
{
2886 2887
    uint64_t fdt2;

2888 2889
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2890
    update_fcr31();
2891
    return fdt2;
T
ths 已提交
2892
}
2893

2894
uint32_t helper_float_recip_s(uint32_t fst0)
T
ths 已提交
2895
{
2896 2897
    uint32_t fst2;

2898 2899
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2900
    update_fcr31();
2901
    return fst2;
T
ths 已提交
2902 2903
}

2904
uint64_t helper_float_rsqrt_d(uint64_t fdt0)
T
ths 已提交
2905
{
2906 2907
    uint64_t fdt2;

2908 2909 2910
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
T
ths 已提交
2911
    update_fcr31();
2912
    return fdt2;
T
ths 已提交
2913
}
2914

2915
uint32_t helper_float_rsqrt_s(uint32_t fst0)
T
ths 已提交
2916
{
2917 2918
    uint32_t fst2;

2919 2920 2921
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
T
ths 已提交
2922
    update_fcr31();
2923
    return fst2;
T
ths 已提交
2924 2925
}

2926
uint64_t helper_float_recip1_d(uint64_t fdt0)
T
ths 已提交
2927
{
2928 2929
    uint64_t fdt2;

2930 2931
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2932
    update_fcr31();
2933
    return fdt2;
T
ths 已提交
2934
}
2935

2936
uint32_t helper_float_recip1_s(uint32_t fst0)
T
ths 已提交
2937
{
2938 2939
    uint32_t fst2;

2940 2941
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2942
    update_fcr31();
2943
    return fst2;
T
ths 已提交
2944
}
2945

2946
uint64_t helper_float_recip1_ps(uint64_t fdt0)
T
ths 已提交
2947
{
2948 2949 2950
    uint32_t fst2;
    uint32_t fsth2;

2951 2952 2953
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
T
ths 已提交
2954
    update_fcr31();
2955
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2956 2957
}

2958
uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
T
ths 已提交
2959
{
2960 2961
    uint64_t fdt2;

2962 2963 2964
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
T
ths 已提交
2965
    update_fcr31();
2966
    return fdt2;
T
ths 已提交
2967
}
2968

2969
uint32_t helper_float_rsqrt1_s(uint32_t fst0)
T
ths 已提交
2970
{
2971 2972
    uint32_t fst2;

2973 2974 2975
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
T
ths 已提交
2976
    update_fcr31();
2977
    return fst2;
T
ths 已提交
2978
}
2979

2980
uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
T
ths 已提交
2981
{
2982 2983 2984
    uint32_t fst2;
    uint32_t fsth2;

2985 2986 2987 2988 2989
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
T
ths 已提交
2990
    update_fcr31();
2991
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2992 2993
}

2994
#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2995

2996
/* binary operations */
2997
#define FLOAT_BINOP(name)                                          \
2998
uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2999 3000 3001
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
3002 3003
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3004
    update_fcr31();                                                \
3005
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
3006 3007 3008 3009
        dt2 = FLOAT_QNAN64;                                        \
    return dt2;                                                    \
}                                                                  \
                                                                   \
3010
uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
3011 3012 3013
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
3014 3015
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3016
    update_fcr31();                                                \
3017
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
3018 3019 3020 3021
        wt2 = FLOAT_QNAN32;                                        \
    return wt2;                                                    \
}                                                                  \
                                                                   \
3022
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
3023 3024 3025 3026 3027 3028 3029 3030
{                                                                  \
    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;                                                 \
                                                                   \
3031 3032 3033
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3034
    update_fcr31();                                                \
3035
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
3036 3037 3038 3039
        wt2 = FLOAT_QNAN32;                                        \
        wth2 = FLOAT_QNAN32;                                       \
    }                                                              \
    return ((uint64_t)wth2 << 32) | wt2;                           \
3040
}
3041

3042 3043 3044 3045 3046 3047
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

3048
/* ternary operations */
3049
#define FLOAT_TERNOP(name1, name2)                                        \
3050
uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
3051 3052
                                           uint64_t fdt2)                 \
{                                                                         \
3053 3054
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
3055 3056
}                                                                         \
                                                                          \
3057
uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
3058 3059
                                           uint32_t fst2)                 \
{                                                                         \
3060 3061
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
3062 3063
}                                                                         \
                                                                          \
3064
uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
3065 3066 3067 3068 3069 3070 3071 3072 3073
                                            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;                                          \
                                                                          \
3074 3075 3076 3077
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
3078
    return ((uint64_t)fsth2 << 32) | fst2;                                \
3079
}
3080

3081 3082 3083 3084 3085
FLOAT_TERNOP(mul, add)
FLOAT_TERNOP(mul, sub)
#undef FLOAT_TERNOP

/* negated ternary operations */
3086
#define FLOAT_NTERNOP(name1, name2)                                       \
3087
uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
3088 3089
                                           uint64_t fdt2)                 \
{                                                                         \
3090 3091
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
3092 3093 3094
    return float64_chs(fdt2);                                             \
}                                                                         \
                                                                          \
3095
uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
3096 3097
                                           uint32_t fst2)                 \
{                                                                         \
3098 3099
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
3100 3101 3102
    return float32_chs(fst2);                                             \
}                                                                         \
                                                                          \
3103
uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
3104 3105 3106 3107 3108 3109 3110 3111 3112
                                           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;                                          \
                                                                          \
3113 3114 3115 3116
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
3117 3118 3119
    fst2 = float32_chs(fst2);                                             \
    fsth2 = float32_chs(fsth2);                                           \
    return ((uint64_t)fsth2 << 32) | fst2;                                \
3120
}
3121

3122 3123 3124 3125
FLOAT_NTERNOP(mul, add)
FLOAT_NTERNOP(mul, sub)
#undef FLOAT_NTERNOP

T
ths 已提交
3126
/* MIPS specific binary operations */
3127
uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3128
{
3129 3130 3131
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
T
ths 已提交
3132
    update_fcr31();
3133
    return fdt2;
T
ths 已提交
3134
}
3135

3136
uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
3137
{
3138 3139 3140
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
T
ths 已提交
3141
    update_fcr31();
3142
    return fst2;
T
ths 已提交
3143
}
3144

3145
uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3146
{
3147 3148 3149 3150 3151
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3152 3153 3154 3155 3156
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
T
ths 已提交
3157
    update_fcr31();
3158
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3159 3160
}

3161
uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3162
{
3163 3164 3165 3166
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
T
ths 已提交
3167
    update_fcr31();
3168
    return fdt2;
T
ths 已提交
3169
}
3170

3171
uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
3172
{
3173 3174 3175 3176
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
T
ths 已提交
3177
    update_fcr31();
3178
    return fst2;
T
ths 已提交
3179
}
3180

3181
uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3182
{
3183 3184 3185 3186 3187
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3188 3189 3190 3191 3192 3193 3194
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
    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));
T
ths 已提交
3195
    update_fcr31();
3196
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3197 3198
}

3199
uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
3200
{
3201 3202 3203 3204 3205 3206 3207
    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;

3208 3209 3210
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3211
    update_fcr31();
3212
    return ((uint64_t)fsth2 << 32) | fst2;
3213 3214
}

3215
uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
3216
{
3217 3218 3219 3220 3221 3222 3223
    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;

3224 3225 3226
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
T
ths 已提交
3227
    update_fcr31();
3228
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3229 3230
}

T
ths 已提交
3231
/* compare operations */
3232
#define FOP_COND_D(op, cond)                                   \
3233
void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
3234
{                                                              \
3235 3236 3237
    int c;                                                     \
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
    c = cond;                                                  \
3238 3239
    update_fcr31();                                            \
    if (c)                                                     \
3240
        SET_FP_COND(cc, env->active_fpu);                      \
3241
    else                                                       \
3242
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3243
}                                                              \
3244
void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3245 3246
{                                                              \
    int c;                                                     \
3247
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
3248 3249 3250 3251 3252
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
3253
        SET_FP_COND(cc, env->active_fpu);                      \
3254
    else                                                       \
3255
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3256 3257 3258
}

/* NOTE: the comma operator will make "cond" to eval to false,
3259 3260 3261
 * 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))
3262
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3263
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3264 3265 3266 3267
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))
3268
/* NOTE: the comma operator will make "cond" to eval to false,
3269 3270 3271
 * 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))
3272 3273 3274
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))
3275
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3276
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3277
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3278 3279

#define FOP_COND_S(op, cond)                                   \
3280
void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
3281
{                                                              \
3282 3283 3284
    int c;                                                     \
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
    c = cond;                                                  \
3285 3286
    update_fcr31();                                            \
    if (c)                                                     \
3287
        SET_FP_COND(cc, env->active_fpu);                      \
3288
    else                                                       \
3289
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3290
}                                                              \
3291
void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
3292 3293
{                                                              \
    int c;                                                     \
3294
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
3295 3296 3297 3298 3299
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
3300
        SET_FP_COND(cc, env->active_fpu);                      \
3301
    else                                                       \
3302
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3303 3304 3305
}

/* NOTE: the comma operator will make "cond" to eval to false,
3306 3307 3308
 * 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))
3309
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3310
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3311 3312 3313 3314
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))
3315
/* NOTE: the comma operator will make "cond" to eval to false,
3316 3317 3318
 * 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))
3319 3320 3321
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))
3322
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3323
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3324
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3325 3326

#define FOP_COND_PS(op, condl, condh)                           \
3327
void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
3328
{                                                               \
3329 3330 3331 3332 3333 3334 3335 3336 3337
    uint32_t fst0, fsth0, fst1, fsth1;                          \
    int ch, cl;                                                 \
    set_float_exception_flags(0, &env->active_fpu.fp_status);   \
    fst0 = fdt0 & 0XFFFFFFFF;                                   \
    fsth0 = fdt0 >> 32;                                         \
    fst1 = fdt1 & 0XFFFFFFFF;                                   \
    fsth1 = fdt1 >> 32;                                         \
    cl = condl;                                                 \
    ch = condh;                                                 \
3338 3339
    update_fcr31();                                             \
    if (cl)                                                     \
3340
        SET_FP_COND(cc, env->active_fpu);                       \
3341
    else                                                        \
3342
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3343
    if (ch)                                                     \
3344
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3345
    else                                                        \
3346
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3347
}                                                               \
3348
void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3349
{                                                               \
3350 3351 3352 3353 3354 3355 3356 3357
    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;                                                 \
3358 3359
    update_fcr31();                                             \
    if (cl)                                                     \
3360
        SET_FP_COND(cc, env->active_fpu);                       \
3361
    else                                                        \
3362
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3363
    if (ch)                                                     \
3364
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3365
    else                                                        \
3366
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3367 3368 3369
}

/* NOTE: the comma operator will make "cond" to eval to false,
3370 3371 3372 3373 3374
 * 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))
3375 3376
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3377 3378
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))
3379 3380 3381 3382 3383 3384 3385 3386
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))
3387
/* NOTE: the comma operator will make "cond" to eval to false,
3388 3389 3390 3391 3392
 * 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))
3393 3394 3395 3396 3397 3398
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))
3399 3400
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))
3401 3402
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3403 3404
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))