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

22 23
#include "host-utils.h"

P
pbrook 已提交
24
#include "helper.h"
B
bellard 已提交
25 26 27
/*****************************************************************************/
/* Exceptions processing helpers */

28
void helper_raise_exception_err (uint32_t exception, int error_code)
B
bellard 已提交
29 30
{
#if 1
31 32
    if (exception < 0x100)
        qemu_log("%s: %d %d\n", __func__, exception, error_code);
B
bellard 已提交
33 34 35 36 37 38
#endif
    env->exception_index = exception;
    env->error_code = error_code;
    cpu_loop_exit();
}

39
void helper_raise_exception (uint32_t exception)
B
bellard 已提交
40
{
41
    helper_raise_exception_err(exception, 0);
B
bellard 已提交
42 43
}

44
void helper_interrupt_restart (void)
45 46 47 48 49 50 51
{
    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
        !(env->CP0_Status & (1 << CP0St_ERL)) &&
        !(env->hflags & MIPS_HFLAG_DM) &&
        (env->CP0_Status & (1 << CP0St_IE)) &&
        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
        env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
52
        helper_raise_exception(EXCP_EXT_INTERRUPT);
53 54 55
    }
}

56 57
#if !defined(CONFIG_USER_ONLY)
static void do_restore_state (void *pc_ptr)
B
bellard 已提交
58
{
B
bellard 已提交
59 60 61 62 63 64 65
    TranslationBlock *tb;
    unsigned long pc = (unsigned long) pc_ptr;
    
    tb = tb_find_pc (pc);
    if (tb) {
        cpu_restore_state (tb, env, pc, NULL);
    }
B
bellard 已提交
66
}
67
#endif
B
bellard 已提交
68

69
target_ulong helper_clo (target_ulong arg1)
70
{
71
    return clo32(arg1);
72 73
}

74
target_ulong helper_clz (target_ulong arg1)
75
{
76
    return clz32(arg1);
77 78
}

79
#if defined(TARGET_MIPS64)
80
target_ulong helper_dclo (target_ulong arg1)
81
{
82
    return clo64(arg1);
83 84
}

85
target_ulong helper_dclz (target_ulong arg1)
86
{
87
    return clz64(arg1);
88
}
89
#endif /* TARGET_MIPS64 */
90

B
bellard 已提交
91
/* 64 bits arithmetic for 32 bits hosts */
T
ths 已提交
92
static inline uint64_t get_HILO (void)
B
bellard 已提交
93
{
94
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
B
bellard 已提交
95 96
}

T
ths 已提交
97
static inline void set_HILO (uint64_t HILO)
B
bellard 已提交
98
{
99 100
    env->active_tc.LO[0] = (int32_t)HILO;
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
B
bellard 已提交
101 102
}

103
static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
104
{
105
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
106
    arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
107 108
}

109
static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
110
{
111
    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
112
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
113 114 115
}

/* Multiplication variants of the vr54xx. */
116
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
117
{
118
    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
119

120
    return arg1;
121 122
}

123
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
124
{
125
    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
126

127
    return arg1;
128 129
}

130
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
131
{
132
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
133

134
    return arg1;
135 136
}

137
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
138
{
139
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
140

141
    return arg1;
142 143
}

144
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
145
{
146
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
147

148
    return arg1;
149 150
}

151
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
152
{
153
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
154

155
    return arg1;
156 157
}

158
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
159
{
160
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
161

162
    return arg1;
163 164
}

165
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
166
{
167
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
168

169
    return arg1;
170 171
}

172
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
173
{
174
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
175

176
    return arg1;
177 178
}

179
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
180
{
181
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
182

183
    return arg1;
184 185
}

186
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
187
{
188
    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
189

190
    return arg1;
191 192
}

193
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
194
{
195
    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
196

197
    return arg1;
198 199
}

200
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
201
{
202
    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
203

204
    return arg1;
205 206
}

207
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
208
{
209
    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
210

211
    return arg1;
212
}
B
bellard 已提交
213

214
#ifdef TARGET_MIPS64
215
void helper_dmult (target_ulong arg1, target_ulong arg2)
216
{
217
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
218 219
}

220
void helper_dmultu (target_ulong arg1, target_ulong arg2)
221
{
222
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
223 224 225
}
#endif

T
ths 已提交
226 227 228 229 230 231 232 233
#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

234
target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
{
    target_ulong tmp;

#ifdef CONFIG_USER_ONLY
#define ldfun ldub_raw
#else
    int (*ldfun)(target_ulong);

    switch (mem_idx)
    {
    case 0: ldfun = ldub_kernel; break;
    case 1: ldfun = ldub_super; break;
    default:
    case 2: ldfun = ldub_user; break;
    }
#endif
251 252
    tmp = ldfun(arg2);
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
253

254 255 256
    if (GET_LMASK(arg2) <= 2) {
        tmp = ldfun(GET_OFFSET(arg2, 1));
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
257 258
    }

259 260 261
    if (GET_LMASK(arg2) <= 1) {
        tmp = ldfun(GET_OFFSET(arg2, 2));
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
262 263
    }

264 265 266
    if (GET_LMASK(arg2) == 0) {
        tmp = ldfun(GET_OFFSET(arg2, 3));
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
267
    }
268
    return (int32_t)arg1;
T
ths 已提交
269 270
}

271
target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
{
    target_ulong tmp;

#ifdef CONFIG_USER_ONLY
#define ldfun ldub_raw
#else
    int (*ldfun)(target_ulong);

    switch (mem_idx)
    {
    case 0: ldfun = ldub_kernel; break;
    case 1: ldfun = ldub_super; break;
    default:
    case 2: ldfun = ldub_user; break;
    }
#endif
288 289
    tmp = ldfun(arg2);
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
T
ths 已提交
290

291 292 293
    if (GET_LMASK(arg2) >= 1) {
        tmp = ldfun(GET_OFFSET(arg2, -1));
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
T
ths 已提交
294 295
    }

296 297 298
    if (GET_LMASK(arg2) >= 2) {
        tmp = ldfun(GET_OFFSET(arg2, -2));
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
T
ths 已提交
299 300
    }

301 302 303
    if (GET_LMASK(arg2) == 3) {
        tmp = ldfun(GET_OFFSET(arg2, -3));
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
T
ths 已提交
304
    }
305
    return (int32_t)arg1;
T
ths 已提交
306 307
}

308
void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322
{
#ifdef CONFIG_USER_ONLY
#define stfun stb_raw
#else
    void (*stfun)(target_ulong, int);

    switch (mem_idx)
    {
    case 0: stfun = stb_kernel; break;
    case 1: stfun = stb_super; break;
    default:
    case 2: stfun = stb_user; break;
    }
#endif
323
    stfun(arg2, (uint8_t)(arg1 >> 24));
T
ths 已提交
324

325 326
    if (GET_LMASK(arg2) <= 2)
        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16));
T
ths 已提交
327

328 329
    if (GET_LMASK(arg2) <= 1)
        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8));
T
ths 已提交
330

331 332
    if (GET_LMASK(arg2) == 0)
        stfun(GET_OFFSET(arg2, 3), (uint8_t)arg1);
T
ths 已提交
333 334
}

335
void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
336 337 338 339 340 341 342 343 344 345 346 347 348 349
{
#ifdef CONFIG_USER_ONLY
#define stfun stb_raw
#else
    void (*stfun)(target_ulong, int);

    switch (mem_idx)
    {
    case 0: stfun = stb_kernel; break;
    case 1: stfun = stb_super; break;
    default:
    case 2: stfun = stb_user; break;
    }
#endif
350
    stfun(arg2, (uint8_t)arg1);
T
ths 已提交
351

352 353
    if (GET_LMASK(arg2) >= 1)
        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
T
ths 已提交
354

355 356
    if (GET_LMASK(arg2) >= 2)
        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
T
ths 已提交
357

358 359
    if (GET_LMASK(arg2) == 3)
        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
T
ths 已提交
360 361 362 363 364 365 366 367 368 369 370 371
}

#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

372
target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
373 374 375 376 377 378
{
    uint64_t tmp;

#ifdef CONFIG_USER_ONLY
#define ldfun ldub_raw
#else
379
    int (*ldfun)(target_ulong);
T
ths 已提交
380 381 382 383 384 385 386 387 388

    switch (mem_idx)
    {
    case 0: ldfun = ldub_kernel; break;
    case 1: ldfun = ldub_super; break;
    default:
    case 2: ldfun = ldub_user; break;
    }
#endif
389 390
    tmp = ldfun(arg2);
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
391

392 393 394
    if (GET_LMASK64(arg2) <= 6) {
        tmp = ldfun(GET_OFFSET(arg2, 1));
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
395 396
    }

397 398 399
    if (GET_LMASK64(arg2) <= 5) {
        tmp = ldfun(GET_OFFSET(arg2, 2));
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
400 401
    }

402 403 404
    if (GET_LMASK64(arg2) <= 4) {
        tmp = ldfun(GET_OFFSET(arg2, 3));
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
405 406
    }

407 408 409
    if (GET_LMASK64(arg2) <= 3) {
        tmp = ldfun(GET_OFFSET(arg2, 4));
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
410 411
    }

412 413 414
    if (GET_LMASK64(arg2) <= 2) {
        tmp = ldfun(GET_OFFSET(arg2, 5));
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
415 416
    }

417 418 419
    if (GET_LMASK64(arg2) <= 1) {
        tmp = ldfun(GET_OFFSET(arg2, 6));
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
T
ths 已提交
420 421
    }

422 423 424
    if (GET_LMASK64(arg2) == 0) {
        tmp = ldfun(GET_OFFSET(arg2, 7));
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
425
    }
426

427
    return arg1;
T
ths 已提交
428 429
}

430
target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
431 432 433 434 435 436
{
    uint64_t tmp;

#ifdef CONFIG_USER_ONLY
#define ldfun ldub_raw
#else
437
    int (*ldfun)(target_ulong);
T
ths 已提交
438 439 440 441 442 443 444 445 446

    switch (mem_idx)
    {
    case 0: ldfun = ldub_kernel; break;
    case 1: ldfun = ldub_super; break;
    default:
    case 2: ldfun = ldub_user; break;
    }
#endif
447 448
    tmp = ldfun(arg2);
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
T
ths 已提交
449

450 451 452
    if (GET_LMASK64(arg2) >= 1) {
        tmp = ldfun(GET_OFFSET(arg2, -1));
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
T
ths 已提交
453 454
    }

455 456 457
    if (GET_LMASK64(arg2) >= 2) {
        tmp = ldfun(GET_OFFSET(arg2, -2));
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
T
ths 已提交
458 459
    }

460 461 462
    if (GET_LMASK64(arg2) >= 3) {
        tmp = ldfun(GET_OFFSET(arg2, -3));
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
T
ths 已提交
463 464
    }

465 466 467
    if (GET_LMASK64(arg2) >= 4) {
        tmp = ldfun(GET_OFFSET(arg2, -4));
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
T
ths 已提交
468 469
    }

470 471 472
    if (GET_LMASK64(arg2) >= 5) {
        tmp = ldfun(GET_OFFSET(arg2, -5));
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
T
ths 已提交
473 474
    }

475 476 477
    if (GET_LMASK64(arg2) >= 6) {
        tmp = ldfun(GET_OFFSET(arg2, -6));
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
T
ths 已提交
478 479
    }

480 481 482
    if (GET_LMASK64(arg2) == 7) {
        tmp = ldfun(GET_OFFSET(arg2, -7));
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
T
ths 已提交
483
    }
484

485
    return arg1;
T
ths 已提交
486 487
}

488
void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501 502
{
#ifdef CONFIG_USER_ONLY
#define stfun stb_raw
#else
    void (*stfun)(target_ulong, int);

    switch (mem_idx)
    {
    case 0: stfun = stb_kernel; break;
    case 1: stfun = stb_super; break;
    default:
    case 2: stfun = stb_user; break;
    }
#endif
503
    stfun(arg2, (uint8_t)(arg1 >> 56));
T
ths 已提交
504

505 506
    if (GET_LMASK64(arg2) <= 6)
        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48));
T
ths 已提交
507

508 509
    if (GET_LMASK64(arg2) <= 5)
        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40));
T
ths 已提交
510

511 512
    if (GET_LMASK64(arg2) <= 4)
        stfun(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32));
T
ths 已提交
513

514 515
    if (GET_LMASK64(arg2) <= 3)
        stfun(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24));
T
ths 已提交
516

517 518
    if (GET_LMASK64(arg2) <= 2)
        stfun(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16));
T
ths 已提交
519

520 521
    if (GET_LMASK64(arg2) <= 1)
        stfun(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8));
T
ths 已提交
522

523 524
    if (GET_LMASK64(arg2) <= 0)
        stfun(GET_OFFSET(arg2, 7), (uint8_t)arg1);
T
ths 已提交
525 526
}

527
void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
T
ths 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541
{
#ifdef CONFIG_USER_ONLY
#define stfun stb_raw
#else
    void (*stfun)(target_ulong, int);

    switch (mem_idx)
    {
    case 0: stfun = stb_kernel; break;
    case 1: stfun = stb_super; break;
     default:
    case 2: stfun = stb_user; break;
    }
#endif
542
    stfun(arg2, (uint8_t)arg1);
T
ths 已提交
543

544 545
    if (GET_LMASK64(arg2) >= 1)
        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
T
ths 已提交
546

547 548
    if (GET_LMASK64(arg2) >= 2)
        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
T
ths 已提交
549

550 551
    if (GET_LMASK64(arg2) >= 3)
        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
T
ths 已提交
552

553 554
    if (GET_LMASK64(arg2) >= 4)
        stfun(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32));
T
ths 已提交
555

556 557
    if (GET_LMASK64(arg2) >= 5)
        stfun(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40));
T
ths 已提交
558

559 560
    if (GET_LMASK64(arg2) >= 6)
        stfun(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48));
T
ths 已提交
561

562 563
    if (GET_LMASK64(arg2) == 7)
        stfun(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56));
T
ths 已提交
564 565 566
}
#endif /* TARGET_MIPS64 */

T
ths 已提交
567
#ifndef CONFIG_USER_ONLY
B
bellard 已提交
568
/* CP0 helpers */
569
target_ulong helper_mfc0_mvpcontrol (void)
570
{
571
    return env->mvp->CP0_MVPControl;
572 573
}

574
target_ulong helper_mfc0_mvpconf0 (void)
575
{
576
    return env->mvp->CP0_MVPConf0;
577 578
}

579
target_ulong helper_mfc0_mvpconf1 (void)
580
{
581
    return env->mvp->CP0_MVPConf1;
582 583
}

584
target_ulong helper_mfc0_random (void)
B
bellard 已提交
585
{
586
    return (int32_t)cpu_mips_get_random(env);
587
}
B
bellard 已提交
588

589
target_ulong helper_mfc0_tcstatus (void)
590
{
591
    return env->active_tc.CP0_TCStatus;
592 593
}

594
target_ulong helper_mftc0_tcstatus(void)
595 596 597
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

598 599 600 601
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCStatus;
    else
        return env->tcs[other_tc].CP0_TCStatus;
602 603
}

604
target_ulong helper_mfc0_tcbind (void)
605
{
606
    return env->active_tc.CP0_TCBind;
607 608
}

609
target_ulong helper_mftc0_tcbind(void)
610 611 612
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

613 614 615 616
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCBind;
    else
        return env->tcs[other_tc].CP0_TCBind;
617 618
}

619
target_ulong helper_mfc0_tcrestart (void)
620
{
621
    return env->active_tc.PC;
622 623
}

624
target_ulong helper_mftc0_tcrestart(void)
625 626 627
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

628 629 630 631
    if (other_tc == env->current_tc)
        return env->active_tc.PC;
    else
        return env->tcs[other_tc].PC;
632 633
}

634
target_ulong helper_mfc0_tchalt (void)
635
{
636
    return env->active_tc.CP0_TCHalt;
637 638
}

639
target_ulong helper_mftc0_tchalt(void)
640 641 642
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

643 644 645 646
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCHalt;
    else
        return env->tcs[other_tc].CP0_TCHalt;
647 648
}

649
target_ulong helper_mfc0_tccontext (void)
650
{
651
    return env->active_tc.CP0_TCContext;
652 653
}

654
target_ulong helper_mftc0_tccontext(void)
655 656 657
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

658 659 660 661
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCContext;
    else
        return env->tcs[other_tc].CP0_TCContext;
662 663
}

664
target_ulong helper_mfc0_tcschedule (void)
665
{
666
    return env->active_tc.CP0_TCSchedule;
667 668
}

669
target_ulong helper_mftc0_tcschedule(void)
670 671 672
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

673 674 675 676
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCSchedule;
    else
        return env->tcs[other_tc].CP0_TCSchedule;
677 678
}

679
target_ulong helper_mfc0_tcschefback (void)
680
{
681
    return env->active_tc.CP0_TCScheFBack;
682 683
}

684
target_ulong helper_mftc0_tcschefback(void)
685 686 687
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

688 689 690 691
    if (other_tc == env->current_tc)
        return env->active_tc.CP0_TCScheFBack;
    else
        return env->tcs[other_tc].CP0_TCScheFBack;
692 693
}

694
target_ulong helper_mfc0_count (void)
695
{
696
    return (int32_t)cpu_mips_get_count(env);
B
bellard 已提交
697 698
}

699
target_ulong helper_mftc0_entryhi(void)
700 701
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
702
    int32_t tcstatus;
703

704 705 706 707 708 709
    if (other_tc == env->current_tc)
        tcstatus = env->active_tc.CP0_TCStatus;
    else
        tcstatus = env->tcs[other_tc].CP0_TCStatus;

    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
710 711
}

712
target_ulong helper_mftc0_status(void)
713 714
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
715
    target_ulong t0;
716 717 718 719 720 721
    int32_t tcstatus;

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

723 724 725 726 727 728
    t0 = env->CP0_Status & ~0xf1000018;
    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);

    return t0;
729 730
}

731
target_ulong helper_mfc0_lladdr (void)
732
{
733
    return (int32_t)env->CP0_LLAddr >> 4;
734 735
}

736
target_ulong helper_mfc0_watchlo (uint32_t sel)
737
{
738
    return (int32_t)env->CP0_WatchLo[sel];
739 740
}

741
target_ulong helper_mfc0_watchhi (uint32_t sel)
742
{
743
    return env->CP0_WatchHi[sel];
744 745
}

746
target_ulong helper_mfc0_debug (void)
747
{
748
    target_ulong t0 = env->CP0_Debug;
749
    if (env->hflags & MIPS_HFLAG_DM)
750 751 752
        t0 |= 1 << CP0DB_DM;

    return t0;
753 754
}

755
target_ulong helper_mftc0_debug(void)
756 757
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
758 759 760 761 762 763
    int32_t tcstatus;

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

    /* XXX: Might be wrong, check with EJTAG spec. */
766
    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
767
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
768 769 770
}

#if defined(TARGET_MIPS64)
771
target_ulong helper_dmfc0_tcrestart (void)
772
{
773
    return env->active_tc.PC;
774 775
}

776
target_ulong helper_dmfc0_tchalt (void)
777
{
778
    return env->active_tc.CP0_TCHalt;
779 780
}

781
target_ulong helper_dmfc0_tccontext (void)
782
{
783
    return env->active_tc.CP0_TCContext;
784 785
}

786
target_ulong helper_dmfc0_tcschedule (void)
787
{
788
    return env->active_tc.CP0_TCSchedule;
789 790
}

791
target_ulong helper_dmfc0_tcschefback (void)
792
{
793
    return env->active_tc.CP0_TCScheFBack;
794 795
}

796
target_ulong helper_dmfc0_lladdr (void)
797
{
798
    return env->CP0_LLAddr >> 4;
799 800
}

801
target_ulong helper_dmfc0_watchlo (uint32_t sel)
802
{
803
    return env->CP0_WatchLo[sel];
804 805 806
}
#endif /* TARGET_MIPS64 */

807
void helper_mtc0_index (target_ulong arg1)
808 809 810 811 812 813 814 815
{
    int num = 1;
    unsigned int tmp = env->tlb->nb_tlb;

    do {
        tmp >>= 1;
        num <<= 1;
    } while (tmp);
816
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
817 818
}

819
void helper_mtc0_mvpcontrol (target_ulong arg1)
820 821 822 823 824 825 826 827 828
{
    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);
829
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
830 831 832 833 834 835

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

    env->mvp->CP0_MVPControl = newval;
}

836
void helper_mtc0_vpecontrol (target_ulong arg1)
837 838 839 840 841 842
{
    uint32_t mask;
    uint32_t newval;

    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
843
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
844 845 846 847 848 849 850 851 852

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

    // TODO: Enable/disable TCs.

    env->CP0_VPEControl = newval;
}

853
void helper_mtc0_vpeconf0 (target_ulong arg1)
854 855 856 857 858 859 860 861 862
{
    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);
    }
863
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
864 865 866 867 868 869

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

    env->CP0_VPEConf0 = newval;
}

870
void helper_mtc0_vpeconf1 (target_ulong arg1)
871 872 873 874 875 876 877
{
    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);
878
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
879 880 881 882 883 884 885 886 887

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

    // TODO: Handle FPU (CP1) binding.

    env->CP0_VPEConf1 = newval;
}

888
void helper_mtc0_yqmask (target_ulong arg1)
889 890 891 892 893
{
    /* Yield qualifier inputs not implemented. */
    env->CP0_YQMask = 0x00000000;
}

894
void helper_mtc0_vpeopt (target_ulong arg1)
895
{
896
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
897 898
}

899
void helper_mtc0_entrylo0 (target_ulong arg1)
900 901 902
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
903
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
904 905
}

906
void helper_mtc0_tcstatus (target_ulong arg1)
907 908 909 910
{
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    uint32_t newval;

911
    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
912 913 914

    // TODO: Sync with CP0_Status.

915
    env->active_tc.CP0_TCStatus = newval;
916 917
}

918
void helper_mttc0_tcstatus (target_ulong arg1)
919 920 921 922 923
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

    // TODO: Sync with CP0_Status.

924
    if (other_tc == env->current_tc)
925
        env->active_tc.CP0_TCStatus = arg1;
926
    else
927
        env->tcs[other_tc].CP0_TCStatus = arg1;
928 929
}

930
void helper_mtc0_tcbind (target_ulong arg1)
931 932 933 934 935 936
{
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
937
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
938
    env->active_tc.CP0_TCBind = newval;
939 940
}

941
void helper_mttc0_tcbind (target_ulong arg1)
942 943 944 945 946 947 948
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    uint32_t mask = (1 << CP0TCBd_TBE);
    uint32_t newval;

    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
        mask |= (1 << CP0TCBd_CurVPE);
949
    if (other_tc == env->current_tc) {
950
        newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
951 952
        env->active_tc.CP0_TCBind = newval;
    } else {
953
        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
954 955
        env->tcs[other_tc].CP0_TCBind = newval;
    }
956 957
}

958
void helper_mtc0_tcrestart (target_ulong arg1)
959
{
960
    env->active_tc.PC = arg1;
961
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
962 963 964 965
    env->CP0_LLAddr = 0ULL;
    /* MIPS16 not implemented. */
}

966
void helper_mttc0_tcrestart (target_ulong arg1)
967 968 969
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

970
    if (other_tc == env->current_tc) {
971
        env->active_tc.PC = arg1;
972 973 974 975
        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        env->CP0_LLAddr = 0ULL;
        /* MIPS16 not implemented. */
    } else {
976
        env->tcs[other_tc].PC = arg1;
977 978 979 980
        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
        env->CP0_LLAddr = 0ULL;
        /* MIPS16 not implemented. */
    }
981 982
}

983
void helper_mtc0_tchalt (target_ulong arg1)
984
{
985
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
986 987 988 989

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

990
void helper_mttc0_tchalt (target_ulong arg1)
991 992 993 994 995
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

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

996
    if (other_tc == env->current_tc)
997
        env->active_tc.CP0_TCHalt = arg1;
998
    else
999
        env->tcs[other_tc].CP0_TCHalt = arg1;
1000 1001
}

1002
void helper_mtc0_tccontext (target_ulong arg1)
1003
{
1004
    env->active_tc.CP0_TCContext = arg1;
1005 1006
}

1007
void helper_mttc0_tccontext (target_ulong arg1)
1008 1009 1010
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1011
    if (other_tc == env->current_tc)
1012
        env->active_tc.CP0_TCContext = arg1;
1013
    else
1014
        env->tcs[other_tc].CP0_TCContext = arg1;
1015 1016
}

1017
void helper_mtc0_tcschedule (target_ulong arg1)
1018
{
1019
    env->active_tc.CP0_TCSchedule = arg1;
1020 1021
}

1022
void helper_mttc0_tcschedule (target_ulong arg1)
1023 1024 1025
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1026
    if (other_tc == env->current_tc)
1027
        env->active_tc.CP0_TCSchedule = arg1;
1028
    else
1029
        env->tcs[other_tc].CP0_TCSchedule = arg1;
1030 1031
}

1032
void helper_mtc0_tcschefback (target_ulong arg1)
1033
{
1034
    env->active_tc.CP0_TCScheFBack = arg1;
1035 1036
}

1037
void helper_mttc0_tcschefback (target_ulong arg1)
1038 1039 1040
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1041
    if (other_tc == env->current_tc)
1042
        env->active_tc.CP0_TCScheFBack = arg1;
1043
    else
1044
        env->tcs[other_tc].CP0_TCScheFBack = arg1;
1045 1046
}

1047
void helper_mtc0_entrylo1 (target_ulong arg1)
1048 1049 1050
{
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
1051
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1052 1053
}

1054
void helper_mtc0_context (target_ulong arg1)
1055
{
1056
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1057 1058
}

1059
void helper_mtc0_pagemask (target_ulong arg1)
1060 1061
{
    /* 1k pages not implemented */
1062
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1063 1064
}

1065
void helper_mtc0_pagegrain (target_ulong arg1)
1066 1067 1068 1069 1070 1071 1072
{
    /* SmartMIPS not implemented */
    /* Large physaddr (PABITS) not implemented */
    /* 1k pages not implemented */
    env->CP0_PageGrain = 0;
}

1073
void helper_mtc0_wired (target_ulong arg1)
1074
{
1075
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1076 1077
}

1078
void helper_mtc0_srsconf0 (target_ulong arg1)
1079
{
1080
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1081 1082
}

1083
void helper_mtc0_srsconf1 (target_ulong arg1)
1084
{
1085
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1086 1087
}

1088
void helper_mtc0_srsconf2 (target_ulong arg1)
1089
{
1090
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1091 1092
}

1093
void helper_mtc0_srsconf3 (target_ulong arg1)
1094
{
1095
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1096 1097
}

1098
void helper_mtc0_srsconf4 (target_ulong arg1)
1099
{
1100
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1101 1102
}

1103
void helper_mtc0_hwrena (target_ulong arg1)
1104
{
1105
    env->CP0_HWREna = arg1 & 0x0000000F;
1106 1107
}

1108
void helper_mtc0_count (target_ulong arg1)
1109
{
1110
    cpu_mips_store_count(env, arg1);
1111 1112
}

1113
void helper_mtc0_entryhi (target_ulong arg1)
1114 1115 1116 1117
{
    target_ulong old, val;

    /* 1k pages not implemented */
1118
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1119 1120 1121 1122 1123 1124
#if defined(TARGET_MIPS64)
    val &= env->SEGMask;
#endif
    old = env->CP0_EntryHi;
    env->CP0_EntryHi = val;
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1125 1126
        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
1127 1128 1129 1130 1131 1132
    }
    /* If the ASID changes, flush qemu's TLB.  */
    if ((old & 0xFF) != (val & 0xFF))
        cpu_mips_tlb_flush(env, 1);
}

1133
void helper_mttc0_entryhi(target_ulong arg1)
1134 1135
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1136
    int32_t tcstatus;
1137

1138
    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
1139
    if (other_tc == env->current_tc) {
1140
        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1141 1142
        env->active_tc.CP0_TCStatus = tcstatus;
    } else {
1143
        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1144 1145
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
    }
1146 1147
}

1148
void helper_mtc0_compare (target_ulong arg1)
1149
{
1150
    cpu_mips_store_compare(env, arg1);
1151 1152
}

1153
void helper_mtc0_status (target_ulong arg1)
1154 1155 1156 1157
{
    uint32_t val, old;
    uint32_t mask = env->CP0_Status_rw_bitmask;

1158
    val = arg1 & mask;
1159 1160 1161
    old = env->CP0_Status;
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
    compute_hflags(env);
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
    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;
	}
    }
1174 1175 1176
    cpu_mips_update_irq(env);
}

1177
void helper_mttc0_status(target_ulong arg1)
1178 1179
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1180
    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
1181

1182 1183 1184 1185
    env->CP0_Status = arg1 & ~0xf1000018;
    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1186 1187 1188 1189
    if (other_tc == env->current_tc)
        env->active_tc.CP0_TCStatus = tcstatus;
    else
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1190 1191
}

1192
void helper_mtc0_intctl (target_ulong arg1)
1193 1194
{
    /* vectored interrupts not implemented, no performance counters. */
1195
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
1196 1197
}

1198
void helper_mtc0_srsctl (target_ulong arg1)
1199 1200
{
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1201
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1202 1203
}

1204
void helper_mtc0_cause (target_ulong arg1)
1205 1206 1207 1208 1209 1210 1211
{
    uint32_t mask = 0x00C00300;
    uint32_t old = env->CP0_Cause;

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

1212
    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222

    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
        if (env->CP0_Cause & (1 << CP0Ca_DC))
            cpu_mips_stop_count(env);
        else
            cpu_mips_start_count(env);
    }

    /* Handle the software interrupt as an hardware one, as they
       are very similar */
1223
    if (arg1 & CP0Ca_IP_mask) {
1224 1225 1226 1227
        cpu_mips_update_irq(env);
    }
}

1228
void helper_mtc0_ebase (target_ulong arg1)
1229 1230 1231
{
    /* vectored interrupts not implemented */
    /* Multi-CPU not implemented */
1232
    env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
1233 1234
}

1235
void helper_mtc0_config0 (target_ulong arg1)
1236
{
1237
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1238 1239
}

1240
void helper_mtc0_config2 (target_ulong arg1)
1241 1242 1243 1244 1245
{
    /* tertiary/secondary caches not implemented */
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
}

1246
void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1247 1248 1249
{
    /* Watch exceptions for instructions, data loads, data stores
       not implemented. */
1250
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1251 1252
}

1253
void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1254
{
1255 1256
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1257 1258
}

1259
void helper_mtc0_xcontext (target_ulong arg1)
1260 1261
{
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1262
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1263 1264
}

1265
void helper_mtc0_framemask (target_ulong arg1)
1266
{
1267
    env->CP0_Framemask = arg1; /* XXX */
1268 1269
}

1270
void helper_mtc0_debug (target_ulong arg1)
1271
{
1272 1273
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
    if (arg1 & (1 << CP0DB_DM))
1274 1275 1276 1277 1278
        env->hflags |= MIPS_HFLAG_DM;
    else
        env->hflags &= ~MIPS_HFLAG_DM;
}

1279
void helper_mttc0_debug(target_ulong arg1)
1280 1281
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1282
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1283 1284

    /* XXX: Might be wrong, check with EJTAG spec. */
1285 1286 1287 1288
    if (other_tc == env->current_tc)
        env->active_tc.CP0_Debug_tcstatus = val;
    else
        env->tcs[other_tc].CP0_Debug_tcstatus = val;
1289
    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1290
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1291 1292
}

1293
void helper_mtc0_performance0 (target_ulong arg1)
1294
{
1295
    env->CP0_Performance0 = arg1 & 0x000007ff;
1296 1297
}

1298
void helper_mtc0_taglo (target_ulong arg1)
1299
{
1300
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1301 1302
}

1303
void helper_mtc0_datalo (target_ulong arg1)
1304
{
1305
    env->CP0_DataLo = arg1; /* XXX */
1306 1307
}

1308
void helper_mtc0_taghi (target_ulong arg1)
1309
{
1310
    env->CP0_TagHi = arg1; /* XXX */
1311 1312
}

1313
void helper_mtc0_datahi (target_ulong arg1)
1314
{
1315
    env->CP0_DataHi = arg1; /* XXX */
1316 1317 1318
}

/* MIPS MT functions */
1319
target_ulong helper_mftgpr(uint32_t sel)
1320 1321 1322
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1323 1324 1325 1326
    if (other_tc == env->current_tc)
        return env->active_tc.gpr[sel];
    else
        return env->tcs[other_tc].gpr[sel];
1327 1328
}

1329
target_ulong helper_mftlo(uint32_t sel)
1330 1331 1332
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1333 1334 1335 1336
    if (other_tc == env->current_tc)
        return env->active_tc.LO[sel];
    else
        return env->tcs[other_tc].LO[sel];
1337 1338
}

1339
target_ulong helper_mfthi(uint32_t sel)
1340 1341 1342
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1343 1344 1345 1346
    if (other_tc == env->current_tc)
        return env->active_tc.HI[sel];
    else
        return env->tcs[other_tc].HI[sel];
1347 1348
}

1349
target_ulong helper_mftacx(uint32_t sel)
1350 1351 1352
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1353 1354 1355 1356
    if (other_tc == env->current_tc)
        return env->active_tc.ACX[sel];
    else
        return env->tcs[other_tc].ACX[sel];
1357 1358
}

1359
target_ulong helper_mftdsp(void)
1360 1361 1362
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1363 1364 1365 1366
    if (other_tc == env->current_tc)
        return env->active_tc.DSPControl;
    else
        return env->tcs[other_tc].DSPControl;
1367
}
B
bellard 已提交
1368

1369
void helper_mttgpr(target_ulong arg1, uint32_t sel)
1370 1371 1372
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1373
    if (other_tc == env->current_tc)
1374
        env->active_tc.gpr[sel] = arg1;
1375
    else
1376
        env->tcs[other_tc].gpr[sel] = arg1;
1377 1378
}

1379
void helper_mttlo(target_ulong arg1, uint32_t sel)
1380 1381 1382
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1383
    if (other_tc == env->current_tc)
1384
        env->active_tc.LO[sel] = arg1;
1385
    else
1386
        env->tcs[other_tc].LO[sel] = arg1;
1387 1388
}

1389
void helper_mtthi(target_ulong arg1, uint32_t sel)
1390 1391 1392
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1393
    if (other_tc == env->current_tc)
1394
        env->active_tc.HI[sel] = arg1;
1395
    else
1396
        env->tcs[other_tc].HI[sel] = arg1;
1397 1398
}

1399
void helper_mttacx(target_ulong arg1, uint32_t sel)
1400 1401 1402
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1403
    if (other_tc == env->current_tc)
1404
        env->active_tc.ACX[sel] = arg1;
1405
    else
1406
        env->tcs[other_tc].ACX[sel] = arg1;
1407 1408
}

1409
void helper_mttdsp(target_ulong arg1)
1410 1411 1412
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);

1413
    if (other_tc == env->current_tc)
1414
        env->active_tc.DSPControl = arg1;
1415
    else
1416
        env->tcs[other_tc].DSPControl = arg1;
1417 1418 1419
}

/* MIPS MT functions */
1420
target_ulong helper_dmt(target_ulong arg1)
1421 1422
{
    // TODO
1423 1424
    arg1 = 0;
    // rt = arg1
1425

1426
    return arg1;
1427 1428
}

1429
target_ulong helper_emt(target_ulong arg1)
1430 1431
{
    // TODO
1432 1433
    arg1 = 0;
    // rt = arg1
1434

1435
    return arg1;
1436 1437
}

1438
target_ulong helper_dvpe(target_ulong arg1)
1439 1440
{
    // TODO
1441 1442
    arg1 = 0;
    // rt = arg1
1443

1444
    return arg1;
1445 1446
}

1447
target_ulong helper_evpe(target_ulong arg1)
1448 1449
{
    // TODO
1450 1451
    arg1 = 0;
    // rt = arg1
1452

1453
    return arg1;
1454
}
1455
#endif /* !CONFIG_USER_ONLY */
1456

1457
void helper_fork(target_ulong arg1, target_ulong arg2)
1458
{
1459 1460
    // arg1 = rt, arg2 = rs
    arg1 = 0;
1461 1462 1463
    // TODO: store to TC register
}

1464
target_ulong helper_yield(target_ulong arg1)
1465
{
1466
    if (arg1 < 0) {
1467
        /* No scheduling policy implemented. */
1468
        if (arg1 != -2) {
1469
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1470
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1471 1472
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1473
                helper_raise_exception(EXCP_THREAD);
1474 1475
            }
        }
1476
    } else if (arg1 == 0) {
A
aurel32 已提交
1477
        if (0 /* TODO: TC underflow */) {
1478
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1479
            helper_raise_exception(EXCP_THREAD);
1480 1481 1482
        } else {
            // TODO: Deallocate TC
        }
1483
    } else if (arg1 > 0) {
1484 1485 1486
        /* Yield qualifier inputs not implemented. */
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1487
        helper_raise_exception(EXCP_THREAD);
1488
    }
1489
    return env->CP0_YQMask;
1490 1491 1492
}

#ifndef CONFIG_USER_ONLY
B
bellard 已提交
1493
/* TLB management */
1494 1495 1496 1497
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
{
    /* Flush qemu's TLB and discard all shadowed entries.  */
    tlb_flush (env, flush_global);
1498
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1499 1500
}

1501
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1502 1503
{
    /* Discard entries from env->tlb[first] onwards.  */
1504 1505
    while (env->tlb->tlb_in_use > first) {
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1506 1507 1508
    }
}

1509
static void r4k_fill_tlb (int idx)
B
bellard 已提交
1510
{
1511
    r4k_tlb_t *tlb;
B
bellard 已提交
1512 1513

    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1514
    tlb = &env->tlb->mmu.r4k.tlb[idx];
T
ths 已提交
1515
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1516
#if defined(TARGET_MIPS64)
T
ths 已提交
1517
    tlb->VPN &= env->SEGMask;
1518
#endif
1519
    tlb->ASID = env->CP0_EntryHi & 0xFF;
T
ths 已提交
1520
    tlb->PageMask = env->CP0_PageMask;
B
bellard 已提交
1521
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1522 1523 1524
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
B
bellard 已提交
1525
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1526 1527 1528
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
B
bellard 已提交
1529 1530 1531
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}

1532
void r4k_helper_tlbwi (void)
B
bellard 已提交
1533
{
A
aurel32 已提交
1534 1535 1536 1537
    int idx;

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

1538 1539 1540
    /* 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.  */
1541
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1542

A
aurel32 已提交
1543 1544
    r4k_invalidate_tlb(env, idx, 0);
    r4k_fill_tlb(idx);
B
bellard 已提交
1545 1546
}

1547
void r4k_helper_tlbwr (void)
B
bellard 已提交
1548 1549 1550
{
    int r = cpu_mips_get_random(env);

1551 1552
    r4k_invalidate_tlb(env, r, 1);
    r4k_fill_tlb(r);
B
bellard 已提交
1553 1554
}

1555
void r4k_helper_tlbp (void)
B
bellard 已提交
1556
{
1557
    r4k_tlb_t *tlb;
T
ths 已提交
1558
    target_ulong mask;
B
bellard 已提交
1559
    target_ulong tag;
T
ths 已提交
1560
    target_ulong VPN;
B
bellard 已提交
1561 1562 1563
    uint8_t ASID;
    int i;

B
bellard 已提交
1564
    ASID = env->CP0_EntryHi & 0xFF;
1565 1566
    for (i = 0; i < env->tlb->nb_tlb; i++) {
        tlb = &env->tlb->mmu.r4k.tlb[i];
T
ths 已提交
1567 1568 1569 1570
        /* 1k pages are not supported. */
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
        tag = env->CP0_EntryHi & ~mask;
        VPN = tlb->VPN & ~mask;
B
bellard 已提交
1571
        /* Check ASID, virtual page number & size */
T
ths 已提交
1572
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
B
bellard 已提交
1573
            /* TLB match */
T
ths 已提交
1574
            env->CP0_Index = i;
B
bellard 已提交
1575 1576 1577
            break;
        }
    }
1578
    if (i == env->tlb->nb_tlb) {
1579
        /* No match.  Discard any shadow entries, if any of them match.  */
1580
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
A
aurel32 已提交
1581 1582 1583 1584 1585 1586 1587
            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) {
1588
                r4k_mips_tlb_flush_extra (env, i);
A
aurel32 已提交
1589 1590 1591
                break;
            }
        }
1592

T
ths 已提交
1593
        env->CP0_Index |= 0x80000000;
B
bellard 已提交
1594 1595 1596
    }
}

1597
void r4k_helper_tlbr (void)
B
bellard 已提交
1598
{
1599
    r4k_tlb_t *tlb;
1600
    uint8_t ASID;
A
aurel32 已提交
1601
    int idx;
B
bellard 已提交
1602

1603
    ASID = env->CP0_EntryHi & 0xFF;
A
aurel32 已提交
1604 1605
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
    tlb = &env->tlb->mmu.r4k.tlb[idx];
B
bellard 已提交
1606 1607

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

1611
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
B
bellard 已提交
1612

B
bellard 已提交
1613
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
T
ths 已提交
1614
    env->CP0_PageMask = tlb->PageMask;
T
ths 已提交
1615 1616 1617 1618
    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 已提交
1619 1620
}

1621
void helper_tlbwi(void)
P
pbrook 已提交
1622
{
1623
    env->tlb->helper_tlbwi();
P
pbrook 已提交
1624 1625
}

1626
void helper_tlbwr(void)
P
pbrook 已提交
1627
{
1628
    env->tlb->helper_tlbwr();
P
pbrook 已提交
1629 1630
}

1631
void helper_tlbp(void)
P
pbrook 已提交
1632
{
1633
    env->tlb->helper_tlbp();
P
pbrook 已提交
1634 1635
}

1636
void helper_tlbr(void)
P
pbrook 已提交
1637
{
1638
    env->tlb->helper_tlbr();
P
pbrook 已提交
1639 1640
}

1641
/* Specials */
1642
target_ulong helper_di (void)
1643
{
1644 1645
    target_ulong t0 = env->CP0_Status;

1646
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
1647
    cpu_mips_update_irq(env);
1648 1649

    return t0;
1650 1651
}

1652
target_ulong helper_ei (void)
1653
{
1654 1655
    target_ulong t0 = env->CP0_Status;

1656
    env->CP0_Status = t0 | (1 << CP0St_IE);
1657
    cpu_mips_update_irq(env);
1658 1659

    return t0;
1660 1661
}

A
aurel32 已提交
1662
static void debug_pre_eret (void)
B
bellard 已提交
1663
{
1664
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1665 1666 1667 1668 1669 1670 1671 1672
        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");
    }
1673 1674
}

A
aurel32 已提交
1675
static void debug_post_eret (void)
1676
{
1677
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689
        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 已提交
1690
    }
B
bellard 已提交
1691 1692
}

1693
void helper_eret (void)
1694
{
1695
    debug_pre_eret();
1696
    if (env->CP0_Status & (1 << CP0St_ERL)) {
1697
        env->active_tc.PC = env->CP0_ErrorEPC;
1698 1699
        env->CP0_Status &= ~(1 << CP0St_ERL);
    } else {
1700
        env->active_tc.PC = env->CP0_EPC;
1701 1702 1703
        env->CP0_Status &= ~(1 << CP0St_EXL);
    }
    compute_hflags(env);
1704
    debug_post_eret();
1705 1706 1707
    env->CP0_LLAddr = 1;
}

1708
void helper_deret (void)
1709
{
1710
    debug_pre_eret();
1711
    env->active_tc.PC = env->CP0_DEPC;
1712 1713
    env->hflags &= MIPS_HFLAG_DM;
    compute_hflags(env);
1714
    debug_post_eret();
1715 1716
    env->CP0_LLAddr = 1;
}
T
ths 已提交
1717
#endif /* !CONFIG_USER_ONLY */
1718

1719
target_ulong helper_rdhwr_cpunum(void)
1720 1721 1722
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 0)))
1723
        return env->CP0_EBase & 0x3ff;
1724
    else
1725
        helper_raise_exception(EXCP_RI);
1726

1727
    return 0;
1728 1729
}

1730
target_ulong helper_rdhwr_synci_step(void)
1731 1732 1733
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 1)))
1734
        return env->SYNCI_Step;
1735
    else
1736
        helper_raise_exception(EXCP_RI);
1737

1738
    return 0;
1739 1740
}

1741
target_ulong helper_rdhwr_cc(void)
1742 1743 1744
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 2)))
1745
        return env->CP0_Count;
1746
    else
1747
        helper_raise_exception(EXCP_RI);
1748

1749
    return 0;
1750 1751
}

1752
target_ulong helper_rdhwr_ccres(void)
1753 1754 1755
{
    if ((env->hflags & MIPS_HFLAG_CP0) ||
        (env->CP0_HWREna & (1 << 3)))
1756
        return env->CCRes;
1757
    else
1758
        helper_raise_exception(EXCP_RI);
1759

1760
    return 0;
1761 1762
}

1763
void helper_pmon (int function)
B
bellard 已提交
1764 1765 1766 1767
{
    function /= 2;
    switch (function) {
    case 2: /* TODO: char inbyte(int waitflag); */
1768 1769
        if (env->active_tc.gpr[4] == 0)
            env->active_tc.gpr[2] = -1;
B
bellard 已提交
1770 1771
        /* Fall through */
    case 11: /* TODO: char inbyte (void); */
1772
        env->active_tc.gpr[2] = -1;
B
bellard 已提交
1773 1774 1775
        break;
    case 3:
    case 12:
1776
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
B
bellard 已提交
1777 1778 1779 1780 1781
        break;
    case 17:
        break;
    case 158:
        {
1782
            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
B
bellard 已提交
1783 1784 1785 1786 1787
            printf("%s", fmt);
        }
        break;
    }
}
1788

1789
void helper_wait (void)
T
ths 已提交
1790 1791
{
    env->halted = 1;
1792
    helper_raise_exception(EXCP_HLT);
T
ths 已提交
1793 1794
}

1795
#if !defined(CONFIG_USER_ONLY)
1796

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

1799
#define MMUSUFFIX _mmu
B
bellard 已提交
1800
#define ALIGNED_ONLY
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813

#define SHIFT 0
#include "softmmu_template.h"

#define SHIFT 1
#include "softmmu_template.h"

#define SHIFT 2
#include "softmmu_template.h"

#define SHIFT 3
#include "softmmu_template.h"

B
bellard 已提交
1814 1815 1816 1817
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
{
    env->CP0_BadVAddr = addr;
    do_restore_state (retaddr);
1818
    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
B
bellard 已提交
1819 1820
}

1821
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831
{
    TranslationBlock *tb;
    CPUState *saved_env;
    unsigned long pc;
    int ret;

    /* XXX: hack to restore env in all cases, even if not called from
       generated code */
    saved_env = env;
    env = cpu_single_env;
1832
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
    if (ret) {
        if (retaddr) {
            /* now we have a real cpu fault */
            pc = (unsigned long)retaddr;
            tb = tb_find_pc(pc);
            if (tb) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
                cpu_restore_state(tb, env, pc, NULL);
            }
        }
1844
        helper_raise_exception_err(env->exception_index, env->error_code);
1845 1846 1847 1848
    }
    env = saved_env;
}

T
ths 已提交
1849
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1850
                          int unused, int size)
T
ths 已提交
1851 1852
{
    if (is_exec)
1853
        helper_raise_exception(EXCP_IBE);
T
ths 已提交
1854
    else
1855
        helper_raise_exception(EXCP_DBE);
T
ths 已提交
1856
}
1857
#endif /* !CONFIG_USER_ONLY */
1858 1859 1860

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

P
pbrook 已提交
1861 1862 1863 1864
#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 已提交
1865 1866 1867 1868
#define FLOAT_QNAN32 0x7fbfffff
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
#define FLOAT_SNAN32 0x7fffffff
#define FLOAT_SNAN64 0x7fffffffffffffffULL
T
ths 已提交
1869

1870 1871 1872 1873 1874 1875 1876 1877 1878
/* convert MIPS rounding mode in FCR31 to IEEE library */
unsigned int ieee_rm[] = {
    float_round_nearest_even,
    float_round_to_zero,
    float_round_up,
    float_round_down
};

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

1881 1882 1883
#define RESTORE_FLUSH_MODE \
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);

1884
target_ulong helper_cfc1 (uint32_t reg)
1885
{
1886
    target_ulong arg1;
1887

1888 1889
    switch (reg) {
    case 0:
1890
        arg1 = (int32_t)env->active_fpu.fcr0;
1891 1892
        break;
    case 25:
1893
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
1894 1895
        break;
    case 26:
1896
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
1897 1898
        break;
    case 28:
1899
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
1900 1901
        break;
    default:
1902
        arg1 = (int32_t)env->active_fpu.fcr31;
1903 1904
        break;
    }
1905

1906
    return arg1;
1907 1908
}

1909
void helper_ctc1 (target_ulong arg1, uint32_t reg)
1910 1911
{
    switch(reg) {
1912
    case 25:
1913
        if (arg1 & 0xffffff00)
1914
            return;
1915 1916
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                     ((arg1 & 0x1) << 23);
1917 1918
        break;
    case 26:
1919
        if (arg1 & 0x007c0000)
1920
            return;
1921
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
1922 1923
        break;
    case 28:
1924
        if (arg1 & 0x007c0000)
1925
            return;
1926 1927
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
                     ((arg1 & 0x4) << 22);
1928 1929
        break;
    case 31:
1930
        if (arg1 & 0x007c0000)
1931
            return;
1932
        env->active_fpu.fcr31 = arg1;
1933 1934 1935 1936 1937 1938
        break;
    default:
        return;
    }
    /* set rounding mode */
    RESTORE_ROUNDING_MODE;
1939 1940
    /* set flush-to-zero mode */
    RESTORE_FLUSH_MODE;
1941 1942
    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))
1943
        helper_raise_exception(EXCP_FPE);
1944 1945
}

T
ths 已提交
1946
static inline char ieee_ex_to_mips(char xcpt)
1947 1948 1949 1950 1951 1952 1953 1954
{
    return (xcpt & float_flag_inexact) >> 5 |
           (xcpt & float_flag_underflow) >> 3 |
           (xcpt & float_flag_overflow) >> 1 |
           (xcpt & float_flag_divbyzero) << 1 |
           (xcpt & float_flag_invalid) << 4;
}

T
ths 已提交
1955
static inline char mips_ex_to_ieee(char xcpt)
1956 1957 1958 1959 1960 1961 1962 1963
{
    return (xcpt & FP_INEXACT) << 5 |
           (xcpt & FP_UNDERFLOW) << 3 |
           (xcpt & FP_OVERFLOW) << 1 |
           (xcpt & FP_DIV0) >> 1 |
           (xcpt & FP_INVALID) >> 4;
}

T
ths 已提交
1964
static inline void update_fcr31(void)
1965
{
1966
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
1967

1968 1969
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
1970
        helper_raise_exception(EXCP_FPE);
1971
    else
1972
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
1973 1974
}

1975 1976 1977 1978 1979 1980
/* 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  */
1981
uint64_t helper_float_sqrt_d(uint64_t fdt0)
1982
{
1983
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
1984 1985
}

1986
uint32_t helper_float_sqrt_s(uint32_t fst0)
1987
{
1988
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
1989
}
1990

1991
uint64_t helper_float_cvtd_s(uint32_t fst0)
1992
{
1993 1994
    uint64_t fdt2;

1995 1996
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
1997
    update_fcr31();
1998
    return fdt2;
1999
}
2000

2001
uint64_t helper_float_cvtd_w(uint32_t wt0)
2002
{
2003 2004
    uint64_t fdt2;

2005 2006
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2007
    update_fcr31();
2008
    return fdt2;
2009
}
2010

2011
uint64_t helper_float_cvtd_l(uint64_t dt0)
2012
{
2013 2014
    uint64_t fdt2;

2015 2016
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2017
    update_fcr31();
2018
    return fdt2;
2019
}
2020

2021
uint64_t helper_float_cvtl_d(uint64_t fdt0)
2022
{
2023 2024
    uint64_t dt2;

2025 2026
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2027
    update_fcr31();
2028
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2029 2030
        dt2 = FLOAT_SNAN64;
    return dt2;
2031
}
2032

2033
uint64_t helper_float_cvtl_s(uint32_t fst0)
2034
{
2035 2036
    uint64_t dt2;

2037 2038
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2039
    update_fcr31();
2040
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2041 2042
        dt2 = FLOAT_SNAN64;
    return dt2;
2043 2044
}

2045
uint64_t helper_float_cvtps_pw(uint64_t dt0)
2046
{
2047 2048 2049
    uint32_t fst2;
    uint32_t fsth2;

2050 2051 2052
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2053
    update_fcr31();
2054
    return ((uint64_t)fsth2 << 32) | fst2;
2055
}
2056

2057
uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2058
{
2059 2060 2061
    uint32_t wt2;
    uint32_t wth2;

2062 2063 2064
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2065
    update_fcr31();
2066
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2067 2068 2069 2070
        wt2 = FLOAT_SNAN32;
        wth2 = FLOAT_SNAN32;
    }
    return ((uint64_t)wth2 << 32) | wt2;
2071
}
2072

2073
uint32_t helper_float_cvts_d(uint64_t fdt0)
2074
{
2075 2076
    uint32_t fst2;

2077 2078
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2079
    update_fcr31();
2080
    return fst2;
2081
}
2082

2083
uint32_t helper_float_cvts_w(uint32_t wt0)
2084
{
2085 2086
    uint32_t fst2;

2087 2088
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2089
    update_fcr31();
2090
    return fst2;
2091
}
2092

2093
uint32_t helper_float_cvts_l(uint64_t dt0)
2094
{
2095 2096
    uint32_t fst2;

2097 2098
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2099
    update_fcr31();
2100
    return fst2;
2101
}
2102

2103
uint32_t helper_float_cvts_pl(uint32_t wt0)
2104
{
2105 2106
    uint32_t wt2;

2107
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2108
    wt2 = wt0;
2109
    update_fcr31();
2110
    return wt2;
2111
}
2112

2113
uint32_t helper_float_cvts_pu(uint32_t wth0)
2114
{
2115 2116
    uint32_t wt2;

2117
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2118
    wt2 = wth0;
2119
    update_fcr31();
2120
    return wt2;
2121
}
2122

2123
uint32_t helper_float_cvtw_s(uint32_t fst0)
2124
{
2125 2126
    uint32_t wt2;

2127 2128
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2129
    update_fcr31();
2130
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2131 2132
        wt2 = FLOAT_SNAN32;
    return wt2;
2133
}
2134

2135
uint32_t helper_float_cvtw_d(uint64_t fdt0)
2136
{
2137 2138
    uint32_t wt2;

2139 2140
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2141
    update_fcr31();
2142
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2143 2144
        wt2 = FLOAT_SNAN32;
    return wt2;
2145 2146
}

2147
uint64_t helper_float_roundl_d(uint64_t fdt0)
2148
{
2149 2150
    uint64_t dt2;

2151 2152
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2153 2154
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2155
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2156 2157
        dt2 = FLOAT_SNAN64;
    return dt2;
2158
}
2159

2160
uint64_t helper_float_roundl_s(uint32_t fst0)
2161
{
2162 2163
    uint64_t dt2;

2164 2165
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2166 2167
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2168
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2169 2170
        dt2 = FLOAT_SNAN64;
    return dt2;
2171
}
2172

2173
uint32_t helper_float_roundw_d(uint64_t fdt0)
2174
{
2175 2176
    uint32_t wt2;

2177 2178
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2179 2180
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2181
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2182 2183
        wt2 = FLOAT_SNAN32;
    return wt2;
2184
}
2185

2186
uint32_t helper_float_roundw_s(uint32_t fst0)
2187
{
2188 2189
    uint32_t wt2;

2190 2191
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2192 2193
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2194
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2195 2196
        wt2 = FLOAT_SNAN32;
    return wt2;
2197 2198
}

2199
uint64_t helper_float_truncl_d(uint64_t fdt0)
2200
{
2201 2202
    uint64_t dt2;

2203
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2204
    update_fcr31();
2205
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2206 2207
        dt2 = FLOAT_SNAN64;
    return dt2;
2208
}
2209

2210
uint64_t helper_float_truncl_s(uint32_t fst0)
2211
{
2212 2213
    uint64_t dt2;

2214
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2215
    update_fcr31();
2216
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2217 2218
        dt2 = FLOAT_SNAN64;
    return dt2;
2219
}
2220

2221
uint32_t helper_float_truncw_d(uint64_t fdt0)
2222
{
2223 2224
    uint32_t wt2;

2225
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2226
    update_fcr31();
2227
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2228 2229
        wt2 = FLOAT_SNAN32;
    return wt2;
2230
}
2231

2232
uint32_t helper_float_truncw_s(uint32_t fst0)
2233
{
2234 2235
    uint32_t wt2;

2236
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2237
    update_fcr31();
2238
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2239 2240
        wt2 = FLOAT_SNAN32;
    return wt2;
2241 2242
}

2243
uint64_t helper_float_ceill_d(uint64_t fdt0)
2244
{
2245 2246
    uint64_t dt2;

2247 2248
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2249 2250
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2251
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2252 2253
        dt2 = FLOAT_SNAN64;
    return dt2;
2254
}
2255

2256
uint64_t helper_float_ceill_s(uint32_t fst0)
2257
{
2258 2259
    uint64_t dt2;

2260 2261
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2262 2263
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2264
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2265 2266
        dt2 = FLOAT_SNAN64;
    return dt2;
2267
}
2268

2269
uint32_t helper_float_ceilw_d(uint64_t fdt0)
2270
{
2271 2272
    uint32_t wt2;

2273 2274
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2275 2276
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2277
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2278 2279
        wt2 = FLOAT_SNAN32;
    return wt2;
2280
}
2281

2282
uint32_t helper_float_ceilw_s(uint32_t fst0)
2283
{
2284 2285
    uint32_t wt2;

2286 2287
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2288 2289
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2290
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2291 2292
        wt2 = FLOAT_SNAN32;
    return wt2;
2293 2294
}

2295
uint64_t helper_float_floorl_d(uint64_t fdt0)
2296
{
2297 2298
    uint64_t dt2;

2299 2300
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2301 2302
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2303
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2304 2305
        dt2 = FLOAT_SNAN64;
    return dt2;
2306
}
2307

2308
uint64_t helper_float_floorl_s(uint32_t fst0)
2309
{
2310 2311
    uint64_t dt2;

2312 2313
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2314 2315
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2316
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2317 2318
        dt2 = FLOAT_SNAN64;
    return dt2;
2319
}
2320

2321
uint32_t helper_float_floorw_d(uint64_t fdt0)
2322
{
2323 2324
    uint32_t wt2;

2325 2326
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2327 2328
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2329
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2330 2331
        wt2 = FLOAT_SNAN32;
    return wt2;
2332
}
2333

2334
uint32_t helper_float_floorw_s(uint32_t fst0)
2335
{
2336 2337
    uint32_t wt2;

2338 2339
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2340 2341
    RESTORE_ROUNDING_MODE;
    update_fcr31();
2342
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2343 2344
        wt2 = FLOAT_SNAN32;
    return wt2;
2345 2346
}

2347
/* unary operations, not modifying fp status  */
2348
#define FLOAT_UNOP(name)                                       \
2349
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2350 2351 2352
{                                                              \
    return float64_ ## name(fdt0);                             \
}                                                              \
2353
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2354 2355 2356
{                                                              \
    return float32_ ## name(fst0);                             \
}                                                              \
2357
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2358 2359 2360 2361 2362 2363 2364
{                                                              \
    uint32_t wt0;                                              \
    uint32_t wth0;                                             \
                                                               \
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
    wth0 = float32_ ## name(fdt0 >> 32);                       \
    return ((uint64_t)wth0 << 32) | wt0;                       \
2365 2366 2367 2368 2369
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP

T
ths 已提交
2370
/* MIPS specific unary operations */
2371
uint64_t helper_float_recip_d(uint64_t fdt0)
T
ths 已提交
2372
{
2373 2374
    uint64_t fdt2;

2375 2376
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2377
    update_fcr31();
2378
    return fdt2;
T
ths 已提交
2379
}
2380

2381
uint32_t helper_float_recip_s(uint32_t fst0)
T
ths 已提交
2382
{
2383 2384
    uint32_t fst2;

2385 2386
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2387
    update_fcr31();
2388
    return fst2;
T
ths 已提交
2389 2390
}

2391
uint64_t helper_float_rsqrt_d(uint64_t fdt0)
T
ths 已提交
2392
{
2393 2394
    uint64_t fdt2;

2395 2396 2397
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
T
ths 已提交
2398
    update_fcr31();
2399
    return fdt2;
T
ths 已提交
2400
}
2401

2402
uint32_t helper_float_rsqrt_s(uint32_t fst0)
T
ths 已提交
2403
{
2404 2405
    uint32_t fst2;

2406 2407 2408
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
T
ths 已提交
2409
    update_fcr31();
2410
    return fst2;
T
ths 已提交
2411 2412
}

2413
uint64_t helper_float_recip1_d(uint64_t fdt0)
T
ths 已提交
2414
{
2415 2416
    uint64_t fdt2;

2417 2418
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
T
ths 已提交
2419
    update_fcr31();
2420
    return fdt2;
T
ths 已提交
2421
}
2422

2423
uint32_t helper_float_recip1_s(uint32_t fst0)
T
ths 已提交
2424
{
2425 2426
    uint32_t fst2;

2427 2428
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
T
ths 已提交
2429
    update_fcr31();
2430
    return fst2;
T
ths 已提交
2431
}
2432

2433
uint64_t helper_float_recip1_ps(uint64_t fdt0)
T
ths 已提交
2434
{
2435 2436 2437
    uint32_t fst2;
    uint32_t fsth2;

2438 2439 2440
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
T
ths 已提交
2441
    update_fcr31();
2442
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2443 2444
}

2445
uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
T
ths 已提交
2446
{
2447 2448
    uint64_t fdt2;

2449 2450 2451
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
T
ths 已提交
2452
    update_fcr31();
2453
    return fdt2;
T
ths 已提交
2454
}
2455

2456
uint32_t helper_float_rsqrt1_s(uint32_t fst0)
T
ths 已提交
2457
{
2458 2459
    uint32_t fst2;

2460 2461 2462
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
T
ths 已提交
2463
    update_fcr31();
2464
    return fst2;
T
ths 已提交
2465
}
2466

2467
uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
T
ths 已提交
2468
{
2469 2470 2471
    uint32_t fst2;
    uint32_t fsth2;

2472 2473 2474 2475 2476
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
T
ths 已提交
2477
    update_fcr31();
2478
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2479 2480
}

2481
#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2482

2483
/* binary operations */
2484
#define FLOAT_BINOP(name)                                          \
2485
uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2486 2487 2488
{                                                                  \
    uint64_t dt2;                                                  \
                                                                   \
2489 2490
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2491
    update_fcr31();                                                \
2492
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2493 2494 2495 2496
        dt2 = FLOAT_QNAN64;                                        \
    return dt2;                                                    \
}                                                                  \
                                                                   \
2497
uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
2498 2499 2500
{                                                                  \
    uint32_t wt2;                                                  \
                                                                   \
2501 2502
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2503
    update_fcr31();                                                \
2504
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2505 2506 2507 2508
        wt2 = FLOAT_QNAN32;                                        \
    return wt2;                                                    \
}                                                                  \
                                                                   \
2509
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
2510 2511 2512 2513 2514 2515 2516 2517
{                                                                  \
    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;                                                 \
                                                                   \
2518 2519 2520
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2521
    update_fcr31();                                                \
2522
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
2523 2524 2525 2526
        wt2 = FLOAT_QNAN32;                                        \
        wth2 = FLOAT_QNAN32;                                       \
    }                                                              \
    return ((uint64_t)wth2 << 32) | wt2;                           \
2527
}
2528

2529 2530 2531 2532 2533 2534
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
FLOAT_BINOP(div)
#undef FLOAT_BINOP

2535
/* ternary operations */
2536
#define FLOAT_TERNOP(name1, name2)                                        \
2537
uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
2538 2539
                                           uint64_t fdt2)                 \
{                                                                         \
2540 2541
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2542 2543
}                                                                         \
                                                                          \
2544
uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
2545 2546
                                           uint32_t fst2)                 \
{                                                                         \
2547 2548
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2549 2550
}                                                                         \
                                                                          \
2551
uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
2552 2553 2554 2555 2556 2557 2558 2559 2560
                                            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;                                          \
                                                                          \
2561 2562 2563 2564
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2565
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2566
}
2567

2568 2569 2570 2571 2572
FLOAT_TERNOP(mul, add)
FLOAT_TERNOP(mul, sub)
#undef FLOAT_TERNOP

/* negated ternary operations */
2573
#define FLOAT_NTERNOP(name1, name2)                                       \
2574
uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
2575 2576
                                           uint64_t fdt2)                 \
{                                                                         \
2577 2578
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2579 2580 2581
    return float64_chs(fdt2);                                             \
}                                                                         \
                                                                          \
2582
uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
2583 2584
                                           uint32_t fst2)                 \
{                                                                         \
2585 2586
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2587 2588 2589
    return float32_chs(fst2);                                             \
}                                                                         \
                                                                          \
2590
uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
2591 2592 2593 2594 2595 2596 2597 2598 2599
                                           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;                                          \
                                                                          \
2600 2601 2602 2603
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2604 2605 2606
    fst2 = float32_chs(fst2);                                             \
    fsth2 = float32_chs(fsth2);                                           \
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2607
}
2608

2609 2610 2611 2612
FLOAT_NTERNOP(mul, add)
FLOAT_NTERNOP(mul, sub)
#undef FLOAT_NTERNOP

T
ths 已提交
2613
/* MIPS specific binary operations */
2614
uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2615
{
2616 2617 2618
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
T
ths 已提交
2619
    update_fcr31();
2620
    return fdt2;
T
ths 已提交
2621
}
2622

2623
uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
2624
{
2625 2626 2627
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
T
ths 已提交
2628
    update_fcr31();
2629
    return fst2;
T
ths 已提交
2630
}
2631

2632
uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2633
{
2634 2635 2636 2637 2638
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

2639 2640 2641 2642 2643
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
T
ths 已提交
2644
    update_fcr31();
2645
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2646 2647
}

2648
uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2649
{
2650 2651 2652 2653
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
T
ths 已提交
2654
    update_fcr31();
2655
    return fdt2;
T
ths 已提交
2656
}
2657

2658
uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
T
ths 已提交
2659
{
2660 2661 2662 2663
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
T
ths 已提交
2664
    update_fcr31();
2665
    return fst2;
T
ths 已提交
2666
}
2667

2668
uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
T
ths 已提交
2669
{
2670 2671 2672 2673 2674
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
    uint32_t fsth0 = fdt0 >> 32;
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
    uint32_t fsth2 = fdt2 >> 32;

2675 2676 2677 2678 2679 2680 2681
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
T
ths 已提交
2682
    update_fcr31();
2683
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2684 2685
}

2686
uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
2687
{
2688 2689 2690 2691 2692 2693 2694
    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;

2695 2696 2697
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
2698
    update_fcr31();
2699
    return ((uint64_t)fsth2 << 32) | fst2;
2700 2701
}

2702
uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
T
ths 已提交
2703
{
2704 2705 2706 2707 2708 2709 2710
    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;

2711 2712 2713
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
T
ths 已提交
2714
    update_fcr31();
2715
    return ((uint64_t)fsth2 << 32) | fst2;
T
ths 已提交
2716 2717
}

T
ths 已提交
2718
/* compare operations */
2719
#define FOP_COND_D(op, cond)                                   \
2720
void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2721 2722 2723 2724
{                                                              \
    int c = cond;                                              \
    update_fcr31();                                            \
    if (c)                                                     \
2725
        SET_FP_COND(cc, env->active_fpu);                      \
2726
    else                                                       \
2727
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2728
}                                                              \
2729
void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2730 2731 2732 2733 2734 2735 2736
{                                                              \
    int c;                                                     \
    fdt0 = float64_abs(fdt0);                                  \
    fdt1 = float64_abs(fdt1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
2737
        SET_FP_COND(cc, env->active_fpu);                      \
2738
    else                                                       \
2739
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2740 2741
}

A
aurel32 已提交
2742
static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757
{
    if (float64_is_signaling_nan(a) ||
        float64_is_signaling_nan(b) ||
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
        float_raise(float_flag_invalid, status);
        return 1;
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
        return 1;
    } else {
        return 0;
    }
}

/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2758 2759 2760 2761 2762 2763 2764 2765
FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2766 2767
/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2768 2769 2770 2771 2772 2773 2774 2775
FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2776 2777

#define FOP_COND_S(op, cond)                                   \
2778
void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
2779 2780 2781 2782
{                                                              \
    int c = cond;                                              \
    update_fcr31();                                            \
    if (c)                                                     \
2783
        SET_FP_COND(cc, env->active_fpu);                      \
2784
    else                                                       \
2785
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2786
}                                                              \
2787
void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
2788 2789 2790 2791 2792 2793 2794
{                                                              \
    int c;                                                     \
    fst0 = float32_abs(fst0);                                  \
    fst1 = float32_abs(fst1);                                  \
    c = cond;                                                  \
    update_fcr31();                                            \
    if (c)                                                     \
2795
        SET_FP_COND(cc, env->active_fpu);                      \
2796
    else                                                       \
2797
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2798 2799
}

A
aurel32 已提交
2800
static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815
{
    if (float32_is_signaling_nan(a) ||
        float32_is_signaling_nan(b) ||
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
        float_raise(float_flag_invalid, status);
        return 1;
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
        return 1;
    } else {
        return 0;
    }
}

/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2816 2817 2818 2819 2820 2821 2822 2823
FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2824 2825
/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2826 2827 2828 2829 2830 2831 2832 2833
FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2834 2835

#define FOP_COND_PS(op, condl, condh)                           \
2836
void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846
{                                                               \
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
    int cl = condl;                                             \
    int ch = condh;                                             \
                                                                \
    update_fcr31();                                             \
    if (cl)                                                     \
2847
        SET_FP_COND(cc, env->active_fpu);                       \
2848
    else                                                        \
2849
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2850
    if (ch)                                                     \
2851
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2852
    else                                                        \
2853
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2854
}                                                               \
2855
void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2856 2857 2858 2859 2860 2861 2862 2863 2864 2865
{                                                               \
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
    int cl = condl;                                             \
    int ch = condh;                                             \
                                                                \
    update_fcr31();                                             \
    if (cl)                                                     \
2866
        SET_FP_COND(cc, env->active_fpu);                       \
2867
    else                                                        \
2868
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2869
    if (ch)                                                     \
2870
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2871
    else                                                        \
2872
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2873 2874 2875 2876
}

/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2893 2894
/* NOTE: the comma operator will make "cond" to eval to false,
 * but float*_is_unordered() is still called. */
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910
FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))