1 /* 2 * MIPS emulation helpers for qemu. 3 * 4 * Copyright (c) 2004-2005 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * 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/>. 18 */ 19 #include <stdlib.h> 20 #include "exec.h" 21 22 #include "host-utils.h" 23 24 #include "helper.h" 25 /*****************************************************************************/ 26 /* Exceptions processing helpers */ 27 28 void helper_raise_exception_err (uint32_t exception, int error_code) 29 { 30 #if 1 31 if (exception < 0x100) 32 qemu_log("%s: %d %d\n", __func__, exception, error_code); 33 #endif 34 env->exception_index = exception; 35 env->error_code = error_code; 36 cpu_loop_exit(); 37 } 38 39 void helper_raise_exception (uint32_t exception) 40 { 41 helper_raise_exception_err(exception, 0); 42 } 43 44 void helper_interrupt_restart (void) 45 { 46 if (!(env->CP0_Status & (1 << CP0St_EXL)) && 47 !(env->CP0_Status & (1 << CP0St_ERL)) && 48 !(env->hflags & MIPS_HFLAG_DM) && 49 (env->CP0_Status & (1 << CP0St_IE)) && 50 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { 51 env->CP0_Cause &= ~(0x1f << CP0Ca_EC); 52 helper_raise_exception(EXCP_EXT_INTERRUPT); 53 } 54 } 55 56 #if !defined(CONFIG_USER_ONLY) 57 static void do_restore_state (void *pc_ptr) 58 { 59 TranslationBlock *tb; 60 unsigned long pc = (unsigned long) pc_ptr; 61 62 tb = tb_find_pc (pc); 63 if (tb) { 64 cpu_restore_state (tb, env, pc); 65 } 66 } 67 #endif 68 69 #if defined(CONFIG_USER_ONLY) 70 #define HELPER_LD(name, insn, type) \ 71 static inline type do_##name(target_ulong addr, int mem_idx) \ 72 { \ 73 return (type) insn##_raw(addr); \ 74 } 75 #else 76 #define HELPER_LD(name, insn, type) \ 77 static inline type do_##name(target_ulong addr, int mem_idx) \ 78 { \ 79 switch (mem_idx) \ 80 { \ 81 case 0: return (type) insn##_kernel(addr); break; \ 82 case 1: return (type) insn##_super(addr); break; \ 83 default: \ 84 case 2: return (type) insn##_user(addr); break; \ 85 } \ 86 } 87 #endif 88 HELPER_LD(lbu, ldub, uint8_t) 89 HELPER_LD(lw, ldl, int32_t) 90 #ifdef TARGET_MIPS64 91 HELPER_LD(ld, ldq, int64_t) 92 #endif 93 #undef HELPER_LD 94 95 #if defined(CONFIG_USER_ONLY) 96 #define HELPER_ST(name, insn, type) \ 97 static inline void do_##name(target_ulong addr, type val, int mem_idx) \ 98 { \ 99 insn##_raw(addr, val); \ 100 } 101 #else 102 #define HELPER_ST(name, insn, type) \ 103 static inline void do_##name(target_ulong addr, type val, int mem_idx) \ 104 { \ 105 switch (mem_idx) \ 106 { \ 107 case 0: insn##_kernel(addr, val); break; \ 108 case 1: insn##_super(addr, val); break; \ 109 default: \ 110 case 2: insn##_user(addr, val); break; \ 111 } \ 112 } 113 #endif 114 HELPER_ST(sb, stb, uint8_t) 115 HELPER_ST(sw, stl, uint32_t) 116 #ifdef TARGET_MIPS64 117 HELPER_ST(sd, stq, uint64_t) 118 #endif 119 #undef HELPER_ST 120 121 target_ulong helper_clo (target_ulong arg1) 122 { 123 return clo32(arg1); 124 } 125 126 target_ulong helper_clz (target_ulong arg1) 127 { 128 return clz32(arg1); 129 } 130 131 #if defined(TARGET_MIPS64) 132 target_ulong helper_dclo (target_ulong arg1) 133 { 134 return clo64(arg1); 135 } 136 137 target_ulong helper_dclz (target_ulong arg1) 138 { 139 return clz64(arg1); 140 } 141 #endif /* TARGET_MIPS64 */ 142 143 /* 64 bits arithmetic for 32 bits hosts */ 144 static inline uint64_t get_HILO (void) 145 { 146 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; 147 } 148 149 static inline void set_HILO (uint64_t HILO) 150 { 151 env->active_tc.LO[0] = (int32_t)HILO; 152 env->active_tc.HI[0] = (int32_t)(HILO >> 32); 153 } 154 155 static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO) 156 { 157 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); 158 arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32); 159 } 160 161 static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO) 162 { 163 arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); 164 env->active_tc.HI[0] = (int32_t)(HILO >> 32); 165 } 166 167 /* Multiplication variants of the vr54xx. */ 168 target_ulong helper_muls (target_ulong arg1, target_ulong arg2) 169 { 170 set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 171 172 return arg1; 173 } 174 175 target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2) 176 { 177 set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 178 179 return arg1; 180 } 181 182 target_ulong helper_macc (target_ulong arg1, target_ulong arg2) 183 { 184 set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 185 186 return arg1; 187 } 188 189 target_ulong helper_macchi (target_ulong arg1, target_ulong arg2) 190 { 191 set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 192 193 return arg1; 194 } 195 196 target_ulong helper_maccu (target_ulong arg1, target_ulong arg2) 197 { 198 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 199 200 return arg1; 201 } 202 203 target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2) 204 { 205 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 206 207 return arg1; 208 } 209 210 target_ulong helper_msac (target_ulong arg1, target_ulong arg2) 211 { 212 set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 213 214 return arg1; 215 } 216 217 target_ulong helper_msachi (target_ulong arg1, target_ulong arg2) 218 { 219 set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 220 221 return arg1; 222 } 223 224 target_ulong helper_msacu (target_ulong arg1, target_ulong arg2) 225 { 226 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 227 228 return arg1; 229 } 230 231 target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2) 232 { 233 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 234 235 return arg1; 236 } 237 238 target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2) 239 { 240 set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); 241 242 return arg1; 243 } 244 245 target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2) 246 { 247 set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); 248 249 return arg1; 250 } 251 252 target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2) 253 { 254 set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); 255 256 return arg1; 257 } 258 259 target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2) 260 { 261 set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2)); 262 263 return arg1; 264 } 265 266 #ifdef TARGET_MIPS64 267 void helper_dmult (target_ulong arg1, target_ulong arg2) 268 { 269 muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); 270 } 271 272 void helper_dmultu (target_ulong arg1, target_ulong arg2) 273 { 274 mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); 275 } 276 #endif 277 278 #ifndef CONFIG_USER_ONLY 279 280 static inline target_phys_addr_t do_translate_address(target_ulong address, int rw) 281 { 282 target_phys_addr_t lladdr; 283 284 lladdr = cpu_mips_translate_address(env, address, rw); 285 286 if (lladdr == -1LL) { 287 cpu_loop_exit(); 288 } else { 289 return lladdr; 290 } 291 } 292 293 #define HELPER_LD_ATOMIC(name, insn) \ 294 target_ulong helper_##name(target_ulong arg, int mem_idx) \ 295 { \ 296 env->lladdr = do_translate_address(arg, 0); \ 297 env->llval = do_##insn(arg, mem_idx); \ 298 return env->llval; \ 299 } 300 HELPER_LD_ATOMIC(ll, lw) 301 #ifdef TARGET_MIPS64 302 HELPER_LD_ATOMIC(lld, ld) 303 #endif 304 #undef HELPER_LD_ATOMIC 305 306 #define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \ 307 target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \ 308 { \ 309 target_long tmp; \ 310 \ 311 if (arg2 & almask) { \ 312 env->CP0_BadVAddr = arg2; \ 313 helper_raise_exception(EXCP_AdES); \ 314 } \ 315 if (do_translate_address(arg2, 1) == env->lladdr) { \ 316 tmp = do_##ld_insn(arg2, mem_idx); \ 317 if (tmp == env->llval) { \ 318 do_##st_insn(arg2, arg1, mem_idx); \ 319 return 1; \ 320 } \ 321 } \ 322 return 0; \ 323 } 324 HELPER_ST_ATOMIC(sc, lw, sw, 0x3) 325 #ifdef TARGET_MIPS64 326 HELPER_ST_ATOMIC(scd, ld, sd, 0x7) 327 #endif 328 #undef HELPER_ST_ATOMIC 329 #endif 330 331 #ifdef TARGET_WORDS_BIGENDIAN 332 #define GET_LMASK(v) ((v) & 3) 333 #define GET_OFFSET(addr, offset) (addr + (offset)) 334 #else 335 #define GET_LMASK(v) (((v) & 3) ^ 3) 336 #define GET_OFFSET(addr, offset) (addr - (offset)) 337 #endif 338 339 target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx) 340 { 341 target_ulong tmp; 342 343 tmp = do_lbu(arg2, mem_idx); 344 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24); 345 346 if (GET_LMASK(arg2) <= 2) { 347 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx); 348 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16); 349 } 350 351 if (GET_LMASK(arg2) <= 1) { 352 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx); 353 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8); 354 } 355 356 if (GET_LMASK(arg2) == 0) { 357 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx); 358 arg1 = (arg1 & 0xFFFFFF00) | tmp; 359 } 360 return (int32_t)arg1; 361 } 362 363 target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx) 364 { 365 target_ulong tmp; 366 367 tmp = do_lbu(arg2, mem_idx); 368 arg1 = (arg1 & 0xFFFFFF00) | tmp; 369 370 if (GET_LMASK(arg2) >= 1) { 371 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx); 372 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8); 373 } 374 375 if (GET_LMASK(arg2) >= 2) { 376 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx); 377 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16); 378 } 379 380 if (GET_LMASK(arg2) == 3) { 381 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx); 382 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24); 383 } 384 return (int32_t)arg1; 385 } 386 387 void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx) 388 { 389 do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx); 390 391 if (GET_LMASK(arg2) <= 2) 392 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx); 393 394 if (GET_LMASK(arg2) <= 1) 395 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx); 396 397 if (GET_LMASK(arg2) == 0) 398 do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx); 399 } 400 401 void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx) 402 { 403 do_sb(arg2, (uint8_t)arg1, mem_idx); 404 405 if (GET_LMASK(arg2) >= 1) 406 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); 407 408 if (GET_LMASK(arg2) >= 2) 409 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); 410 411 if (GET_LMASK(arg2) == 3) 412 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); 413 } 414 415 #if defined(TARGET_MIPS64) 416 /* "half" load and stores. We must do the memory access inline, 417 or fault handling won't work. */ 418 419 #ifdef TARGET_WORDS_BIGENDIAN 420 #define GET_LMASK64(v) ((v) & 7) 421 #else 422 #define GET_LMASK64(v) (((v) & 7) ^ 7) 423 #endif 424 425 target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx) 426 { 427 uint64_t tmp; 428 429 tmp = do_lbu(arg2, mem_idx); 430 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); 431 432 if (GET_LMASK64(arg2) <= 6) { 433 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx); 434 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); 435 } 436 437 if (GET_LMASK64(arg2) <= 5) { 438 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx); 439 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); 440 } 441 442 if (GET_LMASK64(arg2) <= 4) { 443 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx); 444 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); 445 } 446 447 if (GET_LMASK64(arg2) <= 3) { 448 tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx); 449 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); 450 } 451 452 if (GET_LMASK64(arg2) <= 2) { 453 tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx); 454 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); 455 } 456 457 if (GET_LMASK64(arg2) <= 1) { 458 tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx); 459 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); 460 } 461 462 if (GET_LMASK64(arg2) == 0) { 463 tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx); 464 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; 465 } 466 467 return arg1; 468 } 469 470 target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx) 471 { 472 uint64_t tmp; 473 474 tmp = do_lbu(arg2, mem_idx); 475 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; 476 477 if (GET_LMASK64(arg2) >= 1) { 478 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx); 479 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); 480 } 481 482 if (GET_LMASK64(arg2) >= 2) { 483 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx); 484 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); 485 } 486 487 if (GET_LMASK64(arg2) >= 3) { 488 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx); 489 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); 490 } 491 492 if (GET_LMASK64(arg2) >= 4) { 493 tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx); 494 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); 495 } 496 497 if (GET_LMASK64(arg2) >= 5) { 498 tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx); 499 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); 500 } 501 502 if (GET_LMASK64(arg2) >= 6) { 503 tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx); 504 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); 505 } 506 507 if (GET_LMASK64(arg2) == 7) { 508 tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx); 509 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); 510 } 511 512 return arg1; 513 } 514 515 void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx) 516 { 517 do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx); 518 519 if (GET_LMASK64(arg2) <= 6) 520 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx); 521 522 if (GET_LMASK64(arg2) <= 5) 523 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx); 524 525 if (GET_LMASK64(arg2) <= 4) 526 do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx); 527 528 if (GET_LMASK64(arg2) <= 3) 529 do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx); 530 531 if (GET_LMASK64(arg2) <= 2) 532 do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx); 533 534 if (GET_LMASK64(arg2) <= 1) 535 do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx); 536 537 if (GET_LMASK64(arg2) <= 0) 538 do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx); 539 } 540 541 void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx) 542 { 543 do_sb(arg2, (uint8_t)arg1, mem_idx); 544 545 if (GET_LMASK64(arg2) >= 1) 546 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); 547 548 if (GET_LMASK64(arg2) >= 2) 549 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); 550 551 if (GET_LMASK64(arg2) >= 3) 552 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); 553 554 if (GET_LMASK64(arg2) >= 4) 555 do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx); 556 557 if (GET_LMASK64(arg2) >= 5) 558 do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx); 559 560 if (GET_LMASK64(arg2) >= 6) 561 do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx); 562 563 if (GET_LMASK64(arg2) == 7) 564 do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx); 565 } 566 #endif /* TARGET_MIPS64 */ 567 568 #ifndef CONFIG_USER_ONLY 569 /* CP0 helpers */ 570 target_ulong helper_mfc0_mvpcontrol (void) 571 { 572 return env->mvp->CP0_MVPControl; 573 } 574 575 target_ulong helper_mfc0_mvpconf0 (void) 576 { 577 return env->mvp->CP0_MVPConf0; 578 } 579 580 target_ulong helper_mfc0_mvpconf1 (void) 581 { 582 return env->mvp->CP0_MVPConf1; 583 } 584 585 target_ulong helper_mfc0_random (void) 586 { 587 return (int32_t)cpu_mips_get_random(env); 588 } 589 590 target_ulong helper_mfc0_tcstatus (void) 591 { 592 return env->active_tc.CP0_TCStatus; 593 } 594 595 target_ulong helper_mftc0_tcstatus(void) 596 { 597 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 598 599 if (other_tc == env->current_tc) 600 return env->active_tc.CP0_TCStatus; 601 else 602 return env->tcs[other_tc].CP0_TCStatus; 603 } 604 605 target_ulong helper_mfc0_tcbind (void) 606 { 607 return env->active_tc.CP0_TCBind; 608 } 609 610 target_ulong helper_mftc0_tcbind(void) 611 { 612 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 613 614 if (other_tc == env->current_tc) 615 return env->active_tc.CP0_TCBind; 616 else 617 return env->tcs[other_tc].CP0_TCBind; 618 } 619 620 target_ulong helper_mfc0_tcrestart (void) 621 { 622 return env->active_tc.PC; 623 } 624 625 target_ulong helper_mftc0_tcrestart(void) 626 { 627 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 628 629 if (other_tc == env->current_tc) 630 return env->active_tc.PC; 631 else 632 return env->tcs[other_tc].PC; 633 } 634 635 target_ulong helper_mfc0_tchalt (void) 636 { 637 return env->active_tc.CP0_TCHalt; 638 } 639 640 target_ulong helper_mftc0_tchalt(void) 641 { 642 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 643 644 if (other_tc == env->current_tc) 645 return env->active_tc.CP0_TCHalt; 646 else 647 return env->tcs[other_tc].CP0_TCHalt; 648 } 649 650 target_ulong helper_mfc0_tccontext (void) 651 { 652 return env->active_tc.CP0_TCContext; 653 } 654 655 target_ulong helper_mftc0_tccontext(void) 656 { 657 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 658 659 if (other_tc == env->current_tc) 660 return env->active_tc.CP0_TCContext; 661 else 662 return env->tcs[other_tc].CP0_TCContext; 663 } 664 665 target_ulong helper_mfc0_tcschedule (void) 666 { 667 return env->active_tc.CP0_TCSchedule; 668 } 669 670 target_ulong helper_mftc0_tcschedule(void) 671 { 672 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 673 674 if (other_tc == env->current_tc) 675 return env->active_tc.CP0_TCSchedule; 676 else 677 return env->tcs[other_tc].CP0_TCSchedule; 678 } 679 680 target_ulong helper_mfc0_tcschefback (void) 681 { 682 return env->active_tc.CP0_TCScheFBack; 683 } 684 685 target_ulong helper_mftc0_tcschefback(void) 686 { 687 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 688 689 if (other_tc == env->current_tc) 690 return env->active_tc.CP0_TCScheFBack; 691 else 692 return env->tcs[other_tc].CP0_TCScheFBack; 693 } 694 695 target_ulong helper_mfc0_count (void) 696 { 697 return (int32_t)cpu_mips_get_count(env); 698 } 699 700 target_ulong helper_mftc0_entryhi(void) 701 { 702 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 703 int32_t tcstatus; 704 705 if (other_tc == env->current_tc) 706 tcstatus = env->active_tc.CP0_TCStatus; 707 else 708 tcstatus = env->tcs[other_tc].CP0_TCStatus; 709 710 return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff); 711 } 712 713 target_ulong helper_mftc0_status(void) 714 { 715 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 716 target_ulong t0; 717 int32_t tcstatus; 718 719 if (other_tc == env->current_tc) 720 tcstatus = env->active_tc.CP0_TCStatus; 721 else 722 tcstatus = env->tcs[other_tc].CP0_TCStatus; 723 724 t0 = env->CP0_Status & ~0xf1000018; 725 t0 |= tcstatus & (0xf << CP0TCSt_TCU0); 726 t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); 727 t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); 728 729 return t0; 730 } 731 732 target_ulong helper_mfc0_lladdr (void) 733 { 734 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift); 735 } 736 737 target_ulong helper_mfc0_watchlo (uint32_t sel) 738 { 739 return (int32_t)env->CP0_WatchLo[sel]; 740 } 741 742 target_ulong helper_mfc0_watchhi (uint32_t sel) 743 { 744 return env->CP0_WatchHi[sel]; 745 } 746 747 target_ulong helper_mfc0_debug (void) 748 { 749 target_ulong t0 = env->CP0_Debug; 750 if (env->hflags & MIPS_HFLAG_DM) 751 t0 |= 1 << CP0DB_DM; 752 753 return t0; 754 } 755 756 target_ulong helper_mftc0_debug(void) 757 { 758 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 759 int32_t tcstatus; 760 761 if (other_tc == env->current_tc) 762 tcstatus = env->active_tc.CP0_Debug_tcstatus; 763 else 764 tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus; 765 766 /* XXX: Might be wrong, check with EJTAG spec. */ 767 return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | 768 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); 769 } 770 771 #if defined(TARGET_MIPS64) 772 target_ulong helper_dmfc0_tcrestart (void) 773 { 774 return env->active_tc.PC; 775 } 776 777 target_ulong helper_dmfc0_tchalt (void) 778 { 779 return env->active_tc.CP0_TCHalt; 780 } 781 782 target_ulong helper_dmfc0_tccontext (void) 783 { 784 return env->active_tc.CP0_TCContext; 785 } 786 787 target_ulong helper_dmfc0_tcschedule (void) 788 { 789 return env->active_tc.CP0_TCSchedule; 790 } 791 792 target_ulong helper_dmfc0_tcschefback (void) 793 { 794 return env->active_tc.CP0_TCScheFBack; 795 } 796 797 target_ulong helper_dmfc0_lladdr (void) 798 { 799 return env->lladdr >> env->CP0_LLAddr_shift; 800 } 801 802 target_ulong helper_dmfc0_watchlo (uint32_t sel) 803 { 804 return env->CP0_WatchLo[sel]; 805 } 806 #endif /* TARGET_MIPS64 */ 807 808 void helper_mtc0_index (target_ulong arg1) 809 { 810 int num = 1; 811 unsigned int tmp = env->tlb->nb_tlb; 812 813 do { 814 tmp >>= 1; 815 num <<= 1; 816 } while (tmp); 817 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1)); 818 } 819 820 void helper_mtc0_mvpcontrol (target_ulong arg1) 821 { 822 uint32_t mask = 0; 823 uint32_t newval; 824 825 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) 826 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | 827 (1 << CP0MVPCo_EVP); 828 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) 829 mask |= (1 << CP0MVPCo_STLB); 830 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask); 831 832 // TODO: Enable/disable shared TLB, enable/disable VPEs. 833 834 env->mvp->CP0_MVPControl = newval; 835 } 836 837 void helper_mtc0_vpecontrol (target_ulong arg1) 838 { 839 uint32_t mask; 840 uint32_t newval; 841 842 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | 843 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); 844 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask); 845 846 /* Yield scheduler intercept not implemented. */ 847 /* Gating storage scheduler intercept not implemented. */ 848 849 // TODO: Enable/disable TCs. 850 851 env->CP0_VPEControl = newval; 852 } 853 854 void helper_mtc0_vpeconf0 (target_ulong arg1) 855 { 856 uint32_t mask = 0; 857 uint32_t newval; 858 859 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { 860 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) 861 mask |= (0xff << CP0VPEC0_XTC); 862 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); 863 } 864 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask); 865 866 // TODO: TC exclusive handling due to ERL/EXL. 867 868 env->CP0_VPEConf0 = newval; 869 } 870 871 void helper_mtc0_vpeconf1 (target_ulong arg1) 872 { 873 uint32_t mask = 0; 874 uint32_t newval; 875 876 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) 877 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | 878 (0xff << CP0VPEC1_NCP1); 879 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask); 880 881 /* UDI not implemented. */ 882 /* CP2 not implemented. */ 883 884 // TODO: Handle FPU (CP1) binding. 885 886 env->CP0_VPEConf1 = newval; 887 } 888 889 void helper_mtc0_yqmask (target_ulong arg1) 890 { 891 /* Yield qualifier inputs not implemented. */ 892 env->CP0_YQMask = 0x00000000; 893 } 894 895 void helper_mtc0_vpeopt (target_ulong arg1) 896 { 897 env->CP0_VPEOpt = arg1 & 0x0000ffff; 898 } 899 900 void helper_mtc0_entrylo0 (target_ulong arg1) 901 { 902 /* Large physaddr (PABITS) not implemented */ 903 /* 1k pages not implemented */ 904 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF; 905 } 906 907 void helper_mtc0_tcstatus (target_ulong arg1) 908 { 909 uint32_t mask = env->CP0_TCStatus_rw_bitmask; 910 uint32_t newval; 911 912 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask); 913 914 // TODO: Sync with CP0_Status. 915 916 env->active_tc.CP0_TCStatus = newval; 917 } 918 919 void helper_mttc0_tcstatus (target_ulong arg1) 920 { 921 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 922 923 // TODO: Sync with CP0_Status. 924 925 if (other_tc == env->current_tc) 926 env->active_tc.CP0_TCStatus = arg1; 927 else 928 env->tcs[other_tc].CP0_TCStatus = arg1; 929 } 930 931 void helper_mtc0_tcbind (target_ulong arg1) 932 { 933 uint32_t mask = (1 << CP0TCBd_TBE); 934 uint32_t newval; 935 936 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) 937 mask |= (1 << CP0TCBd_CurVPE); 938 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask); 939 env->active_tc.CP0_TCBind = newval; 940 } 941 942 void helper_mttc0_tcbind (target_ulong arg1) 943 { 944 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 945 uint32_t mask = (1 << CP0TCBd_TBE); 946 uint32_t newval; 947 948 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) 949 mask |= (1 << CP0TCBd_CurVPE); 950 if (other_tc == env->current_tc) { 951 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask); 952 env->active_tc.CP0_TCBind = newval; 953 } else { 954 newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask); 955 env->tcs[other_tc].CP0_TCBind = newval; 956 } 957 } 958 959 void helper_mtc0_tcrestart (target_ulong arg1) 960 { 961 env->active_tc.PC = arg1; 962 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 963 env->lladdr = 0ULL; 964 /* MIPS16 not implemented. */ 965 } 966 967 void helper_mttc0_tcrestart (target_ulong arg1) 968 { 969 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 970 971 if (other_tc == env->current_tc) { 972 env->active_tc.PC = arg1; 973 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 974 env->lladdr = 0ULL; 975 /* MIPS16 not implemented. */ 976 } else { 977 env->tcs[other_tc].PC = arg1; 978 env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 979 env->lladdr = 0ULL; 980 /* MIPS16 not implemented. */ 981 } 982 } 983 984 void helper_mtc0_tchalt (target_ulong arg1) 985 { 986 env->active_tc.CP0_TCHalt = arg1 & 0x1; 987 988 // TODO: Halt TC / Restart (if allocated+active) TC. 989 } 990 991 void helper_mttc0_tchalt (target_ulong arg1) 992 { 993 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 994 995 // TODO: Halt TC / Restart (if allocated+active) TC. 996 997 if (other_tc == env->current_tc) 998 env->active_tc.CP0_TCHalt = arg1; 999 else 1000 env->tcs[other_tc].CP0_TCHalt = arg1; 1001 } 1002 1003 void helper_mtc0_tccontext (target_ulong arg1) 1004 { 1005 env->active_tc.CP0_TCContext = arg1; 1006 } 1007 1008 void helper_mttc0_tccontext (target_ulong arg1) 1009 { 1010 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1011 1012 if (other_tc == env->current_tc) 1013 env->active_tc.CP0_TCContext = arg1; 1014 else 1015 env->tcs[other_tc].CP0_TCContext = arg1; 1016 } 1017 1018 void helper_mtc0_tcschedule (target_ulong arg1) 1019 { 1020 env->active_tc.CP0_TCSchedule = arg1; 1021 } 1022 1023 void helper_mttc0_tcschedule (target_ulong arg1) 1024 { 1025 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1026 1027 if (other_tc == env->current_tc) 1028 env->active_tc.CP0_TCSchedule = arg1; 1029 else 1030 env->tcs[other_tc].CP0_TCSchedule = arg1; 1031 } 1032 1033 void helper_mtc0_tcschefback (target_ulong arg1) 1034 { 1035 env->active_tc.CP0_TCScheFBack = arg1; 1036 } 1037 1038 void helper_mttc0_tcschefback (target_ulong arg1) 1039 { 1040 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1041 1042 if (other_tc == env->current_tc) 1043 env->active_tc.CP0_TCScheFBack = arg1; 1044 else 1045 env->tcs[other_tc].CP0_TCScheFBack = arg1; 1046 } 1047 1048 void helper_mtc0_entrylo1 (target_ulong arg1) 1049 { 1050 /* Large physaddr (PABITS) not implemented */ 1051 /* 1k pages not implemented */ 1052 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF; 1053 } 1054 1055 void helper_mtc0_context (target_ulong arg1) 1056 { 1057 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF); 1058 } 1059 1060 void helper_mtc0_pagemask (target_ulong arg1) 1061 { 1062 /* 1k pages not implemented */ 1063 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); 1064 } 1065 1066 void helper_mtc0_pagegrain (target_ulong arg1) 1067 { 1068 /* SmartMIPS not implemented */ 1069 /* Large physaddr (PABITS) not implemented */ 1070 /* 1k pages not implemented */ 1071 env->CP0_PageGrain = 0; 1072 } 1073 1074 void helper_mtc0_wired (target_ulong arg1) 1075 { 1076 env->CP0_Wired = arg1 % env->tlb->nb_tlb; 1077 } 1078 1079 void helper_mtc0_srsconf0 (target_ulong arg1) 1080 { 1081 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask; 1082 } 1083 1084 void helper_mtc0_srsconf1 (target_ulong arg1) 1085 { 1086 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask; 1087 } 1088 1089 void helper_mtc0_srsconf2 (target_ulong arg1) 1090 { 1091 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask; 1092 } 1093 1094 void helper_mtc0_srsconf3 (target_ulong arg1) 1095 { 1096 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask; 1097 } 1098 1099 void helper_mtc0_srsconf4 (target_ulong arg1) 1100 { 1101 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask; 1102 } 1103 1104 void helper_mtc0_hwrena (target_ulong arg1) 1105 { 1106 env->CP0_HWREna = arg1 & 0x0000000F; 1107 } 1108 1109 void helper_mtc0_count (target_ulong arg1) 1110 { 1111 cpu_mips_store_count(env, arg1); 1112 } 1113 1114 void helper_mtc0_entryhi (target_ulong arg1) 1115 { 1116 target_ulong old, val; 1117 1118 /* 1k pages not implemented */ 1119 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF); 1120 #if defined(TARGET_MIPS64) 1121 val &= env->SEGMask; 1122 #endif 1123 old = env->CP0_EntryHi; 1124 env->CP0_EntryHi = val; 1125 if (env->CP0_Config3 & (1 << CP0C3_MT)) { 1126 uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff; 1127 env->active_tc.CP0_TCStatus = tcst | (val & 0xff); 1128 } 1129 /* If the ASID changes, flush qemu's TLB. */ 1130 if ((old & 0xFF) != (val & 0xFF)) 1131 cpu_mips_tlb_flush(env, 1); 1132 } 1133 1134 void helper_mttc0_entryhi(target_ulong arg1) 1135 { 1136 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1137 int32_t tcstatus; 1138 1139 env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff); 1140 if (other_tc == env->current_tc) { 1141 tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff); 1142 env->active_tc.CP0_TCStatus = tcstatus; 1143 } else { 1144 tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff); 1145 env->tcs[other_tc].CP0_TCStatus = tcstatus; 1146 } 1147 } 1148 1149 void helper_mtc0_compare (target_ulong arg1) 1150 { 1151 cpu_mips_store_compare(env, arg1); 1152 } 1153 1154 void helper_mtc0_status (target_ulong arg1) 1155 { 1156 uint32_t val, old; 1157 uint32_t mask = env->CP0_Status_rw_bitmask; 1158 1159 val = arg1 & mask; 1160 old = env->CP0_Status; 1161 env->CP0_Status = (env->CP0_Status & ~mask) | val; 1162 compute_hflags(env); 1163 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 1164 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x", 1165 old, old & env->CP0_Cause & CP0Ca_IP_mask, 1166 val, val & env->CP0_Cause & CP0Ca_IP_mask, 1167 env->CP0_Cause); 1168 switch (env->hflags & MIPS_HFLAG_KSU) { 1169 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break; 1170 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break; 1171 case MIPS_HFLAG_KM: qemu_log("\n"); break; 1172 default: cpu_abort(env, "Invalid MMU mode!\n"); break; 1173 } 1174 } 1175 cpu_mips_update_irq(env); 1176 } 1177 1178 void helper_mttc0_status(target_ulong arg1) 1179 { 1180 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1181 int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus; 1182 1183 env->CP0_Status = arg1 & ~0xf1000018; 1184 tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0)); 1185 tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); 1186 tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); 1187 if (other_tc == env->current_tc) 1188 env->active_tc.CP0_TCStatus = tcstatus; 1189 else 1190 env->tcs[other_tc].CP0_TCStatus = tcstatus; 1191 } 1192 1193 void helper_mtc0_intctl (target_ulong arg1) 1194 { 1195 /* vectored interrupts not implemented, no performance counters. */ 1196 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0); 1197 } 1198 1199 void helper_mtc0_srsctl (target_ulong arg1) 1200 { 1201 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); 1202 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask); 1203 } 1204 1205 void helper_mtc0_cause (target_ulong arg1) 1206 { 1207 uint32_t mask = 0x00C00300; 1208 uint32_t old = env->CP0_Cause; 1209 1210 if (env->insn_flags & ISA_MIPS32R2) 1211 mask |= 1 << CP0Ca_DC; 1212 1213 env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask); 1214 1215 if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { 1216 if (env->CP0_Cause & (1 << CP0Ca_DC)) 1217 cpu_mips_stop_count(env); 1218 else 1219 cpu_mips_start_count(env); 1220 } 1221 1222 /* Handle the software interrupt as an hardware one, as they 1223 are very similar */ 1224 if (arg1 & CP0Ca_IP_mask) { 1225 cpu_mips_update_irq(env); 1226 } 1227 } 1228 1229 void helper_mtc0_ebase (target_ulong arg1) 1230 { 1231 /* vectored interrupts not implemented */ 1232 /* Multi-CPU not implemented */ 1233 env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000); 1234 } 1235 1236 void helper_mtc0_config0 (target_ulong arg1) 1237 { 1238 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007); 1239 } 1240 1241 void helper_mtc0_config2 (target_ulong arg1) 1242 { 1243 /* tertiary/secondary caches not implemented */ 1244 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); 1245 } 1246 1247 void helper_mtc0_lladdr (target_ulong arg1) 1248 { 1249 target_long mask = env->CP0_LLAddr_rw_bitmask; 1250 arg1 = arg1 << env->CP0_LLAddr_shift; 1251 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask); 1252 } 1253 1254 void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel) 1255 { 1256 /* Watch exceptions for instructions, data loads, data stores 1257 not implemented. */ 1258 env->CP0_WatchLo[sel] = (arg1 & ~0x7); 1259 } 1260 1261 void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel) 1262 { 1263 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8); 1264 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7); 1265 } 1266 1267 void helper_mtc0_xcontext (target_ulong arg1) 1268 { 1269 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; 1270 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask); 1271 } 1272 1273 void helper_mtc0_framemask (target_ulong arg1) 1274 { 1275 env->CP0_Framemask = arg1; /* XXX */ 1276 } 1277 1278 void helper_mtc0_debug (target_ulong arg1) 1279 { 1280 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120); 1281 if (arg1 & (1 << CP0DB_DM)) 1282 env->hflags |= MIPS_HFLAG_DM; 1283 else 1284 env->hflags &= ~MIPS_HFLAG_DM; 1285 } 1286 1287 void helper_mttc0_debug(target_ulong arg1) 1288 { 1289 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1290 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); 1291 1292 /* XXX: Might be wrong, check with EJTAG spec. */ 1293 if (other_tc == env->current_tc) 1294 env->active_tc.CP0_Debug_tcstatus = val; 1295 else 1296 env->tcs[other_tc].CP0_Debug_tcstatus = val; 1297 env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | 1298 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); 1299 } 1300 1301 void helper_mtc0_performance0 (target_ulong arg1) 1302 { 1303 env->CP0_Performance0 = arg1 & 0x000007ff; 1304 } 1305 1306 void helper_mtc0_taglo (target_ulong arg1) 1307 { 1308 env->CP0_TagLo = arg1 & 0xFFFFFCF6; 1309 } 1310 1311 void helper_mtc0_datalo (target_ulong arg1) 1312 { 1313 env->CP0_DataLo = arg1; /* XXX */ 1314 } 1315 1316 void helper_mtc0_taghi (target_ulong arg1) 1317 { 1318 env->CP0_TagHi = arg1; /* XXX */ 1319 } 1320 1321 void helper_mtc0_datahi (target_ulong arg1) 1322 { 1323 env->CP0_DataHi = arg1; /* XXX */ 1324 } 1325 1326 /* MIPS MT functions */ 1327 target_ulong helper_mftgpr(uint32_t sel) 1328 { 1329 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1330 1331 if (other_tc == env->current_tc) 1332 return env->active_tc.gpr[sel]; 1333 else 1334 return env->tcs[other_tc].gpr[sel]; 1335 } 1336 1337 target_ulong helper_mftlo(uint32_t sel) 1338 { 1339 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1340 1341 if (other_tc == env->current_tc) 1342 return env->active_tc.LO[sel]; 1343 else 1344 return env->tcs[other_tc].LO[sel]; 1345 } 1346 1347 target_ulong helper_mfthi(uint32_t sel) 1348 { 1349 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1350 1351 if (other_tc == env->current_tc) 1352 return env->active_tc.HI[sel]; 1353 else 1354 return env->tcs[other_tc].HI[sel]; 1355 } 1356 1357 target_ulong helper_mftacx(uint32_t sel) 1358 { 1359 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1360 1361 if (other_tc == env->current_tc) 1362 return env->active_tc.ACX[sel]; 1363 else 1364 return env->tcs[other_tc].ACX[sel]; 1365 } 1366 1367 target_ulong helper_mftdsp(void) 1368 { 1369 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1370 1371 if (other_tc == env->current_tc) 1372 return env->active_tc.DSPControl; 1373 else 1374 return env->tcs[other_tc].DSPControl; 1375 } 1376 1377 void helper_mttgpr(target_ulong arg1, uint32_t sel) 1378 { 1379 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1380 1381 if (other_tc == env->current_tc) 1382 env->active_tc.gpr[sel] = arg1; 1383 else 1384 env->tcs[other_tc].gpr[sel] = arg1; 1385 } 1386 1387 void helper_mttlo(target_ulong arg1, uint32_t sel) 1388 { 1389 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1390 1391 if (other_tc == env->current_tc) 1392 env->active_tc.LO[sel] = arg1; 1393 else 1394 env->tcs[other_tc].LO[sel] = arg1; 1395 } 1396 1397 void helper_mtthi(target_ulong arg1, uint32_t sel) 1398 { 1399 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1400 1401 if (other_tc == env->current_tc) 1402 env->active_tc.HI[sel] = arg1; 1403 else 1404 env->tcs[other_tc].HI[sel] = arg1; 1405 } 1406 1407 void helper_mttacx(target_ulong arg1, uint32_t sel) 1408 { 1409 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1410 1411 if (other_tc == env->current_tc) 1412 env->active_tc.ACX[sel] = arg1; 1413 else 1414 env->tcs[other_tc].ACX[sel] = arg1; 1415 } 1416 1417 void helper_mttdsp(target_ulong arg1) 1418 { 1419 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1420 1421 if (other_tc == env->current_tc) 1422 env->active_tc.DSPControl = arg1; 1423 else 1424 env->tcs[other_tc].DSPControl = arg1; 1425 } 1426 1427 /* MIPS MT functions */ 1428 target_ulong helper_dmt(target_ulong arg1) 1429 { 1430 // TODO 1431 arg1 = 0; 1432 // rt = arg1 1433 1434 return arg1; 1435 } 1436 1437 target_ulong helper_emt(target_ulong arg1) 1438 { 1439 // TODO 1440 arg1 = 0; 1441 // rt = arg1 1442 1443 return arg1; 1444 } 1445 1446 target_ulong helper_dvpe(target_ulong arg1) 1447 { 1448 // TODO 1449 arg1 = 0; 1450 // rt = arg1 1451 1452 return arg1; 1453 } 1454 1455 target_ulong helper_evpe(target_ulong arg1) 1456 { 1457 // TODO 1458 arg1 = 0; 1459 // rt = arg1 1460 1461 return arg1; 1462 } 1463 #endif /* !CONFIG_USER_ONLY */ 1464 1465 void helper_fork(target_ulong arg1, target_ulong arg2) 1466 { 1467 // arg1 = rt, arg2 = rs 1468 arg1 = 0; 1469 // TODO: store to TC register 1470 } 1471 1472 target_ulong helper_yield(target_ulong arg1) 1473 { 1474 if (arg1 < 0) { 1475 /* No scheduling policy implemented. */ 1476 if (arg1 != -2) { 1477 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && 1478 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { 1479 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 1480 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; 1481 helper_raise_exception(EXCP_THREAD); 1482 } 1483 } 1484 } else if (arg1 == 0) { 1485 if (0 /* TODO: TC underflow */) { 1486 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 1487 helper_raise_exception(EXCP_THREAD); 1488 } else { 1489 // TODO: Deallocate TC 1490 } 1491 } else if (arg1 > 0) { 1492 /* Yield qualifier inputs not implemented. */ 1493 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 1494 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; 1495 helper_raise_exception(EXCP_THREAD); 1496 } 1497 return env->CP0_YQMask; 1498 } 1499 1500 #ifndef CONFIG_USER_ONLY 1501 static void inline r4k_invalidate_tlb_shadow (CPUState *env, int idx) 1502 { 1503 r4k_tlb_t *tlb; 1504 uint8_t ASID = env->CP0_EntryHi & 0xFF; 1505 1506 tlb = &env->tlb->mmu.r4k.tlb[idx]; 1507 /* The qemu TLB is flushed when the ASID changes, so no need to 1508 flush these entries again. */ 1509 if (tlb->G == 0 && tlb->ASID != ASID) { 1510 return; 1511 } 1512 } 1513 1514 static void inline r4k_invalidate_tlb (CPUState *env, int idx) 1515 { 1516 r4k_tlb_t *tlb; 1517 target_ulong addr; 1518 target_ulong end; 1519 uint8_t ASID = env->CP0_EntryHi & 0xFF; 1520 target_ulong mask; 1521 1522 tlb = &env->tlb->mmu.r4k.tlb[idx]; 1523 /* The qemu TLB is flushed when the ASID changes, so no need to 1524 flush these entries again. */ 1525 if (tlb->G == 0 && tlb->ASID != ASID) { 1526 return; 1527 } 1528 1529 /* 1k pages are not supported. */ 1530 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); 1531 if (tlb->V0) { 1532 addr = tlb->VPN & ~mask; 1533 #if defined(TARGET_MIPS64) 1534 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { 1535 addr |= 0x3FFFFF0000000000ULL; 1536 } 1537 #endif 1538 end = addr | (mask >> 1); 1539 while (addr < end) { 1540 tlb_flush_page (env, addr); 1541 addr += TARGET_PAGE_SIZE; 1542 } 1543 } 1544 if (tlb->V1) { 1545 addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); 1546 #if defined(TARGET_MIPS64) 1547 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { 1548 addr |= 0x3FFFFF0000000000ULL; 1549 } 1550 #endif 1551 end = addr | mask; 1552 while (addr - 1 < end) { 1553 tlb_flush_page (env, addr); 1554 addr += TARGET_PAGE_SIZE; 1555 } 1556 } 1557 } 1558 1559 /* TLB management */ 1560 void cpu_mips_tlb_flush (CPUState *env, int flush_global) 1561 { 1562 /* Flush qemu's TLB and discard all shadowed entries. */ 1563 tlb_flush (env, flush_global); 1564 } 1565 1566 static void r4k_fill_tlb (int idx) 1567 { 1568 r4k_tlb_t *tlb; 1569 1570 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ 1571 tlb = &env->tlb->mmu.r4k.tlb[idx]; 1572 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); 1573 #if defined(TARGET_MIPS64) 1574 tlb->VPN &= env->SEGMask; 1575 #endif 1576 tlb->ASID = env->CP0_EntryHi & 0xFF; 1577 tlb->PageMask = env->CP0_PageMask; 1578 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; 1579 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; 1580 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; 1581 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; 1582 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; 1583 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; 1584 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; 1585 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; 1586 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; 1587 } 1588 1589 void r4k_helper_ptw_tlbrefill(CPUState *target_env) 1590 { 1591 CPUState *saved_env; 1592 1593 /* Save current 'env' value */ 1594 saved_env = env; 1595 env = target_env; 1596 1597 /* Do TLB load on behalf of Page Table Walk */ 1598 int r = cpu_mips_get_random(env); 1599 r4k_invalidate_tlb_shadow(env, r); 1600 r4k_fill_tlb(r); 1601 1602 /* Restore 'env' value */ 1603 env = saved_env; 1604 } 1605 1606 void r4k_helper_tlbwi (void) 1607 { 1608 r4k_tlb_t *tlb; 1609 target_ulong tag; 1610 target_ulong VPN; 1611 target_ulong mask; 1612 1613 /* If tlbwi is trying to upgrading access permissions on current entry, 1614 * we do not need to flush tlb hash table. 1615 */ 1616 tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb]; 1617 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); 1618 tag = env->CP0_EntryHi & ~mask; 1619 VPN = tlb->VPN & ~mask; 1620 if (VPN == tag) 1621 { 1622 if (tlb->ASID == (env->CP0_EntryHi & 0xFF)) 1623 { 1624 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; 1625 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; 1626 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; 1627 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; 1628 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; 1629 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; 1630 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; 1631 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; 1632 return; 1633 } 1634 } 1635 1636 /*flush all the tlb cache */ 1637 cpu_mips_tlb_flush (env, 1); 1638 1639 r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb); 1640 r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb); 1641 } 1642 1643 void r4k_helper_tlbwr (void) 1644 { 1645 int r = cpu_mips_get_random(env); 1646 1647 r4k_invalidate_tlb_shadow(env, r); 1648 r4k_fill_tlb(r); 1649 } 1650 1651 void r4k_helper_tlbp (void) 1652 { 1653 r4k_tlb_t *tlb; 1654 target_ulong mask; 1655 target_ulong tag; 1656 target_ulong VPN; 1657 uint8_t ASID; 1658 int i; 1659 target_ulong addr; 1660 target_ulong end; 1661 1662 ASID = env->CP0_EntryHi & 0xFF; 1663 for (i = 0; i < env->tlb->nb_tlb; i++) { 1664 tlb = &env->tlb->mmu.r4k.tlb[i]; 1665 /* 1k pages are not supported. */ 1666 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); 1667 tag = env->CP0_EntryHi & ~mask; 1668 VPN = tlb->VPN & ~mask; 1669 /* Check ASID, virtual page number & size */ 1670 if (unlikely((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag)) { 1671 /* TLB match */ 1672 env->CP0_Index = i; 1673 break; 1674 } 1675 } 1676 if (i == env->tlb->nb_tlb) { 1677 /* No match. Discard any shadow entries, if any of them match. */ 1678 int index = ((env->CP0_EntryHi>>5)&0x1ff00) | ASID; 1679 index |= (env->CP0_EntryHi>>13)&0x20000; 1680 env->CP0_Index |= 0x80000000; 1681 } 1682 } 1683 1684 void r4k_helper_tlbr (void) 1685 { 1686 r4k_tlb_t *tlb; 1687 uint8_t ASID; 1688 1689 ASID = env->CP0_EntryHi & 0xFF; 1690 tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb]; 1691 1692 /* If this will change the current ASID, flush qemu's TLB. */ 1693 if (ASID != tlb->ASID) 1694 cpu_mips_tlb_flush (env, 1); 1695 1696 /*flush all the tlb cache */ 1697 cpu_mips_tlb_flush (env, 1); 1698 1699 env->CP0_EntryHi = tlb->VPN | tlb->ASID; 1700 env->CP0_PageMask = tlb->PageMask; 1701 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | 1702 (tlb->C0 << 3) | (tlb->PFN[0] >> 6); 1703 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | 1704 (tlb->C1 << 3) | (tlb->PFN[1] >> 6); 1705 } 1706 1707 void helper_tlbwi(void) 1708 { 1709 env->tlb->helper_tlbwi(); 1710 } 1711 1712 void helper_tlbwr(void) 1713 { 1714 env->tlb->helper_tlbwr(); 1715 } 1716 1717 void helper_tlbp(void) 1718 { 1719 env->tlb->helper_tlbp(); 1720 } 1721 1722 void helper_tlbr(void) 1723 { 1724 env->tlb->helper_tlbr(); 1725 } 1726 1727 /* Specials */ 1728 target_ulong helper_di (void) 1729 { 1730 target_ulong t0 = env->CP0_Status; 1731 1732 env->CP0_Status = t0 & ~(1 << CP0St_IE); 1733 cpu_mips_update_irq(env); 1734 1735 return t0; 1736 } 1737 1738 target_ulong helper_ei (void) 1739 { 1740 target_ulong t0 = env->CP0_Status; 1741 1742 env->CP0_Status = t0 | (1 << CP0St_IE); 1743 cpu_mips_update_irq(env); 1744 1745 return t0; 1746 } 1747 1748 static void debug_pre_eret (void) 1749 { 1750 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 1751 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 1752 env->active_tc.PC, env->CP0_EPC); 1753 if (env->CP0_Status & (1 << CP0St_ERL)) 1754 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 1755 if (env->hflags & MIPS_HFLAG_DM) 1756 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 1757 qemu_log("\n"); 1758 } 1759 } 1760 1761 static void debug_post_eret (void) 1762 { 1763 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 1764 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 1765 env->active_tc.PC, env->CP0_EPC); 1766 if (env->CP0_Status & (1 << CP0St_ERL)) 1767 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 1768 if (env->hflags & MIPS_HFLAG_DM) 1769 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 1770 switch (env->hflags & MIPS_HFLAG_KSU) { 1771 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break; 1772 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break; 1773 case MIPS_HFLAG_KM: qemu_log("\n"); break; 1774 default: cpu_abort(env, "Invalid MMU mode!\n"); break; 1775 } 1776 } 1777 } 1778 1779 void helper_eret (void) 1780 { 1781 debug_pre_eret(); 1782 if (env->CP0_Status & (1 << CP0St_ERL)) { 1783 env->active_tc.PC = env->CP0_ErrorEPC; 1784 env->CP0_Status &= ~(1 << CP0St_ERL); 1785 } else { 1786 env->active_tc.PC = env->CP0_EPC; 1787 env->CP0_Status &= ~(1 << CP0St_EXL); 1788 } 1789 compute_hflags(env); 1790 debug_post_eret(); 1791 env->lladdr = 1; 1792 } 1793 1794 void helper_deret (void) 1795 { 1796 debug_pre_eret(); 1797 env->active_tc.PC = env->CP0_DEPC; 1798 env->hflags &= MIPS_HFLAG_DM; 1799 compute_hflags(env); 1800 debug_post_eret(); 1801 env->lladdr = 1; 1802 } 1803 #endif /* !CONFIG_USER_ONLY */ 1804 1805 target_ulong helper_rdhwr_cpunum(void) 1806 { 1807 if ((env->hflags & MIPS_HFLAG_CP0) || 1808 (env->CP0_HWREna & (1 << 0))) 1809 return env->CP0_EBase & 0x3ff; 1810 else 1811 helper_raise_exception(EXCP_RI); 1812 1813 return 0; 1814 } 1815 1816 target_ulong helper_rdhwr_synci_step(void) 1817 { 1818 if ((env->hflags & MIPS_HFLAG_CP0) || 1819 (env->CP0_HWREna & (1 << 1))) 1820 return env->SYNCI_Step; 1821 else 1822 helper_raise_exception(EXCP_RI); 1823 1824 return 0; 1825 } 1826 1827 target_ulong helper_rdhwr_cc(void) 1828 { 1829 if ((env->hflags & MIPS_HFLAG_CP0) || 1830 (env->CP0_HWREna & (1 << 2))) 1831 return env->CP0_Count; 1832 else 1833 helper_raise_exception(EXCP_RI); 1834 1835 return 0; 1836 } 1837 1838 target_ulong helper_rdhwr_ccres(void) 1839 { 1840 if ((env->hflags & MIPS_HFLAG_CP0) || 1841 (env->CP0_HWREna & (1 << 3))) 1842 return env->CCRes; 1843 else 1844 helper_raise_exception(EXCP_RI); 1845 1846 return 0; 1847 } 1848 1849 void helper_pmon (int function) 1850 { 1851 function /= 2; 1852 switch (function) { 1853 case 2: /* TODO: char inbyte(int waitflag); */ 1854 if (env->active_tc.gpr[4] == 0) 1855 env->active_tc.gpr[2] = -1; 1856 /* Fall through */ 1857 case 11: /* TODO: char inbyte (void); */ 1858 env->active_tc.gpr[2] = -1; 1859 break; 1860 case 3: 1861 case 12: 1862 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF)); 1863 break; 1864 case 17: 1865 break; 1866 case 158: 1867 { 1868 unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4]; 1869 printf("%s", fmt); 1870 } 1871 break; 1872 } 1873 } 1874 1875 void helper_wait (void) 1876 { 1877 env->halted = 1; 1878 helper_raise_exception(EXCP_HLT); 1879 } 1880 1881 #if !defined(CONFIG_USER_ONLY) 1882 1883 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); 1884 1885 #define MMUSUFFIX _mmu 1886 #define ALIGNED_ONLY 1887 1888 #define SHIFT 0 1889 #include "softmmu_template.h" 1890 1891 #define SHIFT 1 1892 #include "softmmu_template.h" 1893 1894 #define SHIFT 2 1895 #include "softmmu_template.h" 1896 1897 #define SHIFT 3 1898 #include "softmmu_template.h" 1899 1900 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr) 1901 { 1902 env->CP0_BadVAddr = addr; 1903 do_restore_state (retaddr); 1904 helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); 1905 } 1906 1907 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) 1908 { 1909 TranslationBlock *tb; 1910 CPUState *saved_env; 1911 unsigned long pc; 1912 int ret; 1913 1914 /* XXX: hack to restore env in all cases, even if not called from 1915 generated code */ 1916 saved_env = env; 1917 env = cpu_single_env; 1918 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); 1919 if (ret) { 1920 if (retaddr) { 1921 /* now we have a real cpu fault */ 1922 pc = (unsigned long)retaddr; 1923 tb = tb_find_pc(pc); 1924 if (tb) { 1925 /* the PC is inside the translated code. It means that we have 1926 a virtual CPU fault */ 1927 cpu_restore_state(tb, env, pc); 1928 } 1929 } 1930 helper_raise_exception_err(env->exception_index, env->error_code); 1931 } 1932 env = saved_env; 1933 } 1934 1935 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, 1936 int unused, int size) 1937 { 1938 if (is_exec) 1939 helper_raise_exception(EXCP_IBE); 1940 else 1941 helper_raise_exception(EXCP_DBE); 1942 } 1943 /* 1944 * The following functions are address translation helper functions 1945 * for fast memory access in QEMU. 1946 */ 1947 static unsigned long v2p_mmu(target_ulong addr, int is_user) 1948 { 1949 int index; 1950 target_ulong tlb_addr; 1951 unsigned long physaddr; 1952 void *retaddr; 1953 1954 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 1955 redo: 1956 tlb_addr = env->tlb_table[is_user][index].addr_read; 1957 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { 1958 physaddr = addr + env->tlb_table[is_user][index].addend; 1959 } else { 1960 /* the page is not in the TLB : fill it */ 1961 retaddr = GETPC(); 1962 tlb_fill(addr, 0, is_user, retaddr); 1963 goto redo; 1964 } 1965 return physaddr; 1966 } 1967 1968 /* 1969 * translation from virtual address of simulated OS 1970 * to the address of simulation host (not the physical 1971 * address of simulated OS. 1972 */ 1973 unsigned long v2p(target_ulong ptr, int is_user) 1974 { 1975 CPUState *saved_env; 1976 int index; 1977 target_ulong addr; 1978 unsigned long physaddr; 1979 1980 saved_env = env; 1981 env = cpu_single_env; 1982 addr = ptr; 1983 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 1984 if (__builtin_expect(env->tlb_table[is_user][index].addr_read != 1985 (addr & TARGET_PAGE_MASK), 0)) { 1986 physaddr = v2p_mmu(addr, is_user); 1987 } else { 1988 physaddr = addr + env->tlb_table[is_user][index].addend; 1989 } 1990 env = saved_env; 1991 return physaddr; 1992 } 1993 1994 /* copy a string from the simulated virtual space to a buffer in QEMU */ 1995 void vstrcpy(target_ulong ptr, char *buf, int max) 1996 { 1997 char *phys = 0; 1998 unsigned long page = 0; 1999 2000 if (buf == NULL) return; 2001 2002 while (max) { 2003 if ((ptr & TARGET_PAGE_MASK) != page) { 2004 phys = (char *)v2p(ptr, 0); 2005 page = ptr & TARGET_PAGE_MASK; 2006 } 2007 *buf = *phys; 2008 if (*phys == '\0') 2009 return; 2010 ptr ++; 2011 buf ++; 2012 phys ++; 2013 max --; 2014 } 2015 } 2016 2017 #endif /* !CONFIG_USER_ONLY */ 2018 2019 /* Complex FPU operations which may need stack space. */ 2020 2021 #define FLOAT_ONE32 make_float32(0x3f8 << 20) 2022 #define FLOAT_ONE64 make_float64(0x3ffULL << 52) 2023 #define FLOAT_TWO32 make_float32(1 << 30) 2024 #define FLOAT_TWO64 make_float64(1ULL << 62) 2025 #define FLOAT_QNAN32 0x7fbfffff 2026 #define FLOAT_QNAN64 0x7ff7ffffffffffffULL 2027 #define FLOAT_SNAN32 0x7fffffff 2028 #define FLOAT_SNAN64 0x7fffffffffffffffULL 2029 2030 /* convert MIPS rounding mode in FCR31 to IEEE library */ 2031 static unsigned int ieee_rm[] = { 2032 float_round_nearest_even, 2033 float_round_to_zero, 2034 float_round_up, 2035 float_round_down 2036 }; 2037 2038 #define RESTORE_ROUNDING_MODE \ 2039 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) 2040 2041 #define RESTORE_FLUSH_MODE \ 2042 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status); 2043 2044 target_ulong helper_cfc1 (uint32_t reg) 2045 { 2046 target_ulong arg1; 2047 2048 switch (reg) { 2049 case 0: 2050 arg1 = (int32_t)env->active_fpu.fcr0; 2051 break; 2052 case 25: 2053 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1); 2054 break; 2055 case 26: 2056 arg1 = env->active_fpu.fcr31 & 0x0003f07c; 2057 break; 2058 case 28: 2059 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4); 2060 break; 2061 default: 2062 arg1 = (int32_t)env->active_fpu.fcr31; 2063 break; 2064 } 2065 2066 return arg1; 2067 } 2068 2069 void helper_ctc1 (target_ulong arg1, uint32_t reg) 2070 { 2071 switch(reg) { 2072 case 25: 2073 if (arg1 & 0xffffff00) 2074 return; 2075 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) | 2076 ((arg1 & 0x1) << 23); 2077 break; 2078 case 26: 2079 if (arg1 & 0x007c0000) 2080 return; 2081 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c); 2082 break; 2083 case 28: 2084 if (arg1 & 0x007c0000) 2085 return; 2086 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) | 2087 ((arg1 & 0x4) << 22); 2088 break; 2089 case 31: 2090 if (arg1 & 0x007c0000) 2091 return; 2092 env->active_fpu.fcr31 = arg1; 2093 break; 2094 default: 2095 return; 2096 } 2097 /* set rounding mode */ 2098 RESTORE_ROUNDING_MODE; 2099 /* set flush-to-zero mode */ 2100 RESTORE_FLUSH_MODE; 2101 set_float_exception_flags(0, &env->active_fpu.fp_status); 2102 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31)) 2103 helper_raise_exception(EXCP_FPE); 2104 } 2105 2106 static inline char ieee_ex_to_mips(char xcpt) 2107 { 2108 return (xcpt & float_flag_inexact) >> 5 | 2109 (xcpt & float_flag_underflow) >> 3 | 2110 (xcpt & float_flag_overflow) >> 1 | 2111 (xcpt & float_flag_divbyzero) << 1 | 2112 (xcpt & float_flag_invalid) << 4; 2113 } 2114 2115 static inline char mips_ex_to_ieee(char xcpt) 2116 { 2117 return (xcpt & FP_INEXACT) << 5 | 2118 (xcpt & FP_UNDERFLOW) << 3 | 2119 (xcpt & FP_OVERFLOW) << 1 | 2120 (xcpt & FP_DIV0) >> 1 | 2121 (xcpt & FP_INVALID) >> 4; 2122 } 2123 2124 static inline void update_fcr31(void) 2125 { 2126 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status)); 2127 2128 SET_FP_CAUSE(env->active_fpu.fcr31, tmp); 2129 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) 2130 helper_raise_exception(EXCP_FPE); 2131 else 2132 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp); 2133 } 2134 2135 /* Float support. 2136 Single precition routines have a "s" suffix, double precision a 2137 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps", 2138 paired single lower "pl", paired single upper "pu". */ 2139 2140 /* unary operations, modifying fp status */ 2141 uint64_t helper_float_sqrt_d(uint64_t fdt0) 2142 { 2143 return float64_sqrt(fdt0, &env->active_fpu.fp_status); 2144 } 2145 2146 uint32_t helper_float_sqrt_s(uint32_t fst0) 2147 { 2148 return float32_sqrt(fst0, &env->active_fpu.fp_status); 2149 } 2150 2151 uint64_t helper_float_cvtd_s(uint32_t fst0) 2152 { 2153 uint64_t fdt2; 2154 2155 set_float_exception_flags(0, &env->active_fpu.fp_status); 2156 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); 2157 update_fcr31(); 2158 return fdt2; 2159 } 2160 2161 uint64_t helper_float_cvtd_w(uint32_t wt0) 2162 { 2163 uint64_t fdt2; 2164 2165 set_float_exception_flags(0, &env->active_fpu.fp_status); 2166 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); 2167 update_fcr31(); 2168 return fdt2; 2169 } 2170 2171 uint64_t helper_float_cvtd_l(uint64_t dt0) 2172 { 2173 uint64_t fdt2; 2174 2175 set_float_exception_flags(0, &env->active_fpu.fp_status); 2176 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); 2177 update_fcr31(); 2178 return fdt2; 2179 } 2180 2181 uint64_t helper_float_cvtl_d(uint64_t fdt0) 2182 { 2183 uint64_t dt2; 2184 2185 set_float_exception_flags(0, &env->active_fpu.fp_status); 2186 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); 2187 update_fcr31(); 2188 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2189 dt2 = FLOAT_SNAN64; 2190 return dt2; 2191 } 2192 2193 uint64_t helper_float_cvtl_s(uint32_t fst0) 2194 { 2195 uint64_t dt2; 2196 2197 set_float_exception_flags(0, &env->active_fpu.fp_status); 2198 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); 2199 update_fcr31(); 2200 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2201 dt2 = FLOAT_SNAN64; 2202 return dt2; 2203 } 2204 2205 uint64_t helper_float_cvtps_pw(uint64_t dt0) 2206 { 2207 uint32_t fst2; 2208 uint32_t fsth2; 2209 2210 set_float_exception_flags(0, &env->active_fpu.fp_status); 2211 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); 2212 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status); 2213 update_fcr31(); 2214 return ((uint64_t)fsth2 << 32) | fst2; 2215 } 2216 2217 uint64_t helper_float_cvtpw_ps(uint64_t fdt0) 2218 { 2219 uint32_t wt2; 2220 uint32_t wth2; 2221 2222 set_float_exception_flags(0, &env->active_fpu.fp_status); 2223 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); 2224 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status); 2225 update_fcr31(); 2226 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) { 2227 wt2 = FLOAT_SNAN32; 2228 wth2 = FLOAT_SNAN32; 2229 } 2230 return ((uint64_t)wth2 << 32) | wt2; 2231 } 2232 2233 uint32_t helper_float_cvts_d(uint64_t fdt0) 2234 { 2235 uint32_t fst2; 2236 2237 set_float_exception_flags(0, &env->active_fpu.fp_status); 2238 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); 2239 update_fcr31(); 2240 return fst2; 2241 } 2242 2243 uint32_t helper_float_cvts_w(uint32_t wt0) 2244 { 2245 uint32_t fst2; 2246 2247 set_float_exception_flags(0, &env->active_fpu.fp_status); 2248 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); 2249 update_fcr31(); 2250 return fst2; 2251 } 2252 2253 uint32_t helper_float_cvts_l(uint64_t dt0) 2254 { 2255 uint32_t fst2; 2256 2257 set_float_exception_flags(0, &env->active_fpu.fp_status); 2258 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); 2259 update_fcr31(); 2260 return fst2; 2261 } 2262 2263 uint32_t helper_float_cvts_pl(uint32_t wt0) 2264 { 2265 uint32_t wt2; 2266 2267 set_float_exception_flags(0, &env->active_fpu.fp_status); 2268 wt2 = wt0; 2269 update_fcr31(); 2270 return wt2; 2271 } 2272 2273 uint32_t helper_float_cvts_pu(uint32_t wth0) 2274 { 2275 uint32_t wt2; 2276 2277 set_float_exception_flags(0, &env->active_fpu.fp_status); 2278 wt2 = wth0; 2279 update_fcr31(); 2280 return wt2; 2281 } 2282 2283 uint32_t helper_float_cvtw_s(uint32_t fst0) 2284 { 2285 uint32_t wt2; 2286 2287 set_float_exception_flags(0, &env->active_fpu.fp_status); 2288 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); 2289 update_fcr31(); 2290 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2291 wt2 = FLOAT_SNAN32; 2292 return wt2; 2293 } 2294 2295 uint32_t helper_float_cvtw_d(uint64_t fdt0) 2296 { 2297 uint32_t wt2; 2298 2299 set_float_exception_flags(0, &env->active_fpu.fp_status); 2300 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); 2301 update_fcr31(); 2302 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2303 wt2 = FLOAT_SNAN32; 2304 return wt2; 2305 } 2306 2307 uint64_t helper_float_roundl_d(uint64_t fdt0) 2308 { 2309 uint64_t dt2; 2310 2311 set_float_exception_flags(0, &env->active_fpu.fp_status); 2312 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); 2313 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); 2314 RESTORE_ROUNDING_MODE; 2315 update_fcr31(); 2316 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2317 dt2 = FLOAT_SNAN64; 2318 return dt2; 2319 } 2320 2321 uint64_t helper_float_roundl_s(uint32_t fst0) 2322 { 2323 uint64_t dt2; 2324 2325 set_float_exception_flags(0, &env->active_fpu.fp_status); 2326 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); 2327 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); 2328 RESTORE_ROUNDING_MODE; 2329 update_fcr31(); 2330 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2331 dt2 = FLOAT_SNAN64; 2332 return dt2; 2333 } 2334 2335 uint32_t helper_float_roundw_d(uint64_t fdt0) 2336 { 2337 uint32_t wt2; 2338 2339 set_float_exception_flags(0, &env->active_fpu.fp_status); 2340 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); 2341 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); 2342 RESTORE_ROUNDING_MODE; 2343 update_fcr31(); 2344 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2345 wt2 = FLOAT_SNAN32; 2346 return wt2; 2347 } 2348 2349 uint32_t helper_float_roundw_s(uint32_t fst0) 2350 { 2351 uint32_t wt2; 2352 2353 set_float_exception_flags(0, &env->active_fpu.fp_status); 2354 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); 2355 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); 2356 RESTORE_ROUNDING_MODE; 2357 update_fcr31(); 2358 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2359 wt2 = FLOAT_SNAN32; 2360 return wt2; 2361 } 2362 2363 uint64_t helper_float_truncl_d(uint64_t fdt0) 2364 { 2365 uint64_t dt2; 2366 2367 set_float_exception_flags(0, &env->active_fpu.fp_status); 2368 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status); 2369 update_fcr31(); 2370 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2371 dt2 = FLOAT_SNAN64; 2372 return dt2; 2373 } 2374 2375 uint64_t helper_float_truncl_s(uint32_t fst0) 2376 { 2377 uint64_t dt2; 2378 2379 set_float_exception_flags(0, &env->active_fpu.fp_status); 2380 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); 2381 update_fcr31(); 2382 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2383 dt2 = FLOAT_SNAN64; 2384 return dt2; 2385 } 2386 2387 uint32_t helper_float_truncw_d(uint64_t fdt0) 2388 { 2389 uint32_t wt2; 2390 2391 set_float_exception_flags(0, &env->active_fpu.fp_status); 2392 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); 2393 update_fcr31(); 2394 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2395 wt2 = FLOAT_SNAN32; 2396 return wt2; 2397 } 2398 2399 uint32_t helper_float_truncw_s(uint32_t fst0) 2400 { 2401 uint32_t wt2; 2402 2403 set_float_exception_flags(0, &env->active_fpu.fp_status); 2404 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); 2405 update_fcr31(); 2406 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2407 wt2 = FLOAT_SNAN32; 2408 return wt2; 2409 } 2410 2411 uint64_t helper_float_ceill_d(uint64_t fdt0) 2412 { 2413 uint64_t dt2; 2414 2415 set_float_exception_flags(0, &env->active_fpu.fp_status); 2416 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); 2417 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); 2418 RESTORE_ROUNDING_MODE; 2419 update_fcr31(); 2420 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2421 dt2 = FLOAT_SNAN64; 2422 return dt2; 2423 } 2424 2425 uint64_t helper_float_ceill_s(uint32_t fst0) 2426 { 2427 uint64_t dt2; 2428 2429 set_float_exception_flags(0, &env->active_fpu.fp_status); 2430 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); 2431 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); 2432 RESTORE_ROUNDING_MODE; 2433 update_fcr31(); 2434 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2435 dt2 = FLOAT_SNAN64; 2436 return dt2; 2437 } 2438 2439 uint32_t helper_float_ceilw_d(uint64_t fdt0) 2440 { 2441 uint32_t wt2; 2442 2443 set_float_exception_flags(0, &env->active_fpu.fp_status); 2444 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); 2445 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); 2446 RESTORE_ROUNDING_MODE; 2447 update_fcr31(); 2448 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2449 wt2 = FLOAT_SNAN32; 2450 return wt2; 2451 } 2452 2453 uint32_t helper_float_ceilw_s(uint32_t fst0) 2454 { 2455 uint32_t wt2; 2456 2457 set_float_exception_flags(0, &env->active_fpu.fp_status); 2458 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); 2459 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); 2460 RESTORE_ROUNDING_MODE; 2461 update_fcr31(); 2462 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2463 wt2 = FLOAT_SNAN32; 2464 return wt2; 2465 } 2466 2467 uint64_t helper_float_floorl_d(uint64_t fdt0) 2468 { 2469 uint64_t dt2; 2470 2471 set_float_exception_flags(0, &env->active_fpu.fp_status); 2472 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); 2473 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); 2474 RESTORE_ROUNDING_MODE; 2475 update_fcr31(); 2476 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2477 dt2 = FLOAT_SNAN64; 2478 return dt2; 2479 } 2480 2481 uint64_t helper_float_floorl_s(uint32_t fst0) 2482 { 2483 uint64_t dt2; 2484 2485 set_float_exception_flags(0, &env->active_fpu.fp_status); 2486 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); 2487 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); 2488 RESTORE_ROUNDING_MODE; 2489 update_fcr31(); 2490 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2491 dt2 = FLOAT_SNAN64; 2492 return dt2; 2493 } 2494 2495 uint32_t helper_float_floorw_d(uint64_t fdt0) 2496 { 2497 uint32_t wt2; 2498 2499 set_float_exception_flags(0, &env->active_fpu.fp_status); 2500 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); 2501 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); 2502 RESTORE_ROUNDING_MODE; 2503 update_fcr31(); 2504 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2505 wt2 = FLOAT_SNAN32; 2506 return wt2; 2507 } 2508 2509 uint32_t helper_float_floorw_s(uint32_t fst0) 2510 { 2511 uint32_t wt2; 2512 2513 set_float_exception_flags(0, &env->active_fpu.fp_status); 2514 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); 2515 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); 2516 RESTORE_ROUNDING_MODE; 2517 update_fcr31(); 2518 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) 2519 wt2 = FLOAT_SNAN32; 2520 return wt2; 2521 } 2522 2523 /* unary operations, not modifying fp status */ 2524 #define FLOAT_UNOP(name) \ 2525 uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \ 2526 { \ 2527 return float64_ ## name(fdt0); \ 2528 } \ 2529 uint32_t helper_float_ ## name ## _s(uint32_t fst0) \ 2530 { \ 2531 return float32_ ## name(fst0); \ 2532 } \ 2533 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \ 2534 { \ 2535 uint32_t wt0; \ 2536 uint32_t wth0; \ 2537 \ 2538 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \ 2539 wth0 = float32_ ## name(fdt0 >> 32); \ 2540 return ((uint64_t)wth0 << 32) | wt0; \ 2541 } 2542 FLOAT_UNOP(abs) 2543 FLOAT_UNOP(chs) 2544 #undef FLOAT_UNOP 2545 2546 /* MIPS specific unary operations */ 2547 uint64_t helper_float_recip_d(uint64_t fdt0) 2548 { 2549 uint64_t fdt2; 2550 2551 set_float_exception_flags(0, &env->active_fpu.fp_status); 2552 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); 2553 update_fcr31(); 2554 return fdt2; 2555 } 2556 2557 uint32_t helper_float_recip_s(uint32_t fst0) 2558 { 2559 uint32_t fst2; 2560 2561 set_float_exception_flags(0, &env->active_fpu.fp_status); 2562 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); 2563 update_fcr31(); 2564 return fst2; 2565 } 2566 2567 uint64_t helper_float_rsqrt_d(uint64_t fdt0) 2568 { 2569 uint64_t fdt2; 2570 2571 set_float_exception_flags(0, &env->active_fpu.fp_status); 2572 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); 2573 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); 2574 update_fcr31(); 2575 return fdt2; 2576 } 2577 2578 uint32_t helper_float_rsqrt_s(uint32_t fst0) 2579 { 2580 uint32_t fst2; 2581 2582 set_float_exception_flags(0, &env->active_fpu.fp_status); 2583 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); 2584 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); 2585 update_fcr31(); 2586 return fst2; 2587 } 2588 2589 uint64_t helper_float_recip1_d(uint64_t fdt0) 2590 { 2591 uint64_t fdt2; 2592 2593 set_float_exception_flags(0, &env->active_fpu.fp_status); 2594 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); 2595 update_fcr31(); 2596 return fdt2; 2597 } 2598 2599 uint32_t helper_float_recip1_s(uint32_t fst0) 2600 { 2601 uint32_t fst2; 2602 2603 set_float_exception_flags(0, &env->active_fpu.fp_status); 2604 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); 2605 update_fcr31(); 2606 return fst2; 2607 } 2608 2609 uint64_t helper_float_recip1_ps(uint64_t fdt0) 2610 { 2611 uint32_t fst2; 2612 uint32_t fsth2; 2613 2614 set_float_exception_flags(0, &env->active_fpu.fp_status); 2615 fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); 2616 fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status); 2617 update_fcr31(); 2618 return ((uint64_t)fsth2 << 32) | fst2; 2619 } 2620 2621 uint64_t helper_float_rsqrt1_d(uint64_t fdt0) 2622 { 2623 uint64_t fdt2; 2624 2625 set_float_exception_flags(0, &env->active_fpu.fp_status); 2626 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); 2627 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); 2628 update_fcr31(); 2629 return fdt2; 2630 } 2631 2632 uint32_t helper_float_rsqrt1_s(uint32_t fst0) 2633 { 2634 uint32_t fst2; 2635 2636 set_float_exception_flags(0, &env->active_fpu.fp_status); 2637 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); 2638 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); 2639 update_fcr31(); 2640 return fst2; 2641 } 2642 2643 uint64_t helper_float_rsqrt1_ps(uint64_t fdt0) 2644 { 2645 uint32_t fst2; 2646 uint32_t fsth2; 2647 2648 set_float_exception_flags(0, &env->active_fpu.fp_status); 2649 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); 2650 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status); 2651 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); 2652 fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status); 2653 update_fcr31(); 2654 return ((uint64_t)fsth2 << 32) | fst2; 2655 } 2656 2657 #define FLOAT_OP(name, p) void helper_float_##name##_##p(void) 2658 2659 /* binary operations */ 2660 #define FLOAT_BINOP(name) \ 2661 uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \ 2662 { \ 2663 uint64_t dt2; \ 2664 \ 2665 set_float_exception_flags(0, &env->active_fpu.fp_status); \ 2666 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \ 2667 update_fcr31(); \ 2668 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ 2669 dt2 = FLOAT_QNAN64; \ 2670 return dt2; \ 2671 } \ 2672 \ 2673 uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \ 2674 { \ 2675 uint32_t wt2; \ 2676 \ 2677 set_float_exception_flags(0, &env->active_fpu.fp_status); \ 2678 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ 2679 update_fcr31(); \ 2680 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ 2681 wt2 = FLOAT_QNAN32; \ 2682 return wt2; \ 2683 } \ 2684 \ 2685 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \ 2686 { \ 2687 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ 2688 uint32_t fsth0 = fdt0 >> 32; \ 2689 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ 2690 uint32_t fsth1 = fdt1 >> 32; \ 2691 uint32_t wt2; \ 2692 uint32_t wth2; \ 2693 \ 2694 set_float_exception_flags(0, &env->active_fpu.fp_status); \ 2695 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ 2696 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \ 2697 update_fcr31(); \ 2698 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \ 2699 wt2 = FLOAT_QNAN32; \ 2700 wth2 = FLOAT_QNAN32; \ 2701 } \ 2702 return ((uint64_t)wth2 << 32) | wt2; \ 2703 } 2704 2705 FLOAT_BINOP(add) 2706 FLOAT_BINOP(sub) 2707 FLOAT_BINOP(mul) 2708 FLOAT_BINOP(div) 2709 #undef FLOAT_BINOP 2710 2711 /* ternary operations */ 2712 #define FLOAT_TERNOP(name1, name2) \ 2713 uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ 2714 uint64_t fdt2) \ 2715 { \ 2716 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ 2717 return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ 2718 } \ 2719 \ 2720 uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ 2721 uint32_t fst2) \ 2722 { \ 2723 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ 2724 return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ 2725 } \ 2726 \ 2727 uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \ 2728 uint64_t fdt2) \ 2729 { \ 2730 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ 2731 uint32_t fsth0 = fdt0 >> 32; \ 2732 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ 2733 uint32_t fsth1 = fdt1 >> 32; \ 2734 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ 2735 uint32_t fsth2 = fdt2 >> 32; \ 2736 \ 2737 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ 2738 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \ 2739 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ 2740 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \ 2741 return ((uint64_t)fsth2 << 32) | fst2; \ 2742 } 2743 2744 FLOAT_TERNOP(mul, add) 2745 FLOAT_TERNOP(mul, sub) 2746 #undef FLOAT_TERNOP 2747 2748 /* negated ternary operations */ 2749 #define FLOAT_NTERNOP(name1, name2) \ 2750 uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ 2751 uint64_t fdt2) \ 2752 { \ 2753 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ 2754 fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ 2755 return float64_chs(fdt2); \ 2756 } \ 2757 \ 2758 uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ 2759 uint32_t fst2) \ 2760 { \ 2761 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ 2762 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ 2763 return float32_chs(fst2); \ 2764 } \ 2765 \ 2766 uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\ 2767 uint64_t fdt2) \ 2768 { \ 2769 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ 2770 uint32_t fsth0 = fdt0 >> 32; \ 2771 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ 2772 uint32_t fsth1 = fdt1 >> 32; \ 2773 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ 2774 uint32_t fsth2 = fdt2 >> 32; \ 2775 \ 2776 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ 2777 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \ 2778 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ 2779 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \ 2780 fst2 = float32_chs(fst2); \ 2781 fsth2 = float32_chs(fsth2); \ 2782 return ((uint64_t)fsth2 << 32) | fst2; \ 2783 } 2784 2785 FLOAT_NTERNOP(mul, add) 2786 FLOAT_NTERNOP(mul, sub) 2787 #undef FLOAT_NTERNOP 2788 2789 /* MIPS specific binary operations */ 2790 uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2) 2791 { 2792 set_float_exception_flags(0, &env->active_fpu.fp_status); 2793 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); 2794 fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status)); 2795 update_fcr31(); 2796 return fdt2; 2797 } 2798 2799 uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2) 2800 { 2801 set_float_exception_flags(0, &env->active_fpu.fp_status); 2802 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); 2803 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); 2804 update_fcr31(); 2805 return fst2; 2806 } 2807 2808 uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2) 2809 { 2810 uint32_t fst0 = fdt0 & 0XFFFFFFFF; 2811 uint32_t fsth0 = fdt0 >> 32; 2812 uint32_t fst2 = fdt2 & 0XFFFFFFFF; 2813 uint32_t fsth2 = fdt2 >> 32; 2814 2815 set_float_exception_flags(0, &env->active_fpu.fp_status); 2816 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); 2817 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); 2818 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); 2819 fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status)); 2820 update_fcr31(); 2821 return ((uint64_t)fsth2 << 32) | fst2; 2822 } 2823 2824 uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2) 2825 { 2826 set_float_exception_flags(0, &env->active_fpu.fp_status); 2827 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); 2828 fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status); 2829 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status)); 2830 update_fcr31(); 2831 return fdt2; 2832 } 2833 2834 uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2) 2835 { 2836 set_float_exception_flags(0, &env->active_fpu.fp_status); 2837 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); 2838 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status); 2839 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); 2840 update_fcr31(); 2841 return fst2; 2842 } 2843 2844 uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2) 2845 { 2846 uint32_t fst0 = fdt0 & 0XFFFFFFFF; 2847 uint32_t fsth0 = fdt0 >> 32; 2848 uint32_t fst2 = fdt2 & 0XFFFFFFFF; 2849 uint32_t fsth2 = fdt2 >> 32; 2850 2851 set_float_exception_flags(0, &env->active_fpu.fp_status); 2852 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); 2853 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); 2854 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status); 2855 fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status); 2856 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); 2857 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status)); 2858 update_fcr31(); 2859 return ((uint64_t)fsth2 << 32) | fst2; 2860 } 2861 2862 uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1) 2863 { 2864 uint32_t fst0 = fdt0 & 0XFFFFFFFF; 2865 uint32_t fsth0 = fdt0 >> 32; 2866 uint32_t fst1 = fdt1 & 0XFFFFFFFF; 2867 uint32_t fsth1 = fdt1 >> 32; 2868 uint32_t fst2; 2869 uint32_t fsth2; 2870 2871 set_float_exception_flags(0, &env->active_fpu.fp_status); 2872 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status); 2873 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status); 2874 update_fcr31(); 2875 return ((uint64_t)fsth2 << 32) | fst2; 2876 } 2877 2878 uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) 2879 { 2880 uint32_t fst0 = fdt0 & 0XFFFFFFFF; 2881 uint32_t fsth0 = fdt0 >> 32; 2882 uint32_t fst1 = fdt1 & 0XFFFFFFFF; 2883 uint32_t fsth1 = fdt1 >> 32; 2884 uint32_t fst2; 2885 uint32_t fsth2; 2886 2887 set_float_exception_flags(0, &env->active_fpu.fp_status); 2888 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status); 2889 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status); 2890 update_fcr31(); 2891 return ((uint64_t)fsth2 << 32) | fst2; 2892 } 2893 2894 /* compare operations */ 2895 #define FOP_COND_D(op, cond) \ 2896 void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ 2897 { \ 2898 int c = cond; \ 2899 update_fcr31(); \ 2900 if (c) \ 2901 SET_FP_COND(cc, env->active_fpu); \ 2902 else \ 2903 CLEAR_FP_COND(cc, env->active_fpu); \ 2904 } \ 2905 void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ 2906 { \ 2907 int c; \ 2908 fdt0 = float64_abs(fdt0); \ 2909 fdt1 = float64_abs(fdt1); \ 2910 c = cond; \ 2911 update_fcr31(); \ 2912 if (c) \ 2913 SET_FP_COND(cc, env->active_fpu); \ 2914 else \ 2915 CLEAR_FP_COND(cc, env->active_fpu); \ 2916 } 2917 2918 static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) 2919 { 2920 if (float64_is_signaling_nan(a) || 2921 float64_is_signaling_nan(b) || 2922 (sig && (float64_is_any_nan(a) || float64_is_any_nan(b)))) { 2923 float_raise(float_flag_invalid, status); 2924 return 1; 2925 } else if (float64_is_any_nan(a) || float64_is_any_nan(b)) { 2926 return 1; 2927 } else { 2928 return 0; 2929 } 2930 } 2931 2932 /* NOTE: the comma operator will make "cond" to eval to false, 2933 * but float*_is_unordered() is still called. */ 2934 FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0)) 2935 FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)) 2936 FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) 2937 FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) 2938 FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) 2939 FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) 2940 FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) 2941 FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) 2942 /* NOTE: the comma operator will make "cond" to eval to false, 2943 * but float*_is_unordered() is still called. */ 2944 FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0)) 2945 FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)) 2946 FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) 2947 FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) 2948 FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) 2949 FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) 2950 FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) 2951 FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) 2952 2953 #define FOP_COND_S(op, cond) \ 2954 void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ 2955 { \ 2956 int c = cond; \ 2957 update_fcr31(); \ 2958 if (c) \ 2959 SET_FP_COND(cc, env->active_fpu); \ 2960 else \ 2961 CLEAR_FP_COND(cc, env->active_fpu); \ 2962 } \ 2963 void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ 2964 { \ 2965 int c; \ 2966 fst0 = float32_abs(fst0); \ 2967 fst1 = float32_abs(fst1); \ 2968 c = cond; \ 2969 update_fcr31(); \ 2970 if (c) \ 2971 SET_FP_COND(cc, env->active_fpu); \ 2972 else \ 2973 CLEAR_FP_COND(cc, env->active_fpu); \ 2974 } 2975 2976 static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) 2977 { 2978 if (float32_is_signaling_nan(a) || 2979 float32_is_signaling_nan(b) || 2980 (sig && (float32_is_any_nan(a) || float32_is_any_nan(b)))) { 2981 float_raise(float_flag_invalid, status); 2982 return 1; 2983 } else if (float32_is_any_nan(a) || float32_is_any_nan(b)) { 2984 return 1; 2985 } else { 2986 return 0; 2987 } 2988 } 2989 2990 /* NOTE: the comma operator will make "cond" to eval to false, 2991 * but float*_is_unordered() is still called. */ 2992 FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0)) 2993 FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)) 2994 FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) 2995 FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) 2996 FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) 2997 FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) 2998 FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) 2999 FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) 3000 /* NOTE: the comma operator will make "cond" to eval to false, 3001 * but float*_is_unordered() is still called. */ 3002 FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0)) 3003 FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)) 3004 FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) 3005 FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) 3006 FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) 3007 FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) 3008 FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) 3009 FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) 3010 3011 #define FOP_COND_PS(op, condl, condh) \ 3012 void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ 3013 { \ 3014 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ 3015 uint32_t fsth0 = float32_abs(fdt0 >> 32); \ 3016 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ 3017 uint32_t fsth1 = float32_abs(fdt1 >> 32); \ 3018 int cl = condl; \ 3019 int ch = condh; \ 3020 \ 3021 update_fcr31(); \ 3022 if (cl) \ 3023 SET_FP_COND(cc, env->active_fpu); \ 3024 else \ 3025 CLEAR_FP_COND(cc, env->active_fpu); \ 3026 if (ch) \ 3027 SET_FP_COND(cc + 1, env->active_fpu); \ 3028 else \ 3029 CLEAR_FP_COND(cc + 1, env->active_fpu); \ 3030 } \ 3031 void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ 3032 { \ 3033 uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ 3034 uint32_t fsth0 = float32_abs(fdt0 >> 32); \ 3035 uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ 3036 uint32_t fsth1 = float32_abs(fdt1 >> 32); \ 3037 int cl = condl; \ 3038 int ch = condh; \ 3039 \ 3040 update_fcr31(); \ 3041 if (cl) \ 3042 SET_FP_COND(cc, env->active_fpu); \ 3043 else \ 3044 CLEAR_FP_COND(cc, env->active_fpu); \ 3045 if (ch) \ 3046 SET_FP_COND(cc + 1, env->active_fpu); \ 3047 else \ 3048 CLEAR_FP_COND(cc + 1, env->active_fpu); \ 3049 } 3050 3051 /* NOTE: the comma operator will make "cond" to eval to false, 3052 * but float*_is_unordered() is still called. */ 3053 FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0), 3054 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0)) 3055 FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 3056 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)) 3057 FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), 3058 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) 3059 FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), 3060 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) 3061 FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), 3062 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) 3063 FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), 3064 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) 3065 FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), 3066 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) 3067 FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), 3068 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) 3069 /* NOTE: the comma operator will make "cond" to eval to false, 3070 * but float*_is_unordered() is still called. */ 3071 FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0), 3072 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0)) 3073 FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 3074 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)) 3075 FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), 3076 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) 3077 FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), 3078 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) 3079 FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), 3080 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) 3081 FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), 3082 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) 3083 FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), 3084 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) 3085 FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), 3086 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) 3087