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

P
pbrook 已提交
23
#include "helper.h"
24

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

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

B
bellard 已提交
33 34 35
/*****************************************************************************/
/* Exceptions processing helpers */

36 37
void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
                                int error_code)
B
bellard 已提交
38 39
{
#if 1
40 41
    if (exception < 0x100)
        qemu_log("%s: %d %d\n", __func__, exception, error_code);
B
bellard 已提交
42 43 44
#endif
    env->exception_index = exception;
    env->error_code = error_code;
B
Blue Swirl 已提交
45
    cpu_loop_exit(env);
B
bellard 已提交
46 47
}

48
void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
B
bellard 已提交
49
{
50
    helper_raise_exception_err(env, exception, 0);
B
bellard 已提交
51 52
}

53
#if !defined(CONFIG_USER_ONLY)
54
static void do_restore_state(CPUMIPSState *env, uintptr_t pc)
B
bellard 已提交
55
{
B
bellard 已提交
56
    TranslationBlock *tb;
57

B
bellard 已提交
58 59
    tb = tb_find_pc (pc);
    if (tb) {
60
        cpu_restore_state(tb, env, pc);
B
bellard 已提交
61
    }
B
bellard 已提交
62
}
63
#endif
B
bellard 已提交
64

65 66
#if defined(CONFIG_USER_ONLY)
#define HELPER_LD(name, insn, type)                                     \
67 68
static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
                             int mem_idx)                               \
69 70 71 72 73
{                                                                       \
    return (type) insn##_raw(addr);                                     \
}
#else
#define HELPER_LD(name, insn, type)                                     \
74 75
static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
                             int mem_idx)                               \
76 77 78
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
79 80
    case 0: return (type) cpu_##insn##_kernel(env, addr); break;        \
    case 1: return (type) cpu_##insn##_super(env, addr); break;         \
81
    default:                                                            \
82
    case 2: return (type) cpu_##insn##_user(env, addr); break;          \
83 84 85 86 87 88 89 90 91 92 93 94
    }                                                                   \
}
#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)                                     \
95 96
static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
                             type val, int mem_idx)                     \
97 98 99 100 101
{                                                                       \
    insn##_raw(addr, val);                                              \
}
#else
#define HELPER_ST(name, insn, type)                                     \
102 103
static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
                             type val, int mem_idx)                     \
104 105 106
{                                                                       \
    switch (mem_idx)                                                    \
    {                                                                   \
107 108
    case 0: cpu_##insn##_kernel(env, addr, val); break;                 \
    case 1: cpu_##insn##_super(env, addr, val); break;                  \
109
    default:                                                            \
110
    case 2: cpu_##insn##_user(env, addr, val); break;                   \
111 112 113 114 115 116 117 118 119 120
    }                                                                   \
}
#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

121
target_ulong helper_clo (target_ulong arg1)
122
{
123
    return clo32(arg1);
124 125
}

126
target_ulong helper_clz (target_ulong arg1)
127
{
128
    return clz32(arg1);
129 130
}

131
#if defined(TARGET_MIPS64)
132
target_ulong helper_dclo (target_ulong arg1)
133
{
134
    return clo64(arg1);
135 136
}

137
target_ulong helper_dclz (target_ulong arg1)
138
{
139
    return clz64(arg1);
140
}
141
#endif /* TARGET_MIPS64 */
142

B
bellard 已提交
143
/* 64 bits arithmetic for 32 bits hosts */
144
static inline uint64_t get_HILO(CPUMIPSState *env)
B
bellard 已提交
145
{
146
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
B
bellard 已提交
147 148
}

149
static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
150
{
151
    target_ulong tmp;
152
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
153 154
    tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
    return tmp;
155 156
}

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

/* Multiplication variants of the vr54xx. */
165 166
target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
167
{
168 169
    return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
                                 (int64_t)(int32_t)arg2));
170 171
}

172 173
target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
174
{
175 176
    return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
177 178
}

179 180
target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
181
{
182 183
    return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
184 185
}

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

193 194
target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
195
{
196 197
    return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
198 199
}

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

207 208
target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
                         target_ulong arg2)
209
{
210 211
    return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
212 213
}

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

221 222
target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
223
{
224 225
    return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
                       (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
226 227
}

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

235 236
target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
                          target_ulong arg2)
237
{
238
    return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
239 240
}

241 242
target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
243
{
244 245
    return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
246 247
}

248 249
target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
                           target_ulong arg2)
250
{
251 252
    return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
                       (int64_t)(int32_t)arg2);
253 254
}

255 256
target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
                            target_ulong arg2)
257
{
258 259
    return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
                       (uint64_t)(uint32_t)arg2);
260
}
B
bellard 已提交
261

262
#ifdef TARGET_MIPS64
263
void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
264
{
265
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
266 267
}

268
void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
269
{
270
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
271 272 273
}
#endif

274
#ifndef CONFIG_USER_ONLY
275

A
Avi Kivity 已提交
276
static inline hwaddr do_translate_address(CPUMIPSState *env,
277 278
                                                      target_ulong address,
                                                      int rw)
279
{
A
Avi Kivity 已提交
280
    hwaddr lladdr;
281 282 283 284

    lladdr = cpu_mips_translate_address(env, address, rw);

    if (lladdr == -1LL) {
B
Blue Swirl 已提交
285
        cpu_loop_exit(env);
286 287 288 289 290
    } else {
        return lladdr;
    }
}

291
#define HELPER_LD_ATOMIC(name, insn)                                          \
292
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
293
{                                                                             \
294 295
    env->lladdr = do_translate_address(env, arg, 0);                          \
    env->llval = do_##insn(env, arg, mem_idx);                                \
296 297 298 299 300 301 302 303 304
    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)                      \
305 306
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
                           target_ulong arg2, int mem_idx)                    \
307 308 309 310 311
{                                                                             \
    target_long tmp;                                                          \
                                                                              \
    if (arg2 & almask) {                                                      \
        env->CP0_BadVAddr = arg2;                                             \
312
        helper_raise_exception(env, EXCP_AdES);                               \
313
    }                                                                         \
314 315
    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
        tmp = do_##ld_insn(env, arg2, mem_idx);                               \
316
        if (tmp == env->llval) {                                              \
317
            do_##st_insn(env, arg2, arg1, mem_idx);                           \
318 319 320 321 322 323 324 325 326 327 328 329
            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 已提交
330 331 332 333 334 335 336 337
#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

338 339
target_ulong helper_lwl(CPUMIPSState *env, target_ulong arg1,
                        target_ulong arg2, int mem_idx)
T
ths 已提交
340 341 342
{
    target_ulong tmp;

343
    tmp = do_lbu(env, arg2, mem_idx);
344
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
345

346
    if (GET_LMASK(arg2) <= 2) {
347
        tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
348
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
349 350
    }

351
    if (GET_LMASK(arg2) <= 1) {
352
        tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
353
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
354 355
    }

356
    if (GET_LMASK(arg2) == 0) {
357
        tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
358
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
359
    }
360
    return (int32_t)arg1;
T
ths 已提交
361 362
}

363 364
target_ulong helper_lwr(CPUMIPSState *env, target_ulong arg1,
                        target_ulong arg2, int mem_idx)
T
ths 已提交
365 366 367
{
    target_ulong tmp;

368
    tmp = do_lbu(env, arg2, mem_idx);
369
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
370

371
    if (GET_LMASK(arg2) >= 1) {
372
        tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
373
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
374 375
    }

376
    if (GET_LMASK(arg2) >= 2) {
377
        tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
378
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
379 380
    }

381
    if (GET_LMASK(arg2) == 3) {
382
        tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
383
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
384
    }
385
    return (int32_t)arg1;
T
ths 已提交
386 387
}

388 389
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
390
{
391
    do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
392

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

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

399
    if (GET_LMASK(arg2) == 0)
400
        do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
T
ths 已提交
401 402
}

403 404
void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
405
{
406
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
407

408
    if (GET_LMASK(arg2) >= 1)
409
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
410

411
    if (GET_LMASK(arg2) >= 2)
412
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
413

414
    if (GET_LMASK(arg2) == 3)
415
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
416 417 418 419 420 421 422 423 424 425 426 427
}

#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

428 429
target_ulong helper_ldl(CPUMIPSState *env, target_ulong arg1,
                        target_ulong arg2, int mem_idx)
T
ths 已提交
430 431 432
{
    uint64_t tmp;

433
    tmp = do_lbu(env, arg2, mem_idx);
434
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
435

436
    if (GET_LMASK64(arg2) <= 6) {
437
        tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
438
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
439 440
    }

441
    if (GET_LMASK64(arg2) <= 5) {
442
        tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
443
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
444 445
    }

446
    if (GET_LMASK64(arg2) <= 4) {
447
        tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
448
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
449 450
    }

451
    if (GET_LMASK64(arg2) <= 3) {
452
        tmp = do_lbu(env, GET_OFFSET(arg2, 4), mem_idx);
453
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
454 455
    }

456
    if (GET_LMASK64(arg2) <= 2) {
457
        tmp = do_lbu(env, GET_OFFSET(arg2, 5), mem_idx);
458
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
459 460
    }

461
    if (GET_LMASK64(arg2) <= 1) {
462
        tmp = do_lbu(env, GET_OFFSET(arg2, 6), mem_idx);
463
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
T
ths 已提交
464 465
    }

466
    if (GET_LMASK64(arg2) == 0) {
467
        tmp = do_lbu(env, GET_OFFSET(arg2, 7), mem_idx);
468
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
469
    }
470

471
    return arg1;
T
ths 已提交
472 473
}

474 475
target_ulong helper_ldr(CPUMIPSState *env, target_ulong arg1,
                        target_ulong arg2, int mem_idx)
T
ths 已提交
476 477 478
{
    uint64_t tmp;

479
    tmp = do_lbu(env, arg2, mem_idx);
480
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
481

482
    if (GET_LMASK64(arg2) >= 1) {
483
        tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
484
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
T
ths 已提交
485 486
    }

487
    if (GET_LMASK64(arg2) >= 2) {
488
        tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
489
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
490 491
    }

492
    if (GET_LMASK64(arg2) >= 3) {
493
        tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
494
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
495 496
    }

497
    if (GET_LMASK64(arg2) >= 4) {
498
        tmp = do_lbu(env, GET_OFFSET(arg2, -4), mem_idx);
499
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
500 501
    }

502
    if (GET_LMASK64(arg2) >= 5) {
503
        tmp = do_lbu(env, GET_OFFSET(arg2, -5), mem_idx);
504
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
505 506
    }

507
    if (GET_LMASK64(arg2) >= 6) {
508
        tmp = do_lbu(env, GET_OFFSET(arg2, -6), mem_idx);
509
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
510 511
    }

512
    if (GET_LMASK64(arg2) == 7) {
513
        tmp = do_lbu(env, GET_OFFSET(arg2, -7), mem_idx);
514
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
515
    }
516

517
    return arg1;
T
ths 已提交
518 519
}

520 521
void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
522
{
523
    do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
524

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

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

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

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

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

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

543
    if (GET_LMASK64(arg2) <= 0)
544
        do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
T
ths 已提交
545 546
}

547 548
void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
                int mem_idx)
T
ths 已提交
549
{
550
    do_sb(env, arg2, (uint8_t)arg1, mem_idx);
T
ths 已提交
551

552
    if (GET_LMASK64(arg2) >= 1)
553
        do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
T
ths 已提交
554

555
    if (GET_LMASK64(arg2) >= 2)
556
        do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
T
ths 已提交
557

558
    if (GET_LMASK64(arg2) >= 3)
559
        do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
T
ths 已提交
560

561
    if (GET_LMASK64(arg2) >= 4)
562
        do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
T
ths 已提交
563

564
    if (GET_LMASK64(arg2) >= 5)
565
        do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
T
ths 已提交
566

567
    if (GET_LMASK64(arg2) >= 6)
568
        do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
T
ths 已提交
569

570
    if (GET_LMASK64(arg2) == 7)
571
        do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
T
ths 已提交
572 573 574
}
#endif /* TARGET_MIPS64 */

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

577 578
void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
579 580 581 582 583
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef ldfun
584
#define ldfun(env, addr) ldl_raw(addr)
585
#else
586
    uint32_t (*ldfun)(CPUMIPSState *env, target_ulong);
587 588 589

    switch (mem_idx)
    {
590 591
    case 0: ldfun = cpu_ldl_kernel; break;
    case 1: ldfun = cpu_ldl_super; break;
592
    default:
593
    case 2: ldfun = cpu_ldl_user; break;
594 595 596 597 598 599 600
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
601
            env->active_tc.gpr[multiple_regs[i]] = (target_long)ldfun(env, addr);
602 603 604 605 606
            addr += 4;
        }
    }

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

611 612
void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
613 614 615 616 617
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef stfun
618
#define stfun(env, addr, val) stl_raw(addr, val)
619
#else
620
    void (*stfun)(CPUMIPSState *env, target_ulong, uint32_t);
621 622 623

    switch (mem_idx)
    {
624 625
    case 0: stfun = cpu_stl_kernel; break;
    case 1: stfun = cpu_stl_super; break;
626
     default:
627
    case 2: stfun = cpu_stl_user; break;
628 629 630 631 632 633 634
    }
#endif

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

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

    if (do_r31) {
641
        stfun(env, addr, env->active_tc.gpr[31]);
642 643 644 645
    }
}

#if defined(TARGET_MIPS64)
646 647
void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
648 649 650 651 652
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef ldfun
653
#define ldfun(env, addr) ldq_raw(addr)
654
#else
655
    uint64_t (*ldfun)(CPUMIPSState *env, target_ulong);
656 657 658

    switch (mem_idx)
    {
659 660
    case 0: ldfun = cpu_ldq_kernel; break;
    case 1: ldfun = cpu_ldq_super; break;
661
    default:
662
    case 2: ldfun = cpu_ldq_user; break;
663 664 665 666 667 668 669
    }
#endif

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

        for (i = 0; i < base_reglist; i++) {
670
            env->active_tc.gpr[multiple_regs[i]] = ldfun(env, addr);
671 672 673 674 675
            addr += 8;
        }
    }

    if (do_r31) {
676
        env->active_tc.gpr[31] = ldfun(env, addr);
677 678 679
    }
}

680 681
void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
                uint32_t mem_idx)
682 683 684 685 686
{
    target_ulong base_reglist = reglist & 0xf;
    target_ulong do_r31 = reglist & 0x10;
#ifdef CONFIG_USER_ONLY
#undef stfun
687
#define stfun(env, addr, val) stq_raw(addr, val)
688
#else
689
    void (*stfun)(CPUMIPSState *env, target_ulong, uint64_t);
690 691 692

    switch (mem_idx)
    {
693 694
    case 0: stfun = cpu_stq_kernel; break;
    case 1: stfun = cpu_stq_super; break;
695
     default:
696
    case 2: stfun = cpu_stq_user; break;
697 698 699 700 701 702 703
    }
#endif

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

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

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

T
ths 已提交
715
#ifndef CONFIG_USER_ONLY
716
/* SMP helpers.  */
717
static bool mips_vpe_is_wfi(MIPSCPU *c)
718
{
719 720
    CPUMIPSState *env = &c->env;

721 722
    /* If the VPE is halted but otherwise active, it means it's waiting for
       an interrupt.  */
723
    return env->halted && mips_vpe_active(env);
724 725
}

726
static inline void mips_vpe_wake(CPUMIPSState *c)
727 728 729 730 731 732 733
{
    /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
       because there might be other conditions that state that c should
       be sleeping.  */
    cpu_interrupt(c, CPU_INTERRUPT_WAKE);
}

734
static inline void mips_vpe_sleep(MIPSCPU *cpu)
735
{
736 737
    CPUMIPSState *c = &cpu->env;

738 739 740 741 742 743
    /* The VPE was shut off, really go to bed.
       Reset any old _WAKE requests.  */
    c->halted = 1;
    cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
}

744
static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
745
{
746 747
    CPUMIPSState *c = &cpu->env;

748
    /* FIXME: TC reschedule.  */
749
    if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
750 751 752 753
        mips_vpe_wake(c);
    }
}

754
static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
755
{
756 757
    CPUMIPSState *c = &cpu->env;

758 759
    /* FIXME: TC reschedule.  */
    if (!mips_vpe_active(c)) {
760
        mips_vpe_sleep(cpu);
761 762 763
    }
}

764 765
/* tc should point to an int with the value of the global TC index.
   This function will transform it into a local index within the
766
   returned CPUMIPSState.
767 768 769

   FIXME: This code assumes that all VPEs have the same number of TCs,
          which depends on runtime setup. Can probably be fixed by
770
          walking the list of CPUMIPSStates.  */
771
static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
772
{
773
    CPUMIPSState *other;
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
    int vpe_idx, nr_threads = env->nr_threads;
    int tc_idx = *tc;

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

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

789 790 791 792 793 794 795 796 797
/* The per VPE CP0_Status register shares some fields with the per TC
   CP0_TCStatus registers. These fields are wired to the same registers,
   so changes to either of them should be reflected on both registers.

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

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

/* Called for updates to CP0_Status.  */
798
static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
{
    int32_t tcstatus, *tcst;
    uint32_t v = cpu->CP0_Status;
    uint32_t cu, mx, asid, ksu;
    uint32_t mask = ((1 << CP0TCSt_TCU3)
                       | (1 << CP0TCSt_TCU2)
                       | (1 << CP0TCSt_TCU1)
                       | (1 << CP0TCSt_TCU0)
                       | (1 << CP0TCSt_TMX)
                       | (3 << CP0TCSt_TKSU)
                       | (0xff << CP0TCSt_TASID));

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

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

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

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

/* Called for updates to CP0_TCStatus.  */
833 834
static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
                             target_ulong v)
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
{
    uint32_t status;
    uint32_t tcu, tmx, tasid, tksu;
    uint32_t mask = ((1 << CP0St_CU3)
                       | (1 << CP0St_CU2)
                       | (1 << CP0St_CU1)
                       | (1 << CP0St_CU0)
                       | (1 << CP0St_MX)
                       | (3 << CP0St_KSU));

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

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

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

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

    compute_hflags(cpu);
}

/* Called for updates to CP0_EntryHi.  */
865
static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
{
    int32_t *tcst;
    uint32_t asid, v = cpu->CP0_EntryHi;

    asid = v & 0xff;

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

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

B
bellard 已提交
882
/* CP0 helpers */
883
target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
884
{
885
    return env->mvp->CP0_MVPControl;
886 887
}

888
target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
889
{
890
    return env->mvp->CP0_MVPConf0;
891 892
}

893
target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
894
{
895
    return env->mvp->CP0_MVPConf1;
896 897
}

898
target_ulong helper_mfc0_random(CPUMIPSState *env)
B
bellard 已提交
899
{
900
    return (int32_t)cpu_mips_get_random(env);
901
}
B
bellard 已提交
902

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

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

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

919
target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
920
{
921
    return env->active_tc.CP0_TCBind;
922 923
}

924
target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
925 926
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
927
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
928

929 930
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCBind;
931
    else
932
        return other->tcs[other_tc].CP0_TCBind;
933 934
}

935
target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
936
{
937
    return env->active_tc.PC;
938 939
}

940
target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
941 942
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
943
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
944

945 946
    if (other_tc == other->current_tc)
        return other->active_tc.PC;
947
    else
948
        return other->tcs[other_tc].PC;
949 950
}

951
target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
952
{
953
    return env->active_tc.CP0_TCHalt;
954 955
}

956
target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
957 958
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
959
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
960

961 962
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCHalt;
963
    else
964
        return other->tcs[other_tc].CP0_TCHalt;
965 966
}

967
target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
968
{
969
    return env->active_tc.CP0_TCContext;
970 971
}

972
target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
973 974
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
975
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
976

977 978
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCContext;
979
    else
980
        return other->tcs[other_tc].CP0_TCContext;
981 982
}

983
target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
984
{
985
    return env->active_tc.CP0_TCSchedule;
986 987
}

988
target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
989 990
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
991
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
992

993 994
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCSchedule;
995
    else
996
        return other->tcs[other_tc].CP0_TCSchedule;
997 998
}

999
target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
1000
{
1001
    return env->active_tc.CP0_TCScheFBack;
1002 1003
}

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

1009 1010
    if (other_tc == other->current_tc)
        return other->active_tc.CP0_TCScheFBack;
1011
    else
1012
        return other->tcs[other_tc].CP0_TCScheFBack;
1013 1014
}

1015
target_ulong helper_mfc0_count(CPUMIPSState *env)
1016
{
1017
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
1018 1019
}

1020
target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
1021 1022
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1023
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1024

1025
    return other->CP0_EntryHi;
1026 1027
}

1028
target_ulong helper_mftc0_cause(CPUMIPSState *env)
1029 1030 1031
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    int32_t tccause;
1032
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

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

    return tccause;
}

1043
target_ulong helper_mftc0_status(CPUMIPSState *env)
1044 1045
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1046
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1047

1048
    return other->CP0_Status;
1049 1050
}

1051
target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
1052
{
1053
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
1054 1055
}

1056
target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
1057
{
1058
    return (int32_t)env->CP0_WatchLo[sel];
1059 1060
}

1061
target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
1062
{
1063
    return env->CP0_WatchHi[sel];
1064 1065
}

1066
target_ulong helper_mfc0_debug(CPUMIPSState *env)
1067
{
1068
    target_ulong t0 = env->CP0_Debug;
1069
    if (env->hflags & MIPS_HFLAG_DM)
1070 1071 1072
        t0 |= 1 << CP0DB_DM;

    return t0;
1073 1074
}

1075
target_ulong helper_mftc0_debug(CPUMIPSState *env)
1076 1077
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1078
    int32_t tcstatus;
1079
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1080

1081 1082
    if (other_tc == other->current_tc)
        tcstatus = other->active_tc.CP0_Debug_tcstatus;
1083
    else
1084
        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
1085 1086

    /* XXX: Might be wrong, check with EJTAG spec. */
1087
    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1088
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1089 1090 1091
}

#if defined(TARGET_MIPS64)
1092
target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
1093
{
1094
    return env->active_tc.PC;
1095 1096
}

1097
target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
1098
{
1099
    return env->active_tc.CP0_TCHalt;
1100 1101
}

1102
target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
1103
{
1104
    return env->active_tc.CP0_TCContext;
1105 1106
}

1107
target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
1108
{
1109
    return env->active_tc.CP0_TCSchedule;
1110 1111
}

1112
target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
1113
{
1114
    return env->active_tc.CP0_TCScheFBack;
1115 1116
}

1117
target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
1118
{
1119
    return env->lladdr >> env->CP0_LLAddr_shift;
1120 1121
}

1122
target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
1123
{
1124
    return env->CP0_WatchLo[sel];
1125 1126 1127
}
#endif /* TARGET_MIPS64 */

1128
void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
1129 1130 1131 1132 1133 1134 1135 1136
{
    int num = 1;
    unsigned int tmp = env->tlb->nb_tlb;

    do {
        tmp >>= 1;
        num <<= 1;
    } while (tmp);
1137
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
1138 1139
}

1140
void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
1141 1142 1143 1144 1145 1146 1147 1148 1149
{
    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);
1150
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1151 1152 1153 1154 1155 1156

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

    env->mvp->CP0_MVPControl = newval;
}

1157
void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1158 1159 1160 1161 1162 1163
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1164
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1165 1166 1167 1168 1169 1170 1171 1172 1173

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

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

1174
void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1175 1176
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1177
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
    uint32_t mask;
    uint32_t newval;

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

    /* TODO: Enable/disable TCs.  */

    other->CP0_VPEControl = newval;
}

1190
target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
1191 1192
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1193
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1194 1195 1196 1197
    /* FIXME: Mask away return zero on read bits.  */
    return other->CP0_VPEControl;
}

1198
target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1199 1200
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1201
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1202 1203 1204 1205

    return other->CP0_VPEConf0;
}

1206
void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1207 1208 1209 1210 1211 1212 1213 1214 1215
{
    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);
    }
1216
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1217 1218 1219 1220 1221 1222

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

    env->CP0_VPEConf0 = newval;
}

1223
void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1224 1225
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1226
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
    uint32_t mask = 0;
    uint32_t newval;

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

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

1237
void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1238 1239 1240 1241 1242 1243 1244
{
    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);
1245
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1246 1247 1248 1249 1250 1251 1252 1253 1254

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

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

1255
void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1256 1257 1258 1259 1260
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

1261
void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1262
{
1263
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1264 1265
}

1266
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1267 1268 1269
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1270
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1271 1272
}

1273
void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1274 1275 1276 1277
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

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

1280
    env->active_tc.CP0_TCStatus = newval;
1281
    sync_c0_tcstatus(env, env->current_tc, newval);
1282 1283
}

1284
void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1285 1286
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1287
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1288

1289 1290
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCStatus = arg1;
1291
    else
1292
        other->tcs[other_tc].CP0_TCStatus = arg1;
1293
    sync_c0_tcstatus(other, other_tc, arg1);
1294 1295
}

1296
void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1297 1298 1299 1300 1301 1302
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
1303
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1304
    env->active_tc.CP0_TCBind = newval;
1305 1306
}

1307
void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1308 1309 1310 1311
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;
1312
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1313

1314
    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1315
        mask |= (1 << CP0TCBd_CurVPE);
1316 1317 1318
    if (other_tc == other->current_tc) {
        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
        other->active_tc.CP0_TCBind = newval;
1319
    } else {
1320 1321
        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
        other->tcs[other_tc].CP0_TCBind = newval;
1322
    }
1323 1324
}

1325
void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1326
{
1327
    env->active_tc.PC = arg1;
1328
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1329
    env->lladdr = 0ULL;
1330 1331 1332
    /* MIPS16 not implemented. */
}

1333
void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1334 1335
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1336
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1337

1338 1339 1340 1341
    if (other_tc == other->current_tc) {
        other->active_tc.PC = arg1;
        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1342 1343
        /* MIPS16 not implemented. */
    } else {
1344 1345 1346
        other->tcs[other_tc].PC = arg1;
        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        other->lladdr = 0ULL;
1347 1348
        /* MIPS16 not implemented. */
    }
1349 1350
}

1351
void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1352
{
1353 1354
    MIPSCPU *cpu = mips_env_get_cpu(env);

1355
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1356 1357

    // TODO: Halt TC / Restart (if allocated+active) TC.
1358
    if (env->active_tc.CP0_TCHalt & 1) {
1359
        mips_tc_sleep(cpu, env->current_tc);
1360
    } else {
1361
        mips_tc_wake(cpu, env->current_tc);
1362
    }
1363 1364
}

1365
void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1366 1367
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1368
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1369
    MIPSCPU *other_cpu = mips_env_get_cpu(other);
1370 1371 1372

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

1373 1374
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCHalt = arg1;
1375
    else
1376
        other->tcs[other_tc].CP0_TCHalt = arg1;
1377 1378

    if (arg1 & 1) {
1379
        mips_tc_sleep(other_cpu, other_tc);
1380
    } else {
1381
        mips_tc_wake(other_cpu, other_tc);
1382
    }
1383 1384
}

1385
void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1386
{
1387
    env->active_tc.CP0_TCContext = arg1;
1388 1389
}

1390
void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1391 1392
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1393
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1394

1395 1396
    if (other_tc == other->current_tc)
        other->active_tc.CP0_TCContext = arg1;
1397
    else
1398
        other->tcs[other_tc].CP0_TCContext = arg1;
1399 1400
}

1401
void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1402
{
1403
    env->active_tc.CP0_TCSchedule = arg1;
1404 1405
}

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

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

1417
void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1418
{
1419
    env->active_tc.CP0_TCScheFBack = arg1;
1420 1421
}

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

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

1433
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1434 1435 1436
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1437
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1438 1439
}

1440
void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1441
{
1442
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1443 1444
}

1445
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1446 1447
{
    /* 1k pages not implemented */
1448
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1449 1450
}

1451
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1452 1453 1454 1455 1456 1457 1458
{
    /* SmartMIPS not implemented */
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
    env->CP0_PageGrain = 0;
}

1459
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1460
{
1461
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1462 1463
}

1464
void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1465
{
1466
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1467 1468
}

1469
void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1470
{
1471
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1472 1473
}

1474
void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1475
{
1476
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1477 1478
}

1479
void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1480
{
1481
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1482 1483
}

1484
void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1485
{
1486
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1487 1488
}

1489
void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1490
{
1491
    env->CP0_HWREna = arg1 & 0x0000000F;
1492 1493
}

1494
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1495
{
1496
    cpu_mips_store_count(env, arg1);
1497 1498
}

1499
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1500 1501 1502 1503
{
    target_ulong old, val;

    /* 1k pages not implemented */
1504
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1505 1506 1507 1508 1509 1510
#if defined(TARGET_MIPS64)
    val &= env->SEGMask;
#endif
    old = env->CP0_EntryHi;
    env->CP0_EntryHi = val;
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1511
        sync_c0_entryhi(env, env->current_tc);
1512 1513 1514 1515 1516 1517
    }
    /* If the ASID changes, flush qemu's TLB.  */
    if ((old & 0xFF) != (val & 0xFF))
        cpu_mips_tlb_flush(env, 1);
}

1518
void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1519 1520
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1521
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1522

1523 1524
    other->CP0_EntryHi = arg1;
    sync_c0_entryhi(other, other_tc);
1525 1526
}

1527
void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1528
{
1529
    cpu_mips_store_compare(env, arg1);
1530 1531
}

1532
void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1533 1534 1535 1536
{
    uint32_t val, old;
    uint32_t mask = env->CP0_Status_rw_bitmask;

1537
    val = arg1 & mask;
1538 1539
    old = env->CP0_Status;
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1540
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1541
        sync_c0_status(env, env, env->current_tc);
1542 1543 1544 1545
    } else {
        compute_hflags(env);
    }

1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
    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 已提交
1556
        }
1557
    }
1558 1559
}

1560
void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1561 1562
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1563
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1564

1565
    other->CP0_Status = arg1 & ~0xf1000018;
1566
    sync_c0_status(env, other, other_tc);
1567 1568
}

1569
void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1570 1571
{
    /* vectored interrupts not implemented, no performance counters. */
1572
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1573 1574
}

1575
void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1576 1577
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1578
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1579 1580
}

1581
static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
1582 1583
{
    uint32_t mask = 0x00C00300;
1584
    uint32_t old = cpu->CP0_Cause;
1585
    int i;
1586

1587
    if (cpu->insn_flags & ISA_MIPS32R2) {
1588
        mask |= 1 << CP0Ca_DC;
1589
    }
1590

1591
    cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
1592

1593 1594 1595 1596 1597 1598
    if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
        if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
            cpu_mips_stop_count(cpu);
        } else {
            cpu_mips_start_count(cpu);
        }
1599
    }
1600 1601 1602

    /* Set/reset software interrupts */
    for (i = 0 ; i < 2 ; i++) {
1603 1604
        if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
            cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
1605 1606
        }
    }
1607 1608
}

1609
void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1610 1611 1612 1613
{
    mtc0_cause(env, arg1);
}

1614
void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1615 1616
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1617
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1618 1619 1620 1621

    mtc0_cause(other, arg1);
}

1622
target_ulong helper_mftc0_epc(CPUMIPSState *env)
1623 1624
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1625
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1626 1627 1628 1629

    return other->CP0_EPC;
}

1630
target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1631 1632
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1633
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1634 1635 1636 1637

    return other->CP0_EBase;
}

1638
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1639 1640
{
    /* vectored interrupts not implemented */
1641
    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1642 1643
}

1644
void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1645 1646
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1647
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1648 1649 1650
    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}

1651
target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1652 1653
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1654
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669

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

1670
void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1671
{
1672
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1673 1674
}

1675
void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1676 1677 1678 1679 1680
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1681
void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1682 1683 1684 1685 1686 1687
{
    target_long mask = env->CP0_LLAddr_rw_bitmask;
    arg1 = arg1 << env->CP0_LLAddr_shift;
    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
}

1688
void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1689 1690 1691
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1692
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1693 1694
}

1695
void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1696
{
1697 1698
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1699 1700
}

1701
void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1702 1703
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1704
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1705 1706
}

1707
void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1708
{
1709
    env->CP0_Framemask = arg1; /* XXX */
1710 1711
}

1712
void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1713
{
1714 1715
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1716 1717 1718 1719 1720
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1721
void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1722 1723
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1724
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1725
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1726 1727

    /* XXX: Might be wrong, check with EJTAG spec. */
1728 1729
    if (other_tc == other->current_tc)
        other->active_tc.CP0_Debug_tcstatus = val;
1730
    else
1731 1732 1733
        other->tcs[other_tc].CP0_Debug_tcstatus = val;
    other->CP0_Debug = (other->CP0_Debug &
                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1734
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1735 1736
}

1737
void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1738
{
1739
    env->CP0_Performance0 = arg1 & 0x000007ff;
1740 1741
}

1742
void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1743
{
1744
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1745 1746
}

1747
void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1748
{
1749
    env->CP0_DataLo = arg1; /* XXX */
1750 1751
}

1752
void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1753
{
1754
    env->CP0_TagHi = arg1; /* XXX */
1755 1756
}

1757
void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1758
{
1759
    env->CP0_DataHi = arg1; /* XXX */
1760 1761 1762
}

/* MIPS MT functions */
1763
target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1764 1765
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1766
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1767

1768 1769
    if (other_tc == other->current_tc)
        return other->active_tc.gpr[sel];
1770
    else
1771
        return other->tcs[other_tc].gpr[sel];
1772 1773
}

1774
target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1775 1776
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1777
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1778

1779 1780
    if (other_tc == other->current_tc)
        return other->active_tc.LO[sel];
1781
    else
1782
        return other->tcs[other_tc].LO[sel];
1783 1784
}

1785
target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1786 1787
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1788
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1789

1790 1791
    if (other_tc == other->current_tc)
        return other->active_tc.HI[sel];
1792
    else
1793
        return other->tcs[other_tc].HI[sel];
1794 1795
}

1796
target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1797 1798
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1799
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1800

1801 1802
    if (other_tc == other->current_tc)
        return other->active_tc.ACX[sel];
1803
    else
1804
        return other->tcs[other_tc].ACX[sel];
1805 1806
}

1807
target_ulong helper_mftdsp(CPUMIPSState *env)
1808 1809
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1810
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1811

1812 1813
    if (other_tc == other->current_tc)
        return other->active_tc.DSPControl;
1814
    else
1815
        return other->tcs[other_tc].DSPControl;
1816
}
B
bellard 已提交
1817

1818
void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1819 1820
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1821
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1822

1823 1824
    if (other_tc == other->current_tc)
        other->active_tc.gpr[sel] = arg1;
1825
    else
1826
        other->tcs[other_tc].gpr[sel] = arg1;
1827 1828
}

1829
void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1830 1831
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1832
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1833

1834 1835
    if (other_tc == other->current_tc)
        other->active_tc.LO[sel] = arg1;
1836
    else
1837
        other->tcs[other_tc].LO[sel] = arg1;
1838 1839
}

1840
void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1841 1842
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1843
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1844

1845 1846
    if (other_tc == other->current_tc)
        other->active_tc.HI[sel] = arg1;
1847
    else
1848
        other->tcs[other_tc].HI[sel] = arg1;
1849 1850
}

1851
void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1852 1853
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1854
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1855

1856 1857
    if (other_tc == other->current_tc)
        other->active_tc.ACX[sel] = arg1;
1858
    else
1859
        other->tcs[other_tc].ACX[sel] = arg1;
1860 1861
}

1862
void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1863 1864
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1865
    CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1866

1867 1868
    if (other_tc == other->current_tc)
        other->active_tc.DSPControl = arg1;
1869
    else
1870
        other->tcs[other_tc].DSPControl = arg1;
1871 1872 1873
}

/* MIPS MT functions */
1874
target_ulong helper_dmt(void)
1875 1876
{
    // TODO
1877
     return 0;
1878 1879
}

1880
target_ulong helper_emt(void)
1881 1882
{
    // TODO
1883
    return 0;
1884 1885
}

1886
target_ulong helper_dvpe(CPUMIPSState *env)
1887
{
1888
    CPUMIPSState *other_cpu_env = first_cpu;
1889 1890 1891 1892
    target_ulong prev = env->mvp->CP0_MVPControl;

    do {
        /* Turn off all VPEs except the one executing the dvpe.  */
1893
        if (other_cpu_env != env) {
1894 1895
            MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env);

1896
            other_cpu_env->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1897
            mips_vpe_sleep(other_cpu);
1898
        }
1899 1900
        other_cpu_env = other_cpu_env->next_cpu;
    } while (other_cpu_env);
1901
    return prev;
1902 1903
}

1904
target_ulong helper_evpe(CPUMIPSState *env)
1905
{
1906
    CPUMIPSState *other_cpu_env = first_cpu;
1907 1908 1909
    target_ulong prev = env->mvp->CP0_MVPControl;

    do {
1910 1911
        MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env);

1912 1913
        if (other_cpu_env != env
            /* If the VPE is WFI, don't disturb its sleep.  */
1914
            && !mips_vpe_is_wfi(other_cpu)) {
1915
            /* Enable the VPE.  */
1916 1917
            other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
            mips_vpe_wake(other_cpu_env); /* And wake it up.  */
1918
        }
1919 1920
        other_cpu_env = other_cpu_env->next_cpu;
    } while (other_cpu_env);
1921
    return prev;
1922
}
1923
#endif /* !CONFIG_USER_ONLY */
1924

1925
void helper_fork(target_ulong arg1, target_ulong arg2)
1926
{
1927 1928
    // arg1 = rt, arg2 = rs
    arg1 = 0;
1929 1930 1931
    // TODO: store to TC register
}

1932
target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
1933
{
B
Blue Swirl 已提交
1934 1935
    target_long arg1 = arg;

1936
    if (arg1 < 0) {
1937
        /* No scheduling policy implemented. */
1938
        if (arg1 != -2) {
1939
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1940
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1941 1942
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1943
                helper_raise_exception(env, EXCP_THREAD);
1944 1945
            }
        }
1946
    } else if (arg1 == 0) {
A
aurel32 已提交
1947
        if (0 /* TODO: TC underflow */) {
1948
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1949
            helper_raise_exception(env, EXCP_THREAD);
1950 1951 1952
        } else {
            // TODO: Deallocate TC
        }
1953
    } else if (arg1 > 0) {
1954 1955 1956
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1957
        helper_raise_exception(env, EXCP_THREAD);
1958
    }
1959
    return env->CP0_YQMask;
1960 1961 1962
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1963
/* TLB management */
1964
static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1965 1966 1967
{
    /* Flush qemu's TLB and discard all shadowed entries.  */
    tlb_flush (env, flush_global);
1968
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1969 1970
}

1971
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1972 1973
{
    /* Discard entries from env->tlb[first] onwards.  */
1974 1975
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1976 1977 1978
    }
}

1979
static void r4k_fill_tlb(CPUMIPSState *env, int idx)
B
bellard 已提交
1980
{
A
Anthony Liguori 已提交
1981
    r4k_tlb_t *tlb;
B
bellard 已提交
1982 1983

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1984
    tlb = &env->tlb->mmu.r4k.tlb[idx];
T
ths 已提交
1985
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1986
#if defined(TARGET_MIPS64)
T
ths 已提交
1987
    tlb->VPN &= env->SEGMask;
1988
#endif
1989
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
1990
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
1991
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1992 1993 1994
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
B
bellard 已提交
1995
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1996 1997 1998
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
B
bellard 已提交
1999 2000 2001
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}

2002
void r4k_helper_tlbwi(CPUMIPSState *env)
B
bellard 已提交
2003
{
A
aurel32 已提交
2004 2005 2006 2007
    int idx;

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

2008 2009 2010
    /* 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.  */
2011
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
2012

A
aurel32 已提交
2013
    r4k_invalidate_tlb(env, idx, 0);
2014
    r4k_fill_tlb(env, idx);
B
bellard 已提交
2015 2016
}

2017
void r4k_helper_tlbwr(CPUMIPSState *env)
B
bellard 已提交
2018 2019 2020
{
    int r = cpu_mips_get_random(env);

2021
    r4k_invalidate_tlb(env, r, 1);
2022
    r4k_fill_tlb(env, r);
B
bellard 已提交
2023 2024
}

2025
void r4k_helper_tlbp(CPUMIPSState *env)
B
bellard 已提交
2026
{
A
Anthony Liguori 已提交
2027
    r4k_tlb_t *tlb;
T
ths 已提交
2028
    target_ulong mask;
B
bellard 已提交
2029
    target_ulong tag;
T
ths 已提交
2030
    target_ulong VPN;
B
bellard 已提交
2031 2032 2033
    uint8_t ASID;
    int i;

B
bellard 已提交
2034
    ASID = env->CP0_EntryHi & 0xFF;
2035 2036
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
2037 2038 2039 2040
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
B
bellard 已提交
2041
        /* Check ASID, virtual page number & size */
T
ths 已提交
2042
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
B
bellard 已提交
2043
            /* TLB match */
T
ths 已提交
2044
            env->CP0_Index = i;
B
bellard 已提交
2045 2046 2047
            break;
        }
    }
2048
    if (i == env->tlb->nb_tlb) {
2049
        /* No match.  Discard any shadow entries, if any of them match.  */
2050
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
2051 2052 2053 2054 2055 2056 2057
            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) {
2058
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
2059 2060 2061
                break;
            }
        }
2062

T
ths 已提交
2063
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
2064 2065 2066
    }
}

2067
void r4k_helper_tlbr(CPUMIPSState *env)
B
bellard 已提交
2068
{
A
Anthony Liguori 已提交
2069
    r4k_tlb_t *tlb;
2070
    uint8_t ASID;
A
aurel32 已提交
2071
    int idx;
B
bellard 已提交
2072

2073
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
2074 2075
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
2076 2077

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

2081
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
2082

B
bellard 已提交
2083
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
T
ths 已提交
2084
    env->CP0_PageMask = tlb->PageMask;
T
ths 已提交
2085 2086 2087 2088
    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 已提交
2089 2090
}

2091
void helper_tlbwi(CPUMIPSState *env)
P
pbrook 已提交
2092
{
2093
    env->tlb->helper_tlbwi(env);
P
pbrook 已提交
2094 2095
}

2096
void helper_tlbwr(CPUMIPSState *env)
P
pbrook 已提交
2097
{
2098
    env->tlb->helper_tlbwr(env);
P
pbrook 已提交
2099 2100
}

2101
void helper_tlbp(CPUMIPSState *env)
P
pbrook 已提交
2102
{
2103
    env->tlb->helper_tlbp(env);
P
pbrook 已提交
2104 2105
}

2106
void helper_tlbr(CPUMIPSState *env)
P
pbrook 已提交
2107
{
2108
    env->tlb->helper_tlbr(env);
P
pbrook 已提交
2109 2110
}

2111
/* Specials */
2112
target_ulong helper_di(CPUMIPSState *env)
2113
{
2114 2115
    target_ulong t0 = env->CP0_Status;

2116 2117
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
    return t0;
2118 2119
}

2120
target_ulong helper_ei(CPUMIPSState *env)
2121
{
2122 2123
    target_ulong t0 = env->CP0_Status;

2124 2125
    env->CP0_Status = t0 | (1 << CP0St_IE);
    return t0;
2126 2127
}

2128
static void debug_pre_eret(CPUMIPSState *env)
B
bellard 已提交
2129
{
2130
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2131 2132 2133 2134 2135 2136 2137 2138
        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");
    }
2139 2140
}

2141
static void debug_post_eret(CPUMIPSState *env)
2142
{
2143
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
        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 已提交
2156
    }
B
bellard 已提交
2157 2158
}

2159
static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2160 2161 2162 2163 2164 2165 2166 2167 2168
{
    env->active_tc.PC = error_pc & ~(target_ulong)1;
    if (error_pc & 1) {
        env->hflags |= MIPS_HFLAG_M16;
    } else {
        env->hflags &= ~(MIPS_HFLAG_M16);
    }
}

2169
void helper_eret(CPUMIPSState *env)
2170
{
2171
    debug_pre_eret(env);
2172
    if (env->CP0_Status & (1 << CP0St_ERL)) {
2173
        set_pc(env, env->CP0_ErrorEPC);
2174 2175
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
2176
        set_pc(env, env->CP0_EPC);
2177 2178 2179
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
2180
    debug_post_eret(env);
2181
    env->lladdr = 1;
2182 2183
}

2184
void helper_deret(CPUMIPSState *env)
2185
{
2186 2187
    debug_pre_eret(env);
    set_pc(env, env->CP0_DEPC);
2188

2189 2190
    env->hflags &= MIPS_HFLAG_DM;
    compute_hflags(env);
2191
    debug_post_eret(env);
2192
    env->lladdr = 1;
2193
}
T
ths 已提交
2194
#endif /* !CONFIG_USER_ONLY */
2195

2196
target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2197 2198 2199
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 0)))
2200
        return env->CP0_EBase & 0x3ff;
2201
    else
2202
        helper_raise_exception(env, EXCP_RI);
2203

2204
    return 0;
2205 2206
}

2207
target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2208 2209 2210
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 1)))
2211
        return env->SYNCI_Step;
2212
    else
2213
        helper_raise_exception(env, EXCP_RI);
2214

2215
    return 0;
2216 2217
}

2218
target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2219 2220 2221
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 2)))
2222
        return env->CP0_Count;
2223
    else
2224
        helper_raise_exception(env, EXCP_RI);
2225

2226
    return 0;
2227 2228
}

2229
target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2230 2231 2232
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 3)))
2233
        return env->CCRes;
2234
    else
2235
        helper_raise_exception(env, EXCP_RI);
2236

2237
    return 0;
2238 2239
}

2240
void helper_pmon(CPUMIPSState *env, int function)
B
bellard 已提交
2241 2242 2243 2244
{
    function /= 2;
    switch (function) {
    case 2: /* TODO: char inbyte(int waitflag); */
2245 2246
        if (env->active_tc.gpr[4] == 0)
            env->active_tc.gpr[2] = -1;
B
bellard 已提交
2247 2248
        /* Fall through */
    case 11: /* TODO: char inbyte (void); */
2249
        env->active_tc.gpr[2] = -1;
B
bellard 已提交
2250 2251 2252
        break;
    case 3:
    case 12:
2253
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
B
bellard 已提交
2254 2255 2256 2257 2258
        break;
    case 17:
        break;
    case 158:
        {
2259
            unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
B
bellard 已提交
2260 2261 2262 2263 2264
            printf("%s", fmt);
        }
        break;
    }
}
2265

2266
void helper_wait(CPUMIPSState *env)
T
ths 已提交
2267 2268
{
    env->halted = 1;
2269
    cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
2270
    helper_raise_exception(env, EXCP_HLT);
T
ths 已提交
2271 2272
}

2273
#if !defined(CONFIG_USER_ONLY)
2274

2275 2276
static void QEMU_NORETURN do_unaligned_access(CPUMIPSState *env,
                                              target_ulong addr, int is_write,
2277
                                              int is_user, uintptr_t retaddr);
B
bellard 已提交
2278

2279
#define MMUSUFFIX _mmu
B
bellard 已提交
2280
#define ALIGNED_ONLY
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293

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

2294 2295
static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
                                int is_write, int is_user, uintptr_t retaddr)
B
bellard 已提交
2296 2297
{
    env->CP0_BadVAddr = addr;
2298 2299
    do_restore_state(env, retaddr);
    helper_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL);
B
bellard 已提交
2300 2301
}

2302
void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
2303
              uintptr_t retaddr)
2304 2305 2306 2307
{
    TranslationBlock *tb;
    int ret;

2308
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
2309 2310 2311
    if (ret) {
        if (retaddr) {
            /* now we have a real cpu fault */
2312
            tb = tb_find_pc(retaddr);
2313 2314 2315
            if (tb) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
2316
                cpu_restore_state(tb, env, retaddr);
2317 2318
            }
        }
2319
        helper_raise_exception_err(env, env->exception_index, env->error_code);
2320 2321 2322
    }
}

A
Avi Kivity 已提交
2323
void cpu_unassigned_access(CPUMIPSState *env, hwaddr addr,
2324
                           int is_write, int is_exec, int unused, int size)
T
ths 已提交
2325 2326
{
    if (is_exec)
2327
        helper_raise_exception(env, EXCP_IBE);
T
ths 已提交
2328
    else
2329
        helper_raise_exception(env, EXCP_DBE);
T
ths 已提交
2330
}
2331
#endif /* !CONFIG_USER_ONLY */
2332 2333 2334

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

P
pbrook 已提交
2335 2336 2337 2338
#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 已提交
2339 2340 2341 2342
#define FLOAT_QNAN32 0x7fbfffff
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
#define FLOAT_SNAN32 0x7fffffff
#define FLOAT_SNAN64 0x7fffffffffffffffULL
T
ths 已提交
2343

2344
/* convert MIPS rounding mode in FCR31 to IEEE library */
B
Blue Swirl 已提交
2345
static unsigned int ieee_rm[] = {
2346 2347 2348 2349 2350 2351 2352
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

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

2355 2356 2357
#define RESTORE_FLUSH_MODE \
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);

2358
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2359
{
2360
    target_ulong arg1;
2361

2362 2363
    switch (reg) {
    case 0:
2364
        arg1 = (int32_t)env->active_fpu.fcr0;
2365 2366
        break;
    case 25:
2367
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2368 2369
        break;
    case 26:
2370
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2371 2372
        break;
    case 28:
2373
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2374 2375
        break;
    default:
2376
        arg1 = (int32_t)env->active_fpu.fcr31;
2377 2378
        break;
    }
2379

2380
    return arg1;
2381 2382
}

2383
void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg)
2384 2385
{
    switch(reg) {
2386
    case 25:
2387
        if (arg1 & 0xffffff00)
2388
            return;
2389 2390
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
2391 2392
        break;
    case 26:
2393
        if (arg1 & 0x007c0000)
2394
            return;
2395
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2396 2397
        break;
    case 28:
2398
        if (arg1 & 0x007c0000)
2399
            return;
2400 2401
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
2402 2403
        break;
    case 31:
2404
        if (arg1 & 0x007c0000)
2405
            return;
2406
        env->active_fpu.fcr31 = arg1;
2407 2408 2409 2410 2411 2412
        break;
    default:
        return;
    }
    /* set rounding mode */
    RESTORE_ROUNDING_MODE;
2413 2414
    /* set flush-to-zero mode */
    RESTORE_FLUSH_MODE;
2415 2416
    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))
2417
        helper_raise_exception(env, EXCP_FPE);
2418 2419
}

2420
static inline int ieee_ex_to_mips(int xcpt)
2421
{
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
    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;
2441 2442
}

2443
static inline void update_fcr31(CPUMIPSState *env)
2444
{
2445
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2446

2447
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457

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

        if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
            helper_raise_exception(env, EXCP_FPE);
        } else {
            UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
        }
    }
2458 2459
}

2460 2461 2462 2463 2464 2465
/* 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  */
2466
uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2467
{
A
Aurelien Jarno 已提交
2468 2469 2470
    fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    update_fcr31(env);
    return fdt0;
2471 2472
}

2473
uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2474
{
A
Aurelien Jarno 已提交
2475 2476 2477
    fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    update_fcr31(env);
    return fst0;
2478
}
2479

2480
uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2481
{
2482 2483
    uint64_t fdt2;

2484
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2485
    update_fcr31(env);
2486
    return fdt2;
2487
}
2488

2489
uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2490
{
2491 2492
    uint64_t fdt2;

2493
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2494
    update_fcr31(env);
2495
    return fdt2;
2496
}
2497

2498
uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2499
{
2500 2501
    uint64_t fdt2;

2502
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2503
    update_fcr31(env);
2504
    return fdt2;
2505
}
2506

2507
uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
2508
{
2509 2510
    uint64_t dt2;

2511
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2512
    update_fcr31(env);
2513
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2514 2515
        dt2 = FLOAT_SNAN64;
    return dt2;
2516
}
2517

2518
uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
2519
{
2520 2521
    uint64_t dt2;

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

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

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

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

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

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

    set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
    update_fcr31(env);

2562
    return ((uint64_t)wth2 << 32) | wt2;
2563
}
2564

2565
uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2566
{
2567 2568
    uint32_t fst2;

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

2574
uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2575
{
2576 2577
    uint32_t fst2;

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

2583
uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2584
{
2585 2586
    uint32_t fst2;

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

2592
uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2593
{
2594 2595 2596
    uint32_t wt2;

    wt2 = wt0;
2597
    update_fcr31(env);
2598
    return wt2;
2599
}
2600

2601
uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2602
{
2603 2604 2605
    uint32_t wt2;

    wt2 = wth0;
2606
    update_fcr31(env);
2607
    return wt2;
2608
}
2609

2610
uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
2611
{
2612 2613
    uint32_t wt2;

2614
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2615
    update_fcr31(env);
2616
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2617 2618
        wt2 = FLOAT_SNAN32;
    return wt2;
2619
}
2620

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

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

2632
uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
2633
{
2634 2635
    uint64_t dt2;

2636 2637
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2638
    RESTORE_ROUNDING_MODE;
2639
    update_fcr31(env);
2640
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2641 2642
        dt2 = FLOAT_SNAN64;
    return dt2;
2643
}
2644

2645
uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
2646
{
2647 2648
    uint64_t dt2;

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

2658
uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
2659
{
2660 2661
    uint32_t wt2;

2662 2663
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2664
    RESTORE_ROUNDING_MODE;
2665
    update_fcr31(env);
2666
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2667 2668
        wt2 = FLOAT_SNAN32;
    return wt2;
2669
}
2670

2671
uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
2672
{
2673 2674
    uint32_t wt2;

2675 2676
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2677
    RESTORE_ROUNDING_MODE;
2678
    update_fcr31(env);
2679
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2680 2681
        wt2 = FLOAT_SNAN32;
    return wt2;
2682 2683
}

2684
uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
2685
{
2686 2687
    uint64_t dt2;

2688
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2689
    update_fcr31(env);
2690
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2691 2692
        dt2 = FLOAT_SNAN64;
    return dt2;
2693
}
2694

2695
uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
2696
{
2697 2698
    uint64_t dt2;

2699
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2700
    update_fcr31(env);
2701
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2702 2703
        dt2 = FLOAT_SNAN64;
    return dt2;
2704
}
2705

2706
uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
2707
{
2708 2709
    uint32_t wt2;

2710
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2711
    update_fcr31(env);
2712
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2713 2714
        wt2 = FLOAT_SNAN32;
    return wt2;
2715
}
2716

2717
uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
2718
{
2719 2720
    uint32_t wt2;

2721
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2722
    update_fcr31(env);
2723
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2724 2725
        wt2 = FLOAT_SNAN32;
    return wt2;
2726 2727
}

2728
uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
2729
{
2730 2731
    uint64_t dt2;

2732 2733
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2734
    RESTORE_ROUNDING_MODE;
2735
    update_fcr31(env);
2736
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2737 2738
        dt2 = FLOAT_SNAN64;
    return dt2;
2739
}
2740

2741
uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
2742
{
2743 2744
    uint64_t dt2;

2745 2746
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2747
    RESTORE_ROUNDING_MODE;
2748
    update_fcr31(env);
2749
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2750 2751
        dt2 = FLOAT_SNAN64;
    return dt2;
2752
}
2753

2754
uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
2755
{
2756 2757
    uint32_t wt2;

2758 2759
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2760
    RESTORE_ROUNDING_MODE;
2761
    update_fcr31(env);
2762
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2763 2764
        wt2 = FLOAT_SNAN32;
    return wt2;
2765
}
2766

2767
uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
2768
{
2769 2770
    uint32_t wt2;

2771 2772
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2773
    RESTORE_ROUNDING_MODE;
2774
    update_fcr31(env);
2775
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2776 2777
        wt2 = FLOAT_SNAN32;
    return wt2;
2778 2779
}

2780
uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
2781
{
2782 2783
    uint64_t dt2;

2784 2785
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2786
    RESTORE_ROUNDING_MODE;
2787
    update_fcr31(env);
2788
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2789 2790
        dt2 = FLOAT_SNAN64;
    return dt2;
2791
}
2792

2793
uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
2794
{
2795 2796
    uint64_t dt2;

2797 2798
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2799
    RESTORE_ROUNDING_MODE;
2800
    update_fcr31(env);
2801
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2802 2803
        dt2 = FLOAT_SNAN64;
    return dt2;
2804
}
2805

2806
uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
2807
{
2808 2809
    uint32_t wt2;

2810 2811
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2812
    RESTORE_ROUNDING_MODE;
2813
    update_fcr31(env);
2814
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2815 2816
        wt2 = FLOAT_SNAN32;
    return wt2;
2817
}
2818

2819
uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
2820
{
2821 2822
    uint32_t wt2;

2823 2824
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2825
    RESTORE_ROUNDING_MODE;
2826
    update_fcr31(env);
2827
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2828 2829
        wt2 = FLOAT_SNAN32;
    return wt2;
2830 2831
}

2832
/* unary operations, not modifying fp status  */
2833
#define FLOAT_UNOP(name)                                       \
2834
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2835 2836 2837
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2838
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2839 2840 2841
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2842
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2843 2844 2845 2846 2847 2848 2849
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2850 2851 2852 2853 2854
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

T
ths 已提交
2855
/* MIPS specific unary operations */
2856
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2857
{
2858 2859
    uint64_t fdt2;

2860
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2861
    update_fcr31(env);
2862
    return fdt2;
T
ths 已提交
2863
}
2864

2865
uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2866
{
2867 2868
    uint32_t fst2;

2869
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2870
    update_fcr31(env);
2871
    return fst2;
T
ths 已提交
2872 2873
}

2874
uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2875
{
2876 2877
    uint64_t fdt2;

2878 2879
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2880
    update_fcr31(env);
2881
    return fdt2;
T
ths 已提交
2882
}
2883

2884
uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2885
{
2886 2887
    uint32_t fst2;

2888 2889
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2890
    update_fcr31(env);
2891
    return fst2;
T
ths 已提交
2892 2893
}

2894
uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2895
{
2896 2897
    uint64_t fdt2;

2898
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2899
    update_fcr31(env);
2900
    return fdt2;
T
ths 已提交
2901
}
2902

2903
uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2904
{
2905 2906
    uint32_t fst2;

2907
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2908
    update_fcr31(env);
2909
    return fst2;
T
ths 已提交
2910
}
2911

2912
uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2913
{
2914 2915 2916
    uint32_t fst2;
    uint32_t fsth2;

2917 2918
    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
2919
    update_fcr31(env);
2920
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2921 2922
}

2923
uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2924
{
2925 2926
    uint64_t fdt2;

2927 2928
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2929
    update_fcr31(env);
2930
    return fdt2;
T
ths 已提交
2931
}
2932

2933
uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
T
ths 已提交
2934
{
2935 2936
    uint32_t fst2;

2937 2938
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2939
    update_fcr31(env);
2940
    return fst2;
T
ths 已提交
2941
}
2942

2943
uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
T
ths 已提交
2944
{
2945 2946 2947
    uint32_t fst2;
    uint32_t fsth2;

2948 2949 2950 2951
    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);
2952
    update_fcr31(env);
2953
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2954 2955
}

2956
#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
2957

2958
/* binary operations */
2959
#define FLOAT_BINOP(name)                                          \
2960 2961
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
                                     uint64_t fdt0, uint64_t fdt1) \
2962 2963 2964
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
2965
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2966
    update_fcr31(env);                                             \
2967 2968 2969
    return dt2;                                                    \
}                                                                  \
                                                                   \
2970 2971
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
                                     uint32_t fst0, uint32_t fst1) \
2972 2973 2974
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
2975
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2976
    update_fcr31(env);                                             \
2977 2978 2979
    return wt2;                                                    \
}                                                                  \
                                                                   \
2980 2981 2982
uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
                                      uint64_t fdt0,               \
                                      uint64_t fdt1)               \
2983 2984 2985 2986 2987 2988 2989 2990
{                                                                  \
    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;                                                 \
                                                                   \
2991 2992
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2993
    update_fcr31(env);                                             \
2994
    return ((uint64_t)wth2 << 32) | wt2;                           \
2995
}
2996

2997 2998 2999 3000 3001 3002
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
/* FMA based operations */
#define FLOAT_FMA(name, type)                                        \
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
                                     uint64_t fdt0, uint64_t fdt1,   \
                                     uint64_t fdt2)                  \
{                                                                    \
    fdt0 = float64_muladd(fdt0, fdt1, fdt2, type,                    \
                         &env->active_fpu.fp_status);                \
    update_fcr31(env);                                               \
    return fdt0;                                                     \
}                                                                    \
                                                                     \
uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
                                     uint32_t fst0, uint32_t fst1,   \
                                     uint32_t fst2)                  \
{                                                                    \
    fst0 = float32_muladd(fst0, fst1, fst2, type,                    \
                         &env->active_fpu.fp_status);                \
    update_fcr31(env);                                               \
    return fst0;                                                     \
}                                                                    \
                                                                     \
uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
                                      uint64_t fdt0, uint64_t fdt1,  \
                                      uint64_t fdt2)                 \
{                                                                    \
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
    uint32_t fsth0 = fdt0 >> 32;                                     \
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
    uint32_t fsth1 = fdt1 >> 32;                                     \
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
    uint32_t fsth2 = fdt2 >> 32;                                     \
                                                                     \
    fst0 = float32_muladd(fst0, fst1, fst2, type,                    \
                          &env->active_fpu.fp_status);               \
    fsth0 = float32_muladd(fsth0, fsth1, fsth2, type,                \
                           &env->active_fpu.fp_status);              \
    update_fcr31(env);                                               \
    return ((uint64_t)fsth0 << 32) | fst0;                           \
}
FLOAT_FMA(madd, 0)
FLOAT_FMA(msub, float_muladd_negate_c)
FLOAT_FMA(nmadd, float_muladd_negate_result)
FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
#undef FLOAT_FMA
3048

T
ths 已提交
3049
/* MIPS specific binary operations */
3050
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3051
{
3052 3053
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
3054
    update_fcr31(env);
3055
    return fdt2;
T
ths 已提交
3056
}
3057

3058
uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3059
{
3060 3061
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
3062
    update_fcr31(env);
3063
    return fst2;
T
ths 已提交
3064
}
3065

3066
uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3067
{
3068 3069 3070 3071 3072
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3073 3074 3075 3076
    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));
3077
    update_fcr31(env);
3078
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3079 3080
}

3081
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3082
{
3083 3084 3085
    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));
3086
    update_fcr31(env);
3087
    return fdt2;
T
ths 已提交
3088
}
3089

3090
uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
T
ths 已提交
3091
{
3092 3093 3094
    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));
3095
    update_fcr31(env);
3096
    return fst2;
T
ths 已提交
3097
}
3098

3099
uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
3100
{
3101 3102 3103 3104 3105
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

3106 3107 3108 3109 3110 3111
    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));
3112
    update_fcr31(env);
3113
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3114 3115
}

3116
uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3117
{
3118 3119 3120 3121 3122 3123 3124
    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;

3125 3126
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3127
    update_fcr31(env);
3128
    return ((uint64_t)fsth2 << 32) | fst2;
3129 3130
}

3131
uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
3132
{
3133 3134 3135 3136 3137 3138 3139
    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;

3140 3141
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3142
    update_fcr31(env);
3143
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
3144 3145
}

T
ths 已提交
3146
/* compare operations */
3147
#define FOP_COND_D(op, cond)                                   \
3148 3149
void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                         uint64_t fdt1, int cc)                \
3150
{                                                              \
3151 3152
    int c;                                                     \
    c = cond;                                                  \
3153
    update_fcr31(env);                                         \
3154
    if (c)                                                     \
3155
        SET_FP_COND(cc, env->active_fpu);                      \
3156
    else                                                       \
3157
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3158
}                                                              \
3159 3160
void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                            uint64_t fdt1, int cc)             \
3161 3162 3163 3164 3165
{                                                              \
    int c;                                                     \
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
3166
    update_fcr31(env);                                         \
3167
    if (c)                                                     \
3168
        SET_FP_COND(cc, env->active_fpu);                      \
3169
    else                                                       \
3170
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3171 3172 3173
}

/* NOTE: the comma operator will make "cond" to eval to false,
3174 3175 3176
 * 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))
3177
FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3178
FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3179 3180 3181 3182
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))
3183
/* NOTE: the comma operator will make "cond" to eval to false,
3184 3185 3186
 * 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))
3187 3188 3189
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))
3190
FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3191
FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3192
FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3193 3194

#define FOP_COND_S(op, cond)                                   \
3195 3196
void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
                         uint32_t fst1, int cc)                \
3197
{                                                              \
3198 3199
    int c;                                                     \
    c = cond;                                                  \
3200
    update_fcr31(env);                                         \
3201
    if (c)                                                     \
3202
        SET_FP_COND(cc, env->active_fpu);                      \
3203
    else                                                       \
3204
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3205
}                                                              \
3206 3207
void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
                            uint32_t fst1, int cc)             \
3208 3209 3210 3211 3212
{                                                              \
    int c;                                                     \
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
3213
    update_fcr31(env);                                         \
3214
    if (c)                                                     \
3215
        SET_FP_COND(cc, env->active_fpu);                      \
3216
    else                                                       \
3217
        CLEAR_FP_COND(cc, env->active_fpu);                    \
3218 3219 3220
}

/* NOTE: the comma operator will make "cond" to eval to false,
3221 3222 3223
 * 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))
3224
FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3225
FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3226 3227 3228 3229
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))
3230
/* NOTE: the comma operator will make "cond" to eval to false,
3231 3232 3233
 * 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))
3234 3235 3236
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))
3237
FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3238
FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3239
FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3240 3241

#define FOP_COND_PS(op, condl, condh)                           \
3242 3243
void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
                          uint64_t fdt1, int cc)                \
3244
{                                                               \
3245 3246 3247 3248 3249 3250 3251 3252
    uint32_t fst0, fsth0, fst1, fsth1;                          \
    int ch, cl;                                                 \
    fst0 = fdt0 & 0XFFFFFFFF;                                   \
    fsth0 = fdt0 >> 32;                                         \
    fst1 = fdt1 & 0XFFFFFFFF;                                   \
    fsth1 = fdt1 >> 32;                                         \
    cl = condl;                                                 \
    ch = condh;                                                 \
3253
    update_fcr31(env);                                          \
3254
    if (cl)                                                     \
3255
        SET_FP_COND(cc, env->active_fpu);                       \
3256
    else                                                        \
3257
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3258
    if (ch)                                                     \
3259
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3260
    else                                                        \
3261
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3262
}                                                               \
3263 3264
void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
                             uint64_t fdt1, int cc)             \
3265
{                                                               \
3266 3267 3268 3269 3270 3271 3272 3273
    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;                                                 \
3274
    update_fcr31(env);                                          \
3275
    if (cl)                                                     \
3276
        SET_FP_COND(cc, env->active_fpu);                       \
3277
    else                                                        \
3278
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3279
    if (ch)                                                     \
3280
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3281
    else                                                        \
3282
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3283 3284 3285
}

/* NOTE: the comma operator will make "cond" to eval to false,
3286 3287 3288 3289 3290
 * 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))
3291 3292
FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3293 3294
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))
3295 3296 3297 3298 3299 3300 3301 3302
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))
3303
/* NOTE: the comma operator will make "cond" to eval to false,
3304 3305 3306 3307 3308
 * 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))
3309 3310 3311 3312 3313 3314
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))
3315 3316
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))
3317 3318
FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3319 3320
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))