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

B
Blue Swirl 已提交
35 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
static inline void compute_hflags(CPUState *env)
{
    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 104
#if !defined(CONFIG_USER_ONLY)
static void do_restore_state (void *pc_ptr)
B
bellard 已提交
105
{
B
bellard 已提交
106 107 108 109 110
    TranslationBlock *tb;
    unsigned long pc = (unsigned long) pc_ptr;
    
    tb = tb_find_pc (pc);
    if (tb) {
111
        cpu_restore_state(tb, env, pc);
B
bellard 已提交
112
    }
B
bellard 已提交
113
}
114
#endif
B
bellard 已提交
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 167
#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

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

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

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

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

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

T
ths 已提交
196
static inline void set_HILO (uint64_t HILO)
B
bellard 已提交
197
{
198 199
    env->active_tc.LO[0] = (int32_t)HILO;
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
B
bellard 已提交
200 201
}

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

208
static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
209
{
210
    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
211
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
212 213 214
}

/* Multiplication variants of the vr54xx. */
215
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
216
{
217
    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
218

219
    return arg1;
220 221
}

222
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
223
{
224
    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
225

226
    return arg1;
227 228
}

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

233
    return arg1;
234 235
}

236
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
237
{
238
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
239

240
    return arg1;
241 242
}

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

247
    return arg1;
248 249
}

250
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
251
{
252
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
253

254
    return arg1;
255 256
}

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

261
    return arg1;
262 263
}

264
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
265
{
266
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
267

268
    return arg1;
269 270
}

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

275
    return arg1;
276 277
}

278
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
279
{
280
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
281

282
    return arg1;
283 284
}

285
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
286
{
287
    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
288

289
    return arg1;
290 291
}

292
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
293
{
294
    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
295

296
    return arg1;
297 298
}

299
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
300
{
301
    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
302

303
    return arg1;
304 305
}

306
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
307
{
308
    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
309

310
    return arg1;
311
}
B
bellard 已提交
312

313
#ifdef TARGET_MIPS64
314
void helper_dmult (target_ulong arg1, target_ulong arg2)
315
{
316
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
317 318
}

319
void helper_dmultu (target_ulong arg1, target_ulong arg2)
320
{
321
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
322 323 324
}
#endif

325
#ifndef CONFIG_USER_ONLY
326 327 328 329 330 331 332 333

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 已提交
334
        cpu_loop_exit(env);
335 336 337 338 339
    } else {
        return lladdr;
    }
}

340 341 342
#define HELPER_LD_ATOMIC(name, insn)                                          \
target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
{                                                                             \
343
    env->lladdr = do_translate_address(arg, 0);                               \
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
    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);                                    \
    }                                                                         \
362
    if (do_translate_address(arg2, 1) == env->lladdr) {                       \
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
        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 已提交
378 379 380 381 382 383 384 385
#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

386
target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
387 388 389
{
    target_ulong tmp;

390
    tmp = do_lbu(arg2, mem_idx);
391
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
392

393
    if (GET_LMASK(arg2) <= 2) {
394
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
395
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
396 397
    }

398
    if (GET_LMASK(arg2) <= 1) {
399
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
400
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
401 402
    }

403
    if (GET_LMASK(arg2) == 0) {
404
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
405
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
406
    }
407
    return (int32_t)arg1;
T
ths 已提交
408 409
}

410
target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
411 412 413
{
    target_ulong tmp;

414
    tmp = do_lbu(arg2, mem_idx);
415
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
416

417
    if (GET_LMASK(arg2) >= 1) {
418
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
419
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
420 421
    }

422
    if (GET_LMASK(arg2) >= 2) {
423
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
424
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
425 426
    }

427
    if (GET_LMASK(arg2) == 3) {
428
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
429
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
430
    }
431
    return (int32_t)arg1;
T
ths 已提交
432 433
}

434
void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
435
{
436
    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
437

438
    if (GET_LMASK(arg2) <= 2)
439
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
440

441
    if (GET_LMASK(arg2) <= 1)
442
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
443

444
    if (GET_LMASK(arg2) == 0)
445
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
T
ths 已提交
446 447
}

448
void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
449
{
450
    do_sb(arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
451

452
    if (GET_LMASK(arg2) >= 1)
453
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
454

455
    if (GET_LMASK(arg2) >= 2)
456
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
457

458
    if (GET_LMASK(arg2) == 3)
459
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
460 461 462 463 464 465 466 467 468 469 470 471
}

#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

472
target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
473 474 475
{
    uint64_t tmp;

476
    tmp = do_lbu(arg2, mem_idx);
477
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
478

479
    if (GET_LMASK64(arg2) <= 6) {
480
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
481
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
482 483
    }

484
    if (GET_LMASK64(arg2) <= 5) {
485
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
486
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
487 488
    }

489
    if (GET_LMASK64(arg2) <= 4) {
490
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
491
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
492 493
    }

494
    if (GET_LMASK64(arg2) <= 3) {
495
        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
496
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
497 498
    }

499
    if (GET_LMASK64(arg2) <= 2) {
500
        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
501
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
502 503
    }

504
    if (GET_LMASK64(arg2) <= 1) {
505
        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
506
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
T
ths 已提交
507 508
    }

509
    if (GET_LMASK64(arg2) == 0) {
510
        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
511
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
512
    }
513

514
    return arg1;
T
ths 已提交
515 516
}

517
target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
518 519 520
{
    uint64_t tmp;

521
    tmp = do_lbu(arg2, mem_idx);
522
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
523

524
    if (GET_LMASK64(arg2) >= 1) {
525
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
526
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
T
ths 已提交
527 528
    }

529
    if (GET_LMASK64(arg2) >= 2) {
530
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
531
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
532 533
    }

534
    if (GET_LMASK64(arg2) >= 3) {
535
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
536
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
537 538
    }

539
    if (GET_LMASK64(arg2) >= 4) {
540
        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
541
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
542 543
    }

544
    if (GET_LMASK64(arg2) >= 5) {
545
        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
546
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
547 548
    }

549
    if (GET_LMASK64(arg2) >= 6) {
550
        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
551
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
552 553
    }

554
    if (GET_LMASK64(arg2) == 7) {
555
        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
556
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
557
    }
558

559
    return arg1;
T
ths 已提交
560 561
}

562
void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
563
{
564
    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
565

566
    if (GET_LMASK64(arg2) <= 6)
567
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
568

569
    if (GET_LMASK64(arg2) <= 5)
570
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
571

572
    if (GET_LMASK64(arg2) <= 4)
573
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
574

575
    if (GET_LMASK64(arg2) <= 3)
576
        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
577

578
    if (GET_LMASK64(arg2) <= 2)
579
        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
580

581
    if (GET_LMASK64(arg2) <= 1)
582
        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
583

584
    if (GET_LMASK64(arg2) <= 0)
585
        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
T
ths 已提交
586 587
}

588
void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
589
{
590
    do_sb(arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
591

592
    if (GET_LMASK64(arg2) >= 1)
593
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
594

595
    if (GET_LMASK64(arg2) >= 2)
596
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
597

598
    if (GET_LMASK64(arg2) >= 3)
599
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
600

601
    if (GET_LMASK64(arg2) >= 4)
602
        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
603

604
    if (GET_LMASK64(arg2) >= 5)
605
        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
606

607
    if (GET_LMASK64(arg2) >= 6)
608
        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
609

610
    if (GET_LMASK64(arg2) == 7)
611
        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
612 613 614
}
#endif /* TARGET_MIPS64 */

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 744 745 746 747 748 749 750
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 已提交
751
#ifndef CONFIG_USER_ONLY
B
bellard 已提交
752
/* CP0 helpers */
753
target_ulong helper_mfc0_mvpcontrol (void)
754
{
755
    return env->mvp->CP0_MVPControl;
756 757
}

758
target_ulong helper_mfc0_mvpconf0 (void)
759
{
760
    return env->mvp->CP0_MVPConf0;
761 762
}

763
target_ulong helper_mfc0_mvpconf1 (void)
764
{
765
    return env->mvp->CP0_MVPConf1;
766 767
}

768
target_ulong helper_mfc0_random (void)
B
bellard 已提交
769
{
770
    return (int32_t)cpu_mips_get_random(env);
771
}
B
bellard 已提交
772

773
target_ulong helper_mfc0_tcstatus (void)
774
{
775
    return env->active_tc.CP0_TCStatus;
776 777
}

778
target_ulong helper_mftc0_tcstatus(void)
779 780 781
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

782 783 784 785
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCStatus;
    else
        return env->tcs[other_tc].CP0_TCStatus;
786 787
}

788
target_ulong helper_mfc0_tcbind (void)
789
{
790
    return env->active_tc.CP0_TCBind;
791 792
}

793
target_ulong helper_mftc0_tcbind(void)
794 795 796
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

797 798 799 800
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCBind;
    else
        return env->tcs[other_tc].CP0_TCBind;
801 802
}

803
target_ulong helper_mfc0_tcrestart (void)
804
{
805
    return env->active_tc.PC;
806 807
}

808
target_ulong helper_mftc0_tcrestart(void)
809 810 811
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

812 813 814 815
    if (other_tc == env->current_tc)
        return env->active_tc.PC;
    else
        return env->tcs[other_tc].PC;
816 817
}

818
target_ulong helper_mfc0_tchalt (void)
819
{
820
    return env->active_tc.CP0_TCHalt;
821 822
}

823
target_ulong helper_mftc0_tchalt(void)
824 825 826
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

827 828 829 830
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCHalt;
    else
        return env->tcs[other_tc].CP0_TCHalt;
831 832
}

833
target_ulong helper_mfc0_tccontext (void)
834
{
835
    return env->active_tc.CP0_TCContext;
836 837
}

838
target_ulong helper_mftc0_tccontext(void)
839 840 841
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

842 843 844 845
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCContext;
    else
        return env->tcs[other_tc].CP0_TCContext;
846 847
}

848
target_ulong helper_mfc0_tcschedule (void)
849
{
850
    return env->active_tc.CP0_TCSchedule;
851 852
}

853
target_ulong helper_mftc0_tcschedule(void)
854 855 856
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

857 858 859 860
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCSchedule;
    else
        return env->tcs[other_tc].CP0_TCSchedule;
861 862
}

863
target_ulong helper_mfc0_tcschefback (void)
864
{
865
    return env->active_tc.CP0_TCScheFBack;
866 867
}

868
target_ulong helper_mftc0_tcschefback(void)
869 870 871
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

872 873 874 875
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCScheFBack;
    else
        return env->tcs[other_tc].CP0_TCScheFBack;
876 877
}

878
target_ulong helper_mfc0_count (void)
879
{
880
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
881 882
}

883
target_ulong helper_mftc0_entryhi(void)
884 885
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
886
    int32_t tcstatus;
887

888 889 890 891 892 893
    if (other_tc == env->current_tc)
        tcstatus = env->active_tc.CP0_TCStatus;
    else
        tcstatus = env->tcs[other_tc].CP0_TCStatus;

    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
894 895
}

896
target_ulong helper_mftc0_status(void)
897 898
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
899
    target_ulong t0;
900 901 902 903 904 905
    int32_t tcstatus;

    if (other_tc == env->current_tc)
        tcstatus = env->active_tc.CP0_TCStatus;
    else
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
906

907 908 909 910 911 912
    t0 = env->CP0_Status & ~0xf1000018;
    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);

    return t0;
913 914
}

915
target_ulong helper_mfc0_lladdr (void)
916
{
917
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
918 919
}

920
target_ulong helper_mfc0_watchlo (uint32_t sel)
921
{
922
    return (int32_t)env->CP0_WatchLo[sel];
923 924
}

925
target_ulong helper_mfc0_watchhi (uint32_t sel)
926
{
927
    return env->CP0_WatchHi[sel];
928 929
}

930
target_ulong helper_mfc0_debug (void)
931
{
932
    target_ulong t0 = env->CP0_Debug;
933
    if (env->hflags & MIPS_HFLAG_DM)
934 935 936
        t0 |= 1 << CP0DB_DM;

    return t0;
937 938
}

939
target_ulong helper_mftc0_debug(void)
940 941
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
942 943 944 945 946 947
    int32_t tcstatus;

    if (other_tc == env->current_tc)
        tcstatus = env->active_tc.CP0_Debug_tcstatus;
    else
        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
948 949

    /* XXX: Might be wrong, check with EJTAG spec. */
950
    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
951
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
952 953 954
}

#if defined(TARGET_MIPS64)
955
target_ulong helper_dmfc0_tcrestart (void)
956
{
957
    return env->active_tc.PC;
958 959
}

960
target_ulong helper_dmfc0_tchalt (void)
961
{
962
    return env->active_tc.CP0_TCHalt;
963 964
}

965
target_ulong helper_dmfc0_tccontext (void)
966
{
967
    return env->active_tc.CP0_TCContext;
968 969
}

970
target_ulong helper_dmfc0_tcschedule (void)
971
{
972
    return env->active_tc.CP0_TCSchedule;
973 974
}

975
target_ulong helper_dmfc0_tcschefback (void)
976
{
977
    return env->active_tc.CP0_TCScheFBack;
978 979
}

980
target_ulong helper_dmfc0_lladdr (void)
981
{
982
    return env->lladdr >> env->CP0_LLAddr_shift;
983 984
}

985
target_ulong helper_dmfc0_watchlo (uint32_t sel)
986
{
987
    return env->CP0_WatchLo[sel];
988 989 990
}
#endif /* TARGET_MIPS64 */

991
void helper_mtc0_index (target_ulong arg1)
992 993 994 995 996 997 998 999
{
    int num = 1;
    unsigned int tmp = env->tlb->nb_tlb;

    do {
        tmp >>= 1;
        num <<= 1;
    } while (tmp);
1000
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
1001 1002
}

1003
void helper_mtc0_mvpcontrol (target_ulong arg1)
1004 1005 1006 1007 1008 1009 1010 1011 1012
{
    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);
1013
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1014 1015 1016 1017 1018 1019

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

    env->mvp->CP0_MVPControl = newval;
}

1020
void helper_mtc0_vpecontrol (target_ulong arg1)
1021 1022 1023 1024 1025 1026
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1027
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1028 1029 1030 1031 1032 1033 1034 1035 1036

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

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

1037
void helper_mtc0_vpeconf0 (target_ulong arg1)
1038 1039 1040 1041 1042 1043 1044 1045 1046
{
    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);
    }
1047
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1048 1049 1050 1051 1052 1053

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

    env->CP0_VPEConf0 = newval;
}

1054
void helper_mtc0_vpeconf1 (target_ulong arg1)
1055 1056 1057 1058 1059 1060 1061
{
    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);
1062
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1063 1064 1065 1066 1067 1068 1069 1070 1071

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

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

1072
void helper_mtc0_yqmask (target_ulong arg1)
1073 1074 1075 1076 1077
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

1078
void helper_mtc0_vpeopt (target_ulong arg1)
1079
{
1080
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1081 1082
}

1083
void helper_mtc0_entrylo0 (target_ulong arg1)
1084 1085 1086
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1087
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1088 1089
}

1090
void helper_mtc0_tcstatus (target_ulong arg1)
1091 1092 1093 1094
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

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

    // TODO: Sync with CP0_Status.

1099
    env->active_tc.CP0_TCStatus = newval;
1100 1101
}

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

    // TODO: Sync with CP0_Status.

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

1114
void helper_mtc0_tcbind (target_ulong arg1)
1115 1116 1117 1118 1119 1120
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

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

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

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

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

1150
void helper_mttc0_tcrestart (target_ulong arg1)
1151 1152 1153
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

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

1167
void helper_mtc0_tchalt (target_ulong arg1)
1168
{
1169
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1170 1171 1172 1173

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

1174
void helper_mttc0_tchalt (target_ulong arg1)
1175 1176 1177 1178 1179
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

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

1180
    if (other_tc == env->current_tc)
1181
        env->active_tc.CP0_TCHalt = arg1;
1182
    else
1183
        env->tcs[other_tc].CP0_TCHalt = arg1;
1184 1185
}

1186
void helper_mtc0_tccontext (target_ulong arg1)
1187
{
1188
    env->active_tc.CP0_TCContext = arg1;
1189 1190
}

1191
void helper_mttc0_tccontext (target_ulong arg1)
1192 1193 1194
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1195
    if (other_tc == env->current_tc)
1196
        env->active_tc.CP0_TCContext = arg1;
1197
    else
1198
        env->tcs[other_tc].CP0_TCContext = arg1;
1199 1200
}

1201
void helper_mtc0_tcschedule (target_ulong arg1)
1202
{
1203
    env->active_tc.CP0_TCSchedule = arg1;
1204 1205
}

1206
void helper_mttc0_tcschedule (target_ulong arg1)
1207 1208 1209
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1210
    if (other_tc == env->current_tc)
1211
        env->active_tc.CP0_TCSchedule = arg1;
1212
    else
1213
        env->tcs[other_tc].CP0_TCSchedule = arg1;
1214 1215
}

1216
void helper_mtc0_tcschefback (target_ulong arg1)
1217
{
1218
    env->active_tc.CP0_TCScheFBack = arg1;
1219 1220
}

1221
void helper_mttc0_tcschefback (target_ulong arg1)
1222 1223 1224
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1225
    if (other_tc == env->current_tc)
1226
        env->active_tc.CP0_TCScheFBack = arg1;
1227
    else
1228
        env->tcs[other_tc].CP0_TCScheFBack = arg1;
1229 1230
}

1231
void helper_mtc0_entrylo1 (target_ulong arg1)
1232 1233 1234
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1235
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1236 1237
}

1238
void helper_mtc0_context (target_ulong arg1)
1239
{
1240
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1241 1242
}

1243
void helper_mtc0_pagemask (target_ulong arg1)
1244 1245
{
    /* 1k pages not implemented */
1246
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1247 1248
}

1249
void helper_mtc0_pagegrain (target_ulong arg1)
1250 1251 1252 1253 1254 1255 1256
{
    /* SmartMIPS not implemented */
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
    env->CP0_PageGrain = 0;
}

1257
void helper_mtc0_wired (target_ulong arg1)
1258
{
1259
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1260 1261
}

1262
void helper_mtc0_srsconf0 (target_ulong arg1)
1263
{
1264
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1265 1266
}

1267
void helper_mtc0_srsconf1 (target_ulong arg1)
1268
{
1269
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1270 1271
}

1272
void helper_mtc0_srsconf2 (target_ulong arg1)
1273
{
1274
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1275 1276
}

1277
void helper_mtc0_srsconf3 (target_ulong arg1)
1278
{
1279
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1280 1281
}

1282
void helper_mtc0_srsconf4 (target_ulong arg1)
1283
{
1284
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1285 1286
}

1287
void helper_mtc0_hwrena (target_ulong arg1)
1288
{
1289
    env->CP0_HWREna = arg1 & 0x0000000F;
1290 1291
}

1292
void helper_mtc0_count (target_ulong arg1)
1293
{
1294
    cpu_mips_store_count(env, arg1);
1295 1296
}

1297
void helper_mtc0_entryhi (target_ulong arg1)
1298 1299 1300 1301
{
    target_ulong old, val;

    /* 1k pages not implemented */
1302
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1303 1304 1305 1306 1307 1308
#if defined(TARGET_MIPS64)
    val &= env->SEGMask;
#endif
    old = env->CP0_EntryHi;
    env->CP0_EntryHi = val;
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1309 1310
        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
1311 1312 1313 1314 1315 1316
    }
    /* If the ASID changes, flush qemu's TLB.  */
    if ((old & 0xFF) != (val & 0xFF))
        cpu_mips_tlb_flush(env, 1);
}

1317
void helper_mttc0_entryhi(target_ulong arg1)
1318 1319
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1320
    int32_t tcstatus;
1321

1322
    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
1323
    if (other_tc == env->current_tc) {
1324
        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1325 1326
        env->active_tc.CP0_TCStatus = tcstatus;
    } else {
1327
        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1328 1329
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
    }
1330 1331
}

1332
void helper_mtc0_compare (target_ulong arg1)
1333
{
1334
    cpu_mips_store_compare(env, arg1);
1335 1336
}

1337
void helper_mtc0_status (target_ulong arg1)
1338 1339 1340 1341
{
    uint32_t val, old;
    uint32_t mask = env->CP0_Status_rw_bitmask;

1342
    val = arg1 & mask;
1343 1344 1345
    old = env->CP0_Status;
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
    compute_hflags(env);
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
    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 已提交
1356
        }
1357
    }
1358 1359
}

1360
void helper_mttc0_status(target_ulong arg1)
1361 1362
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1363
    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
1364

1365 1366 1367 1368
    env->CP0_Status = arg1 & ~0xf1000018;
    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1369 1370 1371 1372
    if (other_tc == env->current_tc)
        env->active_tc.CP0_TCStatus = tcstatus;
    else
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1373 1374
}

1375
void helper_mtc0_intctl (target_ulong arg1)
1376 1377
{
    /* vectored interrupts not implemented, no performance counters. */
1378
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
1379 1380
}

1381
void helper_mtc0_srsctl (target_ulong arg1)
1382 1383
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1384
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1385 1386
}

1387
void helper_mtc0_cause (target_ulong arg1)
1388 1389 1390
{
    uint32_t mask = 0x00C00300;
    uint32_t old = env->CP0_Cause;
1391
    int i;
1392 1393 1394 1395

    if (env->insn_flags & ISA_MIPS32R2)
        mask |= 1 << CP0Ca_DC;

1396
    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
1397 1398 1399 1400 1401 1402 1403

    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
        if (env->CP0_Cause & (1 << CP0Ca_DC))
            cpu_mips_stop_count(env);
        else
            cpu_mips_start_count(env);
    }
1404 1405 1406 1407 1408 1409 1410

    /* Set/reset software interrupts */
    for (i = 0 ; i < 2 ; i++) {
        if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
            cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
        }
    }
1411 1412
}

1413
void helper_mtc0_ebase (target_ulong arg1)
1414 1415
{
    /* vectored interrupts not implemented */
1416
    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1417 1418
}

1419
void helper_mtc0_config0 (target_ulong arg1)
1420
{
1421
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1422 1423
}

1424
void helper_mtc0_config2 (target_ulong arg1)
1425 1426 1427 1428 1429
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1430 1431 1432 1433 1434 1435 1436
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);
}

1437
void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1438 1439 1440
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1441
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1442 1443
}

1444
void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1445
{
1446 1447
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1448 1449
}

1450
void helper_mtc0_xcontext (target_ulong arg1)
1451 1452
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1453
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1454 1455
}

1456
void helper_mtc0_framemask (target_ulong arg1)
1457
{
1458
    env->CP0_Framemask = arg1; /* XXX */
1459 1460
}

1461
void helper_mtc0_debug (target_ulong arg1)
1462
{
1463 1464
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1465 1466 1467 1468 1469
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1470
void helper_mttc0_debug(target_ulong arg1)
1471 1472
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1473
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1474 1475

    /* XXX: Might be wrong, check with EJTAG spec. */
1476 1477 1478 1479
    if (other_tc == env->current_tc)
        env->active_tc.CP0_Debug_tcstatus = val;
    else
        env->tcs[other_tc].CP0_Debug_tcstatus = val;
1480
    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1481
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1482 1483
}

1484
void helper_mtc0_performance0 (target_ulong arg1)
1485
{
1486
    env->CP0_Performance0 = arg1 & 0x000007ff;
1487 1488
}

1489
void helper_mtc0_taglo (target_ulong arg1)
1490
{
1491
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1492 1493
}

1494
void helper_mtc0_datalo (target_ulong arg1)
1495
{
1496
    env->CP0_DataLo = arg1; /* XXX */
1497 1498
}

1499
void helper_mtc0_taghi (target_ulong arg1)
1500
{
1501
    env->CP0_TagHi = arg1; /* XXX */
1502 1503
}

1504
void helper_mtc0_datahi (target_ulong arg1)
1505
{
1506
    env->CP0_DataHi = arg1; /* XXX */
1507 1508 1509
}

/* MIPS MT functions */
1510
target_ulong helper_mftgpr(uint32_t sel)
1511 1512 1513
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1514 1515 1516 1517
    if (other_tc == env->current_tc)
        return env->active_tc.gpr[sel];
    else
        return env->tcs[other_tc].gpr[sel];
1518 1519
}

1520
target_ulong helper_mftlo(uint32_t sel)
1521 1522 1523
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1524 1525 1526 1527
    if (other_tc == env->current_tc)
        return env->active_tc.LO[sel];
    else
        return env->tcs[other_tc].LO[sel];
1528 1529
}

1530
target_ulong helper_mfthi(uint32_t sel)
1531 1532 1533
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1534 1535 1536 1537
    if (other_tc == env->current_tc)
        return env->active_tc.HI[sel];
    else
        return env->tcs[other_tc].HI[sel];
1538 1539
}

1540
target_ulong helper_mftacx(uint32_t sel)
1541 1542 1543
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1544 1545 1546 1547
    if (other_tc == env->current_tc)
        return env->active_tc.ACX[sel];
    else
        return env->tcs[other_tc].ACX[sel];
1548 1549
}

1550
target_ulong helper_mftdsp(void)
1551 1552 1553
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1554 1555 1556 1557
    if (other_tc == env->current_tc)
        return env->active_tc.DSPControl;
    else
        return env->tcs[other_tc].DSPControl;
1558
}
B
bellard 已提交
1559

1560
void helper_mttgpr(target_ulong arg1, uint32_t sel)
1561 1562 1563
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1564
    if (other_tc == env->current_tc)
1565
        env->active_tc.gpr[sel] = arg1;
1566
    else
1567
        env->tcs[other_tc].gpr[sel] = arg1;
1568 1569
}

1570
void helper_mttlo(target_ulong arg1, uint32_t sel)
1571 1572 1573
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1574
    if (other_tc == env->current_tc)
1575
        env->active_tc.LO[sel] = arg1;
1576
    else
1577
        env->tcs[other_tc].LO[sel] = arg1;
1578 1579
}

1580
void helper_mtthi(target_ulong arg1, uint32_t sel)
1581 1582 1583
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1584
    if (other_tc == env->current_tc)
1585
        env->active_tc.HI[sel] = arg1;
1586
    else
1587
        env->tcs[other_tc].HI[sel] = arg1;
1588 1589
}

1590
void helper_mttacx(target_ulong arg1, uint32_t sel)
1591 1592 1593
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1594
    if (other_tc == env->current_tc)
1595
        env->active_tc.ACX[sel] = arg1;
1596
    else
1597
        env->tcs[other_tc].ACX[sel] = arg1;
1598 1599
}

1600
void helper_mttdsp(target_ulong arg1)
1601 1602 1603
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1604
    if (other_tc == env->current_tc)
1605
        env->active_tc.DSPControl = arg1;
1606
    else
1607
        env->tcs[other_tc].DSPControl = arg1;
1608 1609 1610
}

/* MIPS MT functions */
1611
target_ulong helper_dmt(void)
1612 1613
{
    // TODO
1614
     return 0;
1615 1616
}

1617
target_ulong helper_emt(void)
1618 1619
{
    // TODO
1620
    return 0;
1621 1622
}

1623
target_ulong helper_dvpe(void)
1624 1625
{
    // TODO
1626
    return 0;
1627 1628
}

1629
target_ulong helper_evpe(void)
1630 1631
{
    // TODO
1632
    return 0;
1633
}
1634
#endif /* !CONFIG_USER_ONLY */
1635

1636
void helper_fork(target_ulong arg1, target_ulong arg2)
1637
{
1638 1639
    // arg1 = rt, arg2 = rs
    arg1 = 0;
1640 1641 1642
    // TODO: store to TC register
}

B
Blue Swirl 已提交
1643
target_ulong helper_yield(target_ulong arg)
1644
{
B
Blue Swirl 已提交
1645 1646
    target_long arg1 = arg;

1647
    if (arg1 < 0) {
1648
        /* No scheduling policy implemented. */
1649
        if (arg1 != -2) {
1650
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1651
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1652 1653
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1654
                helper_raise_exception(EXCP_THREAD);
1655 1656
            }
        }
1657
    } else if (arg1 == 0) {
A
aurel32 已提交
1658
        if (0 /* TODO: TC underflow */) {
1659
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1660
            helper_raise_exception(EXCP_THREAD);
1661 1662 1663
        } else {
            // TODO: Deallocate TC
        }
1664
    } else if (arg1 > 0) {
1665 1666 1667
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1668
        helper_raise_exception(EXCP_THREAD);
1669
    }
1670
    return env->CP0_YQMask;
1671 1672 1673
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1674
/* TLB management */
1675
static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1676 1677 1678
{
    /* Flush qemu's TLB and discard all shadowed entries.  */
    tlb_flush (env, flush_global);
1679
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1680 1681
}

1682
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1683 1684
{
    /* Discard entries from env->tlb[first] onwards.  */
1685 1686
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1687 1688 1689
    }
}

1690
static void r4k_fill_tlb (int idx)
B
bellard 已提交
1691
{
A
Anthony Liguori 已提交
1692
    r4k_tlb_t *tlb;
B
bellard 已提交
1693 1694

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1695
    tlb = &env->tlb->mmu.r4k.tlb[idx];
T
ths 已提交
1696
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1697
#if defined(TARGET_MIPS64)
T
ths 已提交
1698
    tlb->VPN &= env->SEGMask;
1699
#endif
1700
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
1701
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
1702
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1703 1704 1705
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
B
bellard 已提交
1706
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1707 1708 1709
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
B
bellard 已提交
1710 1711 1712
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}

1713
void r4k_helper_tlbwi (void)
B
bellard 已提交
1714
{
A
aurel32 已提交
1715 1716 1717 1718
    int idx;

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

1719 1720 1721
    /* 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.  */
1722
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1723

A
aurel32 已提交
1724 1725
    r4k_invalidate_tlb(env, idx, 0);
    r4k_fill_tlb(idx);
B
bellard 已提交
1726 1727
}

1728
void r4k_helper_tlbwr (void)
B
bellard 已提交
1729 1730 1731
{
    int r = cpu_mips_get_random(env);

1732 1733
    r4k_invalidate_tlb(env, r, 1);
    r4k_fill_tlb(r);
B
bellard 已提交
1734 1735
}

1736
void r4k_helper_tlbp (void)
B
bellard 已提交
1737
{
A
Anthony Liguori 已提交
1738
    r4k_tlb_t *tlb;
T
ths 已提交
1739
    target_ulong mask;
B
bellard 已提交
1740
    target_ulong tag;
T
ths 已提交
1741
    target_ulong VPN;
B
bellard 已提交
1742 1743 1744
    uint8_t ASID;
    int i;

B
bellard 已提交
1745
    ASID = env->CP0_EntryHi & 0xFF;
1746 1747
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
1748 1749 1750 1751
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
B
bellard 已提交
1752
        /* Check ASID, virtual page number & size */
T
ths 已提交
1753
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
B
bellard 已提交
1754
            /* TLB match */
T
ths 已提交
1755
            env->CP0_Index = i;
B
bellard 已提交
1756 1757 1758
            break;
        }
    }
1759
    if (i == env->tlb->nb_tlb) {
1760
        /* No match.  Discard any shadow entries, if any of them match.  */
1761
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
1762 1763 1764 1765 1766 1767 1768
            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) {
1769
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
1770 1771 1772
                break;
            }
        }
1773

T
ths 已提交
1774
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
1775 1776 1777
    }
}

1778
void r4k_helper_tlbr (void)
B
bellard 已提交
1779
{
A
Anthony Liguori 已提交
1780
    r4k_tlb_t *tlb;
1781
    uint8_t ASID;
A
aurel32 已提交
1782
    int idx;
B
bellard 已提交
1783

1784
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
1785 1786
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
1787 1788

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

1792
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
1793

B
bellard 已提交
1794
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
T
ths 已提交
1795
    env->CP0_PageMask = tlb->PageMask;
T
ths 已提交
1796 1797 1798 1799
    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 已提交
1800 1801
}

1802
void helper_tlbwi(void)
P
pbrook 已提交
1803
{
1804
    env->tlb->helper_tlbwi();
P
pbrook 已提交
1805 1806
}

1807
void helper_tlbwr(void)
P
pbrook 已提交
1808
{
1809
    env->tlb->helper_tlbwr();
P
pbrook 已提交
1810 1811
}

1812
void helper_tlbp(void)
P
pbrook 已提交
1813
{
1814
    env->tlb->helper_tlbp();
P
pbrook 已提交
1815 1816
}

1817
void helper_tlbr(void)
P
pbrook 已提交
1818
{
1819
    env->tlb->helper_tlbr();
P
pbrook 已提交
1820 1821
}

1822
/* Specials */
1823
target_ulong helper_di (void)
1824
{
1825 1826
    target_ulong t0 = env->CP0_Status;

1827 1828
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
    return t0;
1829 1830
}

1831
target_ulong helper_ei (void)
1832
{
1833 1834
    target_ulong t0 = env->CP0_Status;

1835 1836
    env->CP0_Status = t0 | (1 << CP0St_IE);
    return t0;
1837 1838
}

A
aurel32 已提交
1839
static void debug_pre_eret (void)
B
bellard 已提交
1840
{
1841
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1842 1843 1844 1845 1846 1847 1848 1849
        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");
    }
1850 1851
}

A
aurel32 已提交
1852
static void debug_post_eret (void)
1853
{
1854
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
        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 已提交
1867
    }
B
bellard 已提交
1868 1869
}

1870 1871 1872 1873 1874 1875 1876 1877 1878 1879
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);
    }
}

1880
void helper_eret (void)
1881
{
1882
    debug_pre_eret();
1883
    if (env->CP0_Status & (1 << CP0St_ERL)) {
1884
        set_pc(env->CP0_ErrorEPC);
1885 1886
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
1887
        set_pc(env->CP0_EPC);
1888 1889 1890
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
1891
    debug_post_eret();
1892
    env->lladdr = 1;
1893 1894
}

1895
void helper_deret (void)
1896
{
1897
    debug_pre_eret();
1898 1899
    set_pc(env->CP0_DEPC);

1900 1901
    env->hflags &= MIPS_HFLAG_DM;
    compute_hflags(env);
1902
    debug_post_eret();
1903
    env->lladdr = 1;
1904
}
T
ths 已提交
1905
#endif /* !CONFIG_USER_ONLY */
1906

1907
target_ulong helper_rdhwr_cpunum(void)
1908 1909 1910
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 0)))
1911
        return env->CP0_EBase & 0x3ff;
1912
    else
1913
        helper_raise_exception(EXCP_RI);
1914

1915
    return 0;
1916 1917
}

1918
target_ulong helper_rdhwr_synci_step(void)
1919 1920 1921
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 1)))
1922
        return env->SYNCI_Step;
1923
    else
1924
        helper_raise_exception(EXCP_RI);
1925

1926
    return 0;
1927 1928
}

1929
target_ulong helper_rdhwr_cc(void)
1930 1931 1932
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 2)))
1933
        return env->CP0_Count;
1934
    else
1935
        helper_raise_exception(EXCP_RI);
1936

1937
    return 0;
1938 1939
}

1940
target_ulong helper_rdhwr_ccres(void)
1941 1942 1943
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 3)))
1944
        return env->CCRes;
1945
    else
1946
        helper_raise_exception(EXCP_RI);
1947

1948
    return 0;
1949 1950
}

1951
void helper_pmon (int function)
B
bellard 已提交
1952 1953 1954 1955
{
    function /= 2;
    switch (function) {
    case 2: /* TODO: char inbyte(int waitflag); */
1956 1957
        if (env->active_tc.gpr[4] == 0)
            env->active_tc.gpr[2] = -1;
B
bellard 已提交
1958 1959
        /* Fall through */
    case 11: /* TODO: char inbyte (void); */
1960
        env->active_tc.gpr[2] = -1;
B
bellard 已提交
1961 1962 1963
        break;
    case 3:
    case 12:
1964
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
B
bellard 已提交
1965 1966 1967 1968 1969
        break;
    case 17:
        break;
    case 158:
        {
1970
            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
B
bellard 已提交
1971 1972 1973 1974 1975
            printf("%s", fmt);
        }
        break;
    }
}
1976

1977
void helper_wait (void)
T
ths 已提交
1978 1979
{
    env->halted = 1;
1980
    helper_raise_exception(EXCP_HLT);
T
ths 已提交
1981 1982
}

1983
#if !defined(CONFIG_USER_ONLY)
1984

B
bellard 已提交
1985 1986
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);

1987
#define MMUSUFFIX _mmu
B
bellard 已提交
1988
#define ALIGNED_ONLY
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001

#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"

B
bellard 已提交
2002 2003 2004 2005
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
{
    env->CP0_BadVAddr = addr;
    do_restore_state (retaddr);
2006
    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
B
bellard 已提交
2007 2008
}

2009
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
{
    TranslationBlock *tb;
    CPUState *saved_env;
    unsigned long pc;
    int ret;

    /* XXX: hack to restore env in all cases, even if not called from
       generated code */
    saved_env = env;
    env = cpu_single_env;
2020
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2021 2022 2023 2024 2025 2026 2027 2028
    if (ret) {
        if (retaddr) {
            /* now we have a real cpu fault */
            pc = (unsigned long)retaddr;
            tb = tb_find_pc(pc);
            if (tb) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
2029
                cpu_restore_state(tb, env, pc);
2030 2031
            }
        }
2032
        helper_raise_exception_err(env->exception_index, env->error_code);
2033 2034 2035 2036
    }
    env = saved_env;
}

2037 2038
void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
                           int is_write, int is_exec, int unused, int size)
T
ths 已提交
2039
{
2040 2041
    env = env1;

T
ths 已提交
2042
    if (is_exec)
2043
        helper_raise_exception(EXCP_IBE);
T
ths 已提交
2044
    else
2045
        helper_raise_exception(EXCP_DBE);
T
ths 已提交
2046
}
2047
#endif /* !CONFIG_USER_ONLY */
2048 2049 2050

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

P
pbrook 已提交
2051 2052 2053 2054
#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 已提交
2055 2056 2057 2058
#define FLOAT_QNAN32 0x7fbfffff
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
#define FLOAT_SNAN32 0x7fffffff
#define FLOAT_SNAN64 0x7fffffffffffffffULL
T
ths 已提交
2059

2060
/* convert MIPS rounding mode in FCR31 to IEEE library */
B
Blue Swirl 已提交
2061
static unsigned int ieee_rm[] = {
2062 2063 2064 2065 2066 2067 2068
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

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

2071 2072 2073
#define RESTORE_FLUSH_MODE \
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);

2074
target_ulong helper_cfc1 (uint32_t reg)
2075
{
2076
    target_ulong arg1;
2077

2078 2079
    switch (reg) {
    case 0:
2080
        arg1 = (int32_t)env->active_fpu.fcr0;
2081 2082
        break;
    case 25:
2083
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2084 2085
        break;
    case 26:
2086
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2087 2088
        break;
    case 28:
2089
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2090 2091
        break;
    default:
2092
        arg1 = (int32_t)env->active_fpu.fcr31;
2093 2094
        break;
    }
2095

2096
    return arg1;
2097 2098
}

2099
void helper_ctc1 (target_ulong arg1, uint32_t reg)
2100 2101
{
    switch(reg) {
2102
    case 25:
2103
        if (arg1 & 0xffffff00)
2104
            return;
2105 2106
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2107 2108
        break;
    case 26:
2109
        if (arg1 & 0x007c0000)
2110
            return;
2111
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2112 2113
        break;
    case 28:
2114
        if (arg1 & 0x007c0000)
2115
            return;
2116 2117
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2118 2119
        break;
    case 31:
2120
        if (arg1 & 0x007c0000)
2121
            return;
2122
        env->active_fpu.fcr31 = arg1;
2123 2124 2125 2126 2127 2128
        break;
    default:
        return;
    }
    /* set rounding mode */
    RESTORE_ROUNDING_MODE;
2129 2130
    /* set flush-to-zero mode */
    RESTORE_FLUSH_MODE;
2131 2132
    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))
2133
        helper_raise_exception(EXCP_FPE);
2134 2135
}

2136
static inline int ieee_ex_to_mips(int xcpt)
2137
{
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156
    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;
2157 2158
}

T
ths 已提交
2159
static inline void update_fcr31(void)
2160
{
2161
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2162

2163 2164
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
2165
        helper_raise_exception(EXCP_FPE);
2166
    else
2167
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2168 2169
}

2170 2171 2172 2173 2174 2175
/* 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  */
2176
uint64_t helper_float_sqrt_d(uint64_t fdt0)
2177
{
2178
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2179 2180
}

2181
uint32_t helper_float_sqrt_s(uint32_t fst0)
2182
{
2183
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
2184
}
2185

2186
uint64_t helper_float_cvtd_s(uint32_t fst0)
2187
{
2188 2189
    uint64_t fdt2;

2190 2191
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2192
    update_fcr31();
2193
    return fdt2;
2194
}
2195

2196
uint64_t helper_float_cvtd_w(uint32_t wt0)
2197
{
2198 2199
    uint64_t fdt2;

2200 2201
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2202
    update_fcr31();
2203
    return fdt2;
2204
}
2205

2206
uint64_t helper_float_cvtd_l(uint64_t dt0)
2207
{
2208 2209
    uint64_t fdt2;

2210 2211
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2212
    update_fcr31();
2213
    return fdt2;
2214
}
2215

2216
uint64_t helper_float_cvtl_d(uint64_t fdt0)
2217
{
2218 2219
    uint64_t dt2;

2220 2221
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2222
    update_fcr31();
2223
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2224 2225
        dt2 = FLOAT_SNAN64;
    return dt2;
2226
}
2227

2228
uint64_t helper_float_cvtl_s(uint32_t fst0)
2229
{
2230 2231
    uint64_t dt2;

2232 2233
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2234
    update_fcr31();
2235
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2236 2237
        dt2 = FLOAT_SNAN64;
    return dt2;
2238 2239
}

2240
uint64_t helper_float_cvtps_pw(uint64_t dt0)
2241
{
2242 2243 2244
    uint32_t fst2;
    uint32_t fsth2;

2245 2246 2247
    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);
2248
    update_fcr31();
2249
    return ((uint64_t)fsth2 << 32) | fst2;
2250
}
2251

2252
uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2253
{
2254 2255 2256
    uint32_t wt2;
    uint32_t wth2;

2257 2258 2259
    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);
2260
    update_fcr31();
2261
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2262 2263 2264 2265
        wt2 = FLOAT_SNAN32;
        wth2 = FLOAT_SNAN32;
    }
    return ((uint64_t)wth2 << 32) | wt2;
2266
}
2267

2268
uint32_t helper_float_cvts_d(uint64_t fdt0)
2269
{
2270 2271
    uint32_t fst2;

2272 2273
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2274
    update_fcr31();
2275
    return fst2;
2276
}
2277

2278
uint32_t helper_float_cvts_w(uint32_t wt0)
2279
{
2280 2281
    uint32_t fst2;

2282 2283
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2284
    update_fcr31();
2285
    return fst2;
2286
}
2287

2288
uint32_t helper_float_cvts_l(uint64_t dt0)
2289
{
2290 2291
    uint32_t fst2;

2292 2293
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2294
    update_fcr31();
2295
    return fst2;
2296
}
2297

2298
uint32_t helper_float_cvts_pl(uint32_t wt0)
2299
{
2300 2301
    uint32_t wt2;

2302
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2303
    wt2 = wt0;
2304
    update_fcr31();
2305
    return wt2;
2306
}
2307

2308
uint32_t helper_float_cvts_pu(uint32_t wth0)
2309
{
2310 2311
    uint32_t wt2;

2312
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2313
    wt2 = wth0;
2314
    update_fcr31();
2315
    return wt2;
2316
}
2317

2318
uint32_t helper_float_cvtw_s(uint32_t fst0)
2319
{
2320 2321
    uint32_t wt2;

2322 2323
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2324
    update_fcr31();
2325
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2326 2327
        wt2 = FLOAT_SNAN32;
    return wt2;
2328
}
2329

2330
uint32_t helper_float_cvtw_d(uint64_t fdt0)
2331
{
2332 2333
    uint32_t wt2;

2334 2335
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2336
    update_fcr31();
2337
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2338 2339
        wt2 = FLOAT_SNAN32;
    return wt2;
2340 2341
}

2342
uint64_t helper_float_roundl_d(uint64_t fdt0)
2343
{
2344 2345
    uint64_t dt2;

2346
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2347 2348
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2349 2350
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2351
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2352 2353
        dt2 = FLOAT_SNAN64;
    return dt2;
2354
}
2355

2356
uint64_t helper_float_roundl_s(uint32_t fst0)
2357
{
2358 2359
    uint64_t dt2;

2360
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2361 2362
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2363 2364
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2365
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2366 2367
        dt2 = FLOAT_SNAN64;
    return dt2;
2368
}
2369

2370
uint32_t helper_float_roundw_d(uint64_t fdt0)
2371
{
2372 2373
    uint32_t wt2;

2374
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2375 2376
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2377 2378
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2379
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2380 2381
        wt2 = FLOAT_SNAN32;
    return wt2;
2382
}
2383

2384
uint32_t helper_float_roundw_s(uint32_t fst0)
2385
{
2386 2387
    uint32_t wt2;

2388
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2389 2390
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2391 2392
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2393
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2394 2395
        wt2 = FLOAT_SNAN32;
    return wt2;
2396 2397
}

2398
uint64_t helper_float_truncl_d(uint64_t fdt0)
2399
{
2400 2401
    uint64_t dt2;

2402
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2403
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2404
    update_fcr31();
2405
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2406 2407
        dt2 = FLOAT_SNAN64;
    return dt2;
2408
}
2409

2410
uint64_t helper_float_truncl_s(uint32_t fst0)
2411
{
2412 2413
    uint64_t dt2;

2414
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2415
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2416
    update_fcr31();
2417
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2418 2419
        dt2 = FLOAT_SNAN64;
    return dt2;
2420
}
2421

2422
uint32_t helper_float_truncw_d(uint64_t fdt0)
2423
{
2424 2425
    uint32_t wt2;

2426
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2427
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2428
    update_fcr31();
2429
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2430 2431
        wt2 = FLOAT_SNAN32;
    return wt2;
2432
}
2433

2434
uint32_t helper_float_truncw_s(uint32_t fst0)
2435
{
2436 2437
    uint32_t wt2;

2438
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2439
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2440
    update_fcr31();
2441
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2442 2443
        wt2 = FLOAT_SNAN32;
    return wt2;
2444 2445
}

2446
uint64_t helper_float_ceill_d(uint64_t fdt0)
2447
{
2448 2449
    uint64_t dt2;

2450
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2451 2452
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2453 2454
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2455
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2456 2457
        dt2 = FLOAT_SNAN64;
    return dt2;
2458
}
2459

2460
uint64_t helper_float_ceill_s(uint32_t fst0)
2461
{
2462 2463
    uint64_t dt2;

2464
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2465 2466
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2467 2468
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2469
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2470 2471
        dt2 = FLOAT_SNAN64;
    return dt2;
2472
}
2473

2474
uint32_t helper_float_ceilw_d(uint64_t fdt0)
2475
{
2476 2477
    uint32_t wt2;

2478
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2479 2480
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2481 2482
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2483
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2484 2485
        wt2 = FLOAT_SNAN32;
    return wt2;
2486
}
2487

2488
uint32_t helper_float_ceilw_s(uint32_t fst0)
2489
{
2490 2491
    uint32_t wt2;

2492
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2493 2494
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2495 2496
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2497
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2498 2499
        wt2 = FLOAT_SNAN32;
    return wt2;
2500 2501
}

2502
uint64_t helper_float_floorl_d(uint64_t fdt0)
2503
{
2504 2505
    uint64_t dt2;

2506
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2507 2508
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2509 2510
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2511
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2512 2513
        dt2 = FLOAT_SNAN64;
    return dt2;
2514
}
2515

2516
uint64_t helper_float_floorl_s(uint32_t fst0)
2517
{
2518 2519
    uint64_t dt2;

2520
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2521 2522
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2523 2524
    RESTORE_ROUNDING_MODE;
    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
uint32_t helper_float_floorw_d(uint64_t fdt0)
2531
{
2532 2533
    uint32_t wt2;

2534
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2535 2536
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2537 2538
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2539
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2540 2541
        wt2 = FLOAT_SNAN32;
    return wt2;
2542
}
2543

2544
uint32_t helper_float_floorw_s(uint32_t fst0)
2545
{
2546 2547
    uint32_t wt2;

2548
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2549 2550
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2551 2552
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2553
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2554 2555
        wt2 = FLOAT_SNAN32;
    return wt2;
2556 2557
}

2558
/* unary operations, not modifying fp status  */
2559
#define FLOAT_UNOP(name)                                       \
2560
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2561 2562 2563
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2564
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2565 2566 2567
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2568
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2569 2570 2571 2572 2573 2574 2575
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2576 2577 2578 2579 2580
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

T
ths 已提交
2581
/* MIPS specific unary operations */
2582
uint64_t helper_float_recip_d(uint64_t fdt0)
T
ths 已提交
2583
{
2584 2585
    uint64_t fdt2;

2586 2587
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2588
    update_fcr31();
2589
    return fdt2;
T
ths 已提交
2590
}
2591

2592
uint32_t helper_float_recip_s(uint32_t fst0)
T
ths 已提交
2593
{
2594 2595
    uint32_t fst2;

2596 2597
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2598
    update_fcr31();
2599
    return fst2;
T
ths 已提交
2600 2601
}

2602
uint64_t helper_float_rsqrt_d(uint64_t fdt0)
T
ths 已提交
2603
{
2604 2605
    uint64_t fdt2;

2606 2607 2608
    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 已提交
2609
    update_fcr31();
2610
    return fdt2;
T
ths 已提交
2611
}
2612

2613
uint32_t helper_float_rsqrt_s(uint32_t fst0)
T
ths 已提交
2614
{
2615 2616
    uint32_t fst2;

2617 2618 2619
    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 已提交
2620
    update_fcr31();
2621
    return fst2;
T
ths 已提交
2622 2623
}

2624
uint64_t helper_float_recip1_d(uint64_t fdt0)
T
ths 已提交
2625
{
2626 2627
    uint64_t fdt2;

2628 2629
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2630
    update_fcr31();
2631
    return fdt2;
T
ths 已提交
2632
}
2633

2634
uint32_t helper_float_recip1_s(uint32_t fst0)
T
ths 已提交
2635
{
2636 2637
    uint32_t fst2;

2638 2639
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2640
    update_fcr31();
2641
    return fst2;
T
ths 已提交
2642
}
2643

2644
uint64_t helper_float_recip1_ps(uint64_t fdt0)
T
ths 已提交
2645
{
2646 2647 2648
    uint32_t fst2;
    uint32_t fsth2;

2649 2650 2651
    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 已提交
2652
    update_fcr31();
2653
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2654 2655
}

2656
uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
T
ths 已提交
2657
{
2658 2659
    uint64_t fdt2;

2660 2661 2662
    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 已提交
2663
    update_fcr31();
2664
    return fdt2;
T
ths 已提交
2665
}
2666

2667
uint32_t helper_float_rsqrt1_s(uint32_t fst0)
T
ths 已提交
2668
{
2669 2670
    uint32_t fst2;

2671 2672 2673
    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 已提交
2674
    update_fcr31();
2675
    return fst2;
T
ths 已提交
2676
}
2677

2678
uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
T
ths 已提交
2679
{
2680 2681 2682
    uint32_t fst2;
    uint32_t fsth2;

2683 2684 2685 2686 2687
    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 已提交
2688
    update_fcr31();
2689
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2690 2691
}

2692
#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2693

2694
/* binary operations */
2695
#define FLOAT_BINOP(name)                                          \
2696
uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2697 2698 2699
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
2700 2701
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2702
    update_fcr31();                                                \
2703
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2704 2705 2706 2707
        dt2 = FLOAT_QNAN64;                                        \
    return dt2;                                                    \
}                                                                  \
                                                                   \
2708
uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
2709 2710 2711
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
2712 2713
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2714
    update_fcr31();                                                \
2715
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2716 2717 2718 2719
        wt2 = FLOAT_QNAN32;                                        \
    return wt2;                                                    \
}                                                                  \
                                                                   \
2720
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
2721 2722 2723 2724 2725 2726 2727 2728
{                                                                  \
    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;                                                 \
                                                                   \
2729 2730 2731
    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);  \
2732
    update_fcr31();                                                \
2733
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
2734 2735 2736 2737
        wt2 = FLOAT_QNAN32;                                        \
        wth2 = FLOAT_QNAN32;                                       \
    }                                                              \
    return ((uint64_t)wth2 << 32) | wt2;                           \
2738
}
2739

2740 2741 2742 2743 2744 2745
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

2746
/* ternary operations */
2747
#define FLOAT_TERNOP(name1, name2)                                        \
2748
uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
2749 2750
                                           uint64_t fdt2)                 \
{                                                                         \
2751 2752
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2753 2754
}                                                                         \
                                                                          \
2755
uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
2756 2757
                                           uint32_t fst2)                 \
{                                                                         \
2758 2759
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2760 2761
}                                                                         \
                                                                          \
2762
uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
2763 2764 2765 2766 2767 2768 2769 2770 2771
                                            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;                                          \
                                                                          \
2772 2773 2774 2775
    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);       \
2776
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2777
}
2778

2779 2780 2781 2782 2783
FLOAT_TERNOP(mul, add)
FLOAT_TERNOP(mul, sub)
#undef FLOAT_TERNOP

/* negated ternary operations */
2784
#define FLOAT_NTERNOP(name1, name2)                                       \
2785
uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
2786 2787
                                           uint64_t fdt2)                 \
{                                                                         \
2788 2789
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2790 2791 2792
    return float64_chs(fdt2);                                             \
}                                                                         \
                                                                          \
2793
uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
2794 2795
                                           uint32_t fst2)                 \
{                                                                         \
2796 2797
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2798 2799 2800
    return float32_chs(fst2);                                             \
}                                                                         \
                                                                          \
2801
uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
2802 2803 2804 2805 2806 2807 2808 2809 2810
                                           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;                                          \
                                                                          \
2811 2812 2813 2814
    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);       \
2815 2816 2817
    fst2 = float32_chs(fst2);                                             \
    fsth2 = float32_chs(fsth2);                                           \
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2818
}
2819

2820 2821 2822 2823
FLOAT_NTERNOP(mul, add)
FLOAT_NTERNOP(mul, sub)
#undef FLOAT_NTERNOP

T
ths 已提交
2824
/* MIPS specific binary operations */
2825
uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2826
{
2827 2828 2829
    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 已提交
2830
    update_fcr31();
2831
    return fdt2;
T
ths 已提交
2832
}
2833

2834
uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
2835
{
2836 2837 2838
    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 已提交
2839
    update_fcr31();
2840
    return fst2;
T
ths 已提交
2841
}
2842

2843
uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2844
{
2845 2846 2847 2848 2849
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

2850 2851 2852 2853 2854
    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 已提交
2855
    update_fcr31();
2856
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2857 2858
}

2859
uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2860
{
2861 2862 2863 2864
    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 已提交
2865
    update_fcr31();
2866
    return fdt2;
T
ths 已提交
2867
}
2868

2869
uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
2870
{
2871 2872 2873 2874
    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 已提交
2875
    update_fcr31();
2876
    return fst2;
T
ths 已提交
2877
}
2878

2879
uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2880
{
2881 2882 2883 2884 2885
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

2886 2887 2888 2889 2890 2891 2892
    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 已提交
2893
    update_fcr31();
2894
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2895 2896
}

2897
uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
2898
{
2899 2900 2901 2902 2903 2904 2905
    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;

2906 2907 2908
    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);
2909
    update_fcr31();
2910
    return ((uint64_t)fsth2 << 32) | fst2;
2911 2912
}

2913
uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
2914
{
2915 2916 2917 2918 2919 2920 2921
    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;

2922 2923 2924
    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 已提交
2925
    update_fcr31();
2926
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2927 2928
}

T
ths 已提交
2929
/* compare operations */
2930
#define FOP_COND_D(op, cond)                                   \
2931
void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2932
{                                                              \
2933 2934 2935
    int c;                                                     \
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
    c = cond;                                                  \
2936 2937
    update_fcr31();                                            \
    if (c)                                                     \
2938
        SET_FP_COND(cc, env->active_fpu);                      \
2939
    else                                                       \
2940
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2941
}                                                              \
2942
void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2943 2944
{                                                              \
    int c;                                                     \
2945
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
2946 2947 2948 2949 2950
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
2951
        SET_FP_COND(cc, env->active_fpu);                      \
2952
    else                                                       \
2953
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2954 2955 2956
}

/* NOTE: the comma operator will make "cond" to eval to false,
2957 2958 2959
 * 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))
2960
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
2961
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
2962 2963 2964 2965
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))
2966
/* NOTE: the comma operator will make "cond" to eval to false,
2967 2968 2969
 * 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))
2970 2971 2972
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))
2973
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2974
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2975
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2976 2977

#define FOP_COND_S(op, cond)                                   \
2978
void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
2979
{                                                              \
2980 2981 2982
    int c;                                                     \
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
    c = cond;                                                  \
2983 2984
    update_fcr31();                                            \
    if (c)                                                     \
2985
        SET_FP_COND(cc, env->active_fpu);                      \
2986
    else                                                       \
2987
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2988
}                                                              \
2989
void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
2990 2991
{                                                              \
    int c;                                                     \
2992
    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
2993 2994 2995 2996 2997
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
2998
        SET_FP_COND(cc, env->active_fpu);                      \
2999
    else                                                       \
3000
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3001 3002 3003
}

/* NOTE: the comma operator will make "cond" to eval to false,
3004 3005 3006
 * 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))
3007
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3008
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3009 3010 3011 3012
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))
3013
/* NOTE: the comma operator will make "cond" to eval to false,
3014 3015 3016
 * 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))
3017 3018 3019
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))
3020
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3021
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3022
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3023 3024

#define FOP_COND_PS(op, condl, condh)                           \
3025
void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
3026
{                                                               \
3027 3028 3029 3030 3031 3032 3033 3034 3035
    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;                                                 \
3036 3037
    update_fcr31();                                             \
    if (cl)                                                     \
3038
        SET_FP_COND(cc, env->active_fpu);                       \
3039
    else                                                        \
3040
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3041
    if (ch)                                                     \
3042
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3043
    else                                                        \
3044
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3045
}                                                               \
3046
void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3047
{                                                               \
3048 3049 3050 3051 3052 3053 3054 3055
    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;                                                 \
3056 3057
    update_fcr31();                                             \
    if (cl)                                                     \
3058
        SET_FP_COND(cc, env->active_fpu);                       \
3059
    else                                                        \
3060
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3061
    if (ch)                                                     \
3062
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3063
    else                                                        \
3064
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3065 3066 3067
}

/* NOTE: the comma operator will make "cond" to eval to false,
3068 3069 3070 3071 3072
 * 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))
3073 3074
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3075 3076
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))
3077 3078 3079 3080 3081 3082 3083 3084
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))
3085
/* NOTE: the comma operator will make "cond" to eval to false,
3086 3087 3088 3089 3090
 * 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))
3091 3092 3093 3094 3095 3096
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))
3097 3098
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))
3099 3100
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3101 3102
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))