Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <limits.h> | 5 #include <limits.h> |
| 6 #include <stdarg.h> | 6 #include <stdarg.h> |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "src/v8.h" | 10 #include "src/v8.h" |
| (...skipping 2188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2199 case MOVZ: | 2199 case MOVZ: |
| 2200 case MOVCI: | 2200 case MOVCI: |
| 2201 // No action taken on decode. | 2201 // No action taken on decode. |
| 2202 break; | 2202 break; |
| 2203 case DIV: | 2203 case DIV: |
| 2204 case DIVU: | 2204 case DIVU: |
| 2205 case DDIV: | 2205 case DDIV: |
| 2206 case DDIVU: | 2206 case DDIVU: |
| 2207 // div and divu never raise exceptions. | 2207 // div and divu never raise exceptions. |
| 2208 break; | 2208 break; |
| 2209 case SELEQZ_S: | |
| 2210 case SELNEZ_S: | |
| 2211 break; | |
| 2209 default: | 2212 default: |
| 2210 UNREACHABLE(); | 2213 UNREACHABLE(); |
| 2211 } | 2214 } |
| 2212 break; | 2215 break; |
| 2213 case SPECIAL2: | 2216 case SPECIAL2: |
| 2214 switch (instr->FunctionFieldRaw()) { | 2217 switch (instr->FunctionFieldRaw()) { |
| 2215 case MUL: | 2218 case MUL: |
| 2216 // Only the lower 32 bits are kept. | 2219 // Only the lower 32 bits are kept. |
| 2217 *alu_out = (int32_t)rs_u * (int32_t)rt_u; | 2220 *alu_out = (int32_t)rs_u * (int32_t)rt_u; |
| 2218 break; | 2221 break; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2260 default: | 2263 default: |
| 2261 UNREACHABLE(); | 2264 UNREACHABLE(); |
| 2262 } | 2265 } |
| 2263 break; | 2266 break; |
| 2264 default: | 2267 default: |
| 2265 UNREACHABLE(); | 2268 UNREACHABLE(); |
| 2266 } | 2269 } |
| 2267 } | 2270 } |
| 2268 | 2271 |
| 2269 | 2272 |
| 2273 void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, | |
| 2274 const int32_t& fs_reg, | |
| 2275 const int64_t& fd_reg) { | |
| 2276 float f; | |
| 2277 switch (instr->FunctionFieldRaw()) { | |
| 2278 case CVT_D_S: | |
| 2279 f = get_fpu_register_float(fs_reg); | |
| 2280 set_fpu_register_double(fd_reg, static_cast<double>(f)); | |
| 2281 break; | |
| 2282 default: | |
| 2283 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S | |
| 2284 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. | |
| 2285 UNREACHABLE(); | |
| 2286 } | |
| 2287 } | |
| 2288 | |
| 2289 | |
| 2290 void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, | |
| 2291 const int32_t& fs_reg, | |
| 2292 const int64_t& ft_reg, | |
| 2293 const int32_t& fd_reg) { | |
| 2294 double ft, fs; | |
| 2295 uint32_t cc, fcsr_cc; | |
| 2296 fs = get_fpu_register_double(fs_reg); | |
| 2297 ft = get_fpu_register_double(ft_reg); | |
| 2298 cc = instr->FCccValue(); | |
| 2299 fcsr_cc = get_fcsr_condition_bit(cc); | |
| 2300 int64_t ft_int = static_cast<int64_t>(ft); | |
| 2301 switch (instr->FunctionFieldRaw()) { | |
| 2302 case SELEQZ_C: | |
| 2303 DCHECK(kArchVariant == kMips64r6); | |
| 2304 set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0); | |
| 2305 break; | |
| 2306 case SELNEZ_C: | |
| 2307 DCHECK(kArchVariant == kMips64r6); | |
| 2308 set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0); | |
| 2309 break; | |
| 2310 case ADD_D: | |
| 2311 set_fpu_register_double(fd_reg, fs + ft); | |
| 2312 break; | |
| 2313 case SUB_D: | |
| 2314 set_fpu_register_double(fd_reg, fs - ft); | |
| 2315 break; | |
| 2316 case MUL_D: | |
| 2317 set_fpu_register_double(fd_reg, fs * ft); | |
| 2318 break; | |
| 2319 case DIV_D: | |
| 2320 set_fpu_register_double(fd_reg, fs / ft); | |
| 2321 break; | |
| 2322 case ABS_D: | |
| 2323 set_fpu_register_double(fd_reg, fabs(fs)); | |
| 2324 break; | |
| 2325 case MOV_D: | |
| 2326 set_fpu_register_double(fd_reg, fs); | |
| 2327 break; | |
| 2328 case NEG_D: | |
| 2329 set_fpu_register_double(fd_reg, -fs); | |
| 2330 break; | |
| 2331 case SQRT_D: | |
| 2332 set_fpu_register_double(fd_reg, fast_sqrt(fs)); | |
| 2333 break; | |
| 2334 case C_UN_D: | |
| 2335 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); | |
| 2336 break; | |
| 2337 case C_EQ_D: | |
| 2338 set_fcsr_bit(fcsr_cc, (fs == ft)); | |
| 2339 break; | |
| 2340 case C_UEQ_D: | |
| 2341 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2342 break; | |
| 2343 case C_OLT_D: | |
| 2344 set_fcsr_bit(fcsr_cc, (fs < ft)); | |
| 2345 break; | |
| 2346 case C_ULT_D: | |
| 2347 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2348 break; | |
| 2349 case C_OLE_D: | |
| 2350 set_fcsr_bit(fcsr_cc, (fs <= ft)); | |
| 2351 break; | |
| 2352 case C_ULE_D: | |
| 2353 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2354 break; | |
| 2355 case CVT_W_D: // Convert double to word. | |
| 2356 // Rounding modes are not yet supported. | |
| 2357 DCHECK((FCSR_ & 3) == 0); | |
| 2358 // In rounding mode 0 it should behave like ROUND. | |
| 2359 // No break. | |
| 2360 case ROUND_W_D: // Round double to word (round half to even). | |
| 2361 { | |
| 2362 double rounded = std::floor(fs + 0.5); | |
| 2363 int32_t result = static_cast<int32_t>(rounded); | |
| 2364 if ((result & 1) != 0 && result - fs == 0.5) { | |
| 2365 // If the number is halfway between two integers, | |
| 2366 // round to the even one. | |
| 2367 result--; | |
| 2368 } | |
| 2369 set_fpu_register_word(fd_reg, result); | |
| 2370 if (set_fcsr_round_error(fs, rounded)) { | |
| 2371 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2372 } | |
| 2373 } break; | |
| 2374 case TRUNC_W_D: // Truncate double to word (round towards 0). | |
| 2375 { | |
| 2376 double rounded = trunc(fs); | |
| 2377 int32_t result = static_cast<int32_t>(rounded); | |
| 2378 set_fpu_register_word(fd_reg, result); | |
| 2379 if (set_fcsr_round_error(fs, rounded)) { | |
| 2380 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2381 } | |
| 2382 } break; | |
| 2383 case FLOOR_W_D: // Round double to word towards negative infinity. | |
| 2384 { | |
| 2385 double rounded = std::floor(fs); | |
| 2386 int32_t result = static_cast<int32_t>(rounded); | |
| 2387 set_fpu_register_word(fd_reg, result); | |
| 2388 if (set_fcsr_round_error(fs, rounded)) { | |
| 2389 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2390 } | |
| 2391 } break; | |
| 2392 case CEIL_W_D: // Round double to word towards positive infinity. | |
| 2393 { | |
| 2394 double rounded = std::ceil(fs); | |
| 2395 int32_t result = static_cast<int32_t>(rounded); | |
| 2396 set_fpu_register_word(fd_reg, result); | |
| 2397 if (set_fcsr_round_error(fs, rounded)) { | |
| 2398 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2399 } | |
| 2400 } break; | |
| 2401 case CVT_S_D: // Convert double to float (single). | |
| 2402 set_fpu_register_float(fd_reg, static_cast<float>(fs)); | |
| 2403 break; | |
| 2404 case CVT_L_D: // Mips64r2: Truncate double to 64-bit long-word. | |
| 2405 // Rounding modes are not yet supported. | |
| 2406 DCHECK((FCSR_ & 3) == 0); | |
| 2407 // In rounding mode 0 it should behave like ROUND. | |
| 2408 // No break. | |
| 2409 case ROUND_L_D: { // Mips64r2 instruction. | |
|
paul.l...
2015/03/31 04:02:01
As mentioned in simulator-mips.cc: this is for mip
| |
| 2410 // check error cases | |
| 2411 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); | |
| 2412 int64_t result = static_cast<int64_t>(rounded); | |
| 2413 set_fpu_register(fd_reg, result); | |
| 2414 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2415 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2416 } | |
| 2417 break; | |
| 2418 } | |
| 2419 case TRUNC_L_D: { // Mips64r2 instruction. | |
| 2420 double rounded = trunc(fs); | |
| 2421 int64_t result = static_cast<int64_t>(rounded); | |
| 2422 set_fpu_register(fd_reg, result); | |
| 2423 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2424 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2425 } | |
| 2426 break; | |
| 2427 } | |
| 2428 case FLOOR_L_D: { // Mips64r2 instruction. | |
| 2429 double rounded = floor(fs); | |
| 2430 int64_t result = static_cast<int64_t>(rounded); | |
| 2431 set_fpu_register(fd_reg, result); | |
| 2432 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2433 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2434 } | |
| 2435 break; | |
| 2436 } | |
| 2437 case CEIL_L_D: { // Mips64r2 instruction. | |
| 2438 double rounded = ceil(fs); | |
| 2439 int64_t result = static_cast<int64_t>(rounded); | |
| 2440 set_fpu_register(fd_reg, result); | |
| 2441 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2442 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2443 } | |
| 2444 break; | |
| 2445 } | |
| 2446 case C_F_D: | |
| 2447 UNIMPLEMENTED_MIPS(); | |
| 2448 break; | |
| 2449 default: | |
| 2450 UNREACHABLE(); | |
| 2451 } | |
| 2452 } | |
| 2453 | |
| 2454 | |
| 2455 void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, | |
| 2456 const int32_t& fs_reg, | |
| 2457 const int32_t& fd_reg, | |
| 2458 int64_t& alu_out) { | |
| 2459 switch (instr->FunctionFieldRaw()) { | |
| 2460 case CVT_S_W: // Convert word to float (single). | |
| 2461 alu_out = get_fpu_register_signed_word(fs_reg); | |
| 2462 set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); | |
| 2463 break; | |
| 2464 case CVT_D_W: // Convert word to double. | |
| 2465 alu_out = get_fpu_register_signed_word(fs_reg); | |
| 2466 set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); | |
| 2467 break; | |
| 2468 default: // Mips64r6 CMP.S instructions unimplemented. | |
| 2469 UNREACHABLE(); | |
| 2470 } | |
| 2471 } | |
| 2472 | |
| 2473 | |
| 2474 void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, | |
| 2475 const int32_t& fs_reg, | |
| 2476 const int32_t& fd_reg, | |
| 2477 const int32_t& ft_reg) { | |
| 2478 double fs = get_fpu_register_double(fs_reg); | |
| 2479 double ft = get_fpu_register_double(ft_reg); | |
| 2480 int64_t i64; | |
| 2481 switch (instr->FunctionFieldRaw()) { | |
| 2482 case CVT_D_L: // Mips32r2 instruction. | |
| 2483 i64 = get_fpu_register(fs_reg); | |
| 2484 set_fpu_register_double(fd_reg, static_cast<double>(i64)); | |
| 2485 break; | |
| 2486 case CVT_S_L: | |
| 2487 UNIMPLEMENTED_MIPS(); | |
| 2488 break; | |
| 2489 case CMP_AF: // Mips64r6 CMP.D instructions. | |
| 2490 UNIMPLEMENTED_MIPS(); | |
| 2491 break; | |
| 2492 case CMP_UN: | |
| 2493 if (std::isnan(fs) || std::isnan(ft)) { | |
| 2494 set_fpu_register(fd_reg, -1); | |
| 2495 } else { | |
| 2496 set_fpu_register(fd_reg, 0); | |
| 2497 } | |
| 2498 break; | |
| 2499 case CMP_EQ: | |
| 2500 if (fs == ft) { | |
| 2501 set_fpu_register(fd_reg, -1); | |
| 2502 } else { | |
| 2503 set_fpu_register(fd_reg, 0); | |
| 2504 } | |
| 2505 break; | |
| 2506 case CMP_UEQ: | |
| 2507 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2508 set_fpu_register(fd_reg, -1); | |
| 2509 } else { | |
| 2510 set_fpu_register(fd_reg, 0); | |
| 2511 } | |
| 2512 break; | |
| 2513 case CMP_LT: | |
| 2514 if (fs < ft) { | |
| 2515 set_fpu_register(fd_reg, -1); | |
| 2516 } else { | |
| 2517 set_fpu_register(fd_reg, 0); | |
| 2518 } | |
| 2519 break; | |
| 2520 case CMP_ULT: | |
| 2521 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2522 set_fpu_register(fd_reg, -1); | |
| 2523 } else { | |
| 2524 set_fpu_register(fd_reg, 0); | |
| 2525 } | |
| 2526 break; | |
| 2527 case CMP_LE: | |
| 2528 if (fs <= ft) { | |
| 2529 set_fpu_register(fd_reg, -1); | |
| 2530 } else { | |
| 2531 set_fpu_register(fd_reg, 0); | |
| 2532 } | |
| 2533 break; | |
| 2534 case CMP_ULE: | |
| 2535 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2536 set_fpu_register(fd_reg, -1); | |
| 2537 } else { | |
| 2538 set_fpu_register(fd_reg, 0); | |
| 2539 } | |
| 2540 break; | |
| 2541 default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED | |
| 2542 UNREACHABLE(); | |
| 2543 } | |
| 2544 } | |
| 2545 | |
| 2546 | |
| 2547 void Simulator::DecodeTypeRegisterCOP1( | |
| 2548 Instruction* instr, const int64_t& rs_reg, const int64_t& rs, | |
| 2549 const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt, | |
| 2550 const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg, | |
| 2551 const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg, | |
| 2552 int64_t& alu_out) { | |
| 2553 switch (instr->RsFieldRaw()) { | |
| 2554 case BC1: // Branch on coprocessor condition. | |
| 2555 case BC1EQZ: | |
| 2556 case BC1NEZ: | |
| 2557 UNREACHABLE(); | |
| 2558 break; | |
| 2559 case CFC1: | |
| 2560 set_register(rt_reg, alu_out); | |
| 2561 break; | |
| 2562 case MFC1: | |
| 2563 case DMFC1: | |
| 2564 case MFHC1: | |
| 2565 set_register(rt_reg, alu_out); | |
| 2566 break; | |
| 2567 case CTC1: | |
| 2568 // At the moment only FCSR is supported. | |
| 2569 DCHECK(fs_reg == kFCSRRegister); | |
| 2570 FCSR_ = registers_[rt_reg]; | |
| 2571 break; | |
| 2572 case MTC1: | |
| 2573 // Hardware writes upper 32-bits to zero on mtc1. | |
| 2574 set_fpu_register_hi_word(fs_reg, 0); | |
| 2575 set_fpu_register_word(fs_reg, registers_[rt_reg]); | |
| 2576 break; | |
| 2577 case DMTC1: | |
| 2578 set_fpu_register(fs_reg, registers_[rt_reg]); | |
| 2579 break; | |
| 2580 case MTHC1: | |
| 2581 set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); | |
| 2582 break; | |
| 2583 case S: | |
| 2584 DecodeTypeRegisterSRsType(instr, fs_reg, fd_reg); | |
| 2585 break; | |
| 2586 case D: | |
| 2587 DecodeTypeRegisterDRsType(instr, fs_reg, ft_reg, fd_reg); | |
| 2588 break; | |
| 2589 case W: | |
| 2590 DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, alu_out); | |
| 2591 break; | |
| 2592 case L: | |
| 2593 DecodeTypeRegisterLRsType(instr, fs_reg, fd_reg, ft_reg); | |
| 2594 break; | |
| 2595 default: | |
| 2596 UNREACHABLE(); | |
| 2597 } | |
| 2598 } | |
| 2599 | |
| 2600 | |
| 2601 void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr, | |
| 2602 const int32_t& fr_reg, | |
| 2603 const int32_t& fs_reg, | |
| 2604 const int32_t& ft_reg, | |
| 2605 const int64_t& fd_reg) { | |
| 2606 switch (instr->FunctionFieldRaw()) { | |
| 2607 case MADD_D: | |
| 2608 double fr, ft, fs; | |
| 2609 fr = get_fpu_register_double(fr_reg); | |
| 2610 fs = get_fpu_register_double(fs_reg); | |
| 2611 ft = get_fpu_register_double(ft_reg); | |
| 2612 set_fpu_register_double(fd_reg, fs * ft + fr); | |
| 2613 break; | |
| 2614 default: | |
| 2615 UNREACHABLE(); | |
| 2616 } | |
| 2617 } | |
| 2618 | |
| 2619 | |
| 2620 void Simulator::DecodeTypeRegisterSPECIAL( | |
| 2621 Instruction* instr, const int64_t& rs_reg, const int64_t& rs, | |
| 2622 const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt, | |
| 2623 const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg, | |
| 2624 const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg, | |
| 2625 int64_t& i64hilo, uint64_t& u64hilo, int64_t& alu_out, bool& do_interrupt, | |
| 2626 int64_t& current_pc, int64_t& next_pc, int64_t& return_addr_reg, | |
| 2627 int64_t& i128resultH, int64_t& i128resultL) { | |
| 2628 switch (instr->FunctionFieldRaw()) { | |
| 2629 case SELEQZ_S: | |
| 2630 DCHECK(kArchVariant == kMips64r6); | |
| 2631 set_register(rd_reg, rt == 0 ? rs : 0); | |
| 2632 break; | |
| 2633 case SELNEZ_S: | |
| 2634 DCHECK(kArchVariant == kMips64r6); | |
| 2635 set_register(rd_reg, rt != 0 ? rs : 0); | |
| 2636 break; | |
| 2637 case JR: { | |
| 2638 Instruction* branch_delay_instr = | |
| 2639 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); | |
| 2640 BranchDelayInstructionDecode(branch_delay_instr); | |
| 2641 set_pc(next_pc); | |
| 2642 pc_modified_ = true; | |
| 2643 break; | |
| 2644 } | |
| 2645 case JALR: { | |
| 2646 Instruction* branch_delay_instr = | |
| 2647 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); | |
| 2648 BranchDelayInstructionDecode(branch_delay_instr); | |
| 2649 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize); | |
| 2650 set_pc(next_pc); | |
| 2651 pc_modified_ = true; | |
| 2652 break; | |
| 2653 } | |
| 2654 // Instructions using HI and LO registers. | |
| 2655 case MULT: | |
| 2656 if (kArchVariant != kMips64r6) { | |
| 2657 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); | |
| 2658 set_register(HI, static_cast<int32_t>(i64hilo >> 32)); | |
| 2659 } else { | |
| 2660 switch (instr->SaValue()) { | |
| 2661 case MUL_OP: | |
| 2662 set_register(rd_reg, static_cast<int32_t>(i64hilo & 0xffffffff)); | |
| 2663 break; | |
| 2664 case MUH_OP: | |
| 2665 set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32)); | |
| 2666 break; | |
| 2667 default: | |
| 2668 UNIMPLEMENTED_MIPS(); | |
| 2669 break; | |
| 2670 } | |
| 2671 } | |
| 2672 break; | |
| 2673 case MULTU: | |
| 2674 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); | |
| 2675 set_register(HI, static_cast<int32_t>(u64hilo >> 32)); | |
| 2676 break; | |
| 2677 case DMULT: // DMULT == D_MUL_MUH. | |
| 2678 if (kArchVariant != kMips64r6) { | |
| 2679 set_register(LO, static_cast<int64_t>(i128resultL)); | |
| 2680 set_register(HI, static_cast<int64_t>(i128resultH)); | |
| 2681 } else { | |
| 2682 switch (instr->SaValue()) { | |
| 2683 case MUL_OP: | |
| 2684 set_register(rd_reg, static_cast<int64_t>(i128resultL)); | |
| 2685 break; | |
| 2686 case MUH_OP: | |
| 2687 set_register(rd_reg, static_cast<int64_t>(i128resultH)); | |
| 2688 break; | |
| 2689 default: | |
| 2690 UNIMPLEMENTED_MIPS(); | |
| 2691 break; | |
| 2692 } | |
| 2693 } | |
| 2694 break; | |
| 2695 case DMULTU: | |
| 2696 UNIMPLEMENTED_MIPS(); | |
| 2697 break; | |
| 2698 case DSLL: | |
| 2699 set_register(rd_reg, alu_out); | |
| 2700 break; | |
| 2701 case DIV: | |
| 2702 case DDIV: | |
| 2703 switch (kArchVariant) { | |
| 2704 case kMips64r2: | |
| 2705 // Divide by zero and overflow was not checked in the | |
| 2706 // configuration step - div and divu do not raise exceptions. On | |
| 2707 // division by 0 the result will be UNPREDICTABLE. On overflow | |
| 2708 // (INT_MIN/-1), return INT_MIN which is what the hardware does. | |
| 2709 if (rs == INT_MIN && rt == -1) { | |
| 2710 set_register(LO, INT_MIN); | |
| 2711 set_register(HI, 0); | |
| 2712 } else if (rt != 0) { | |
| 2713 set_register(LO, rs / rt); | |
| 2714 set_register(HI, rs % rt); | |
| 2715 } | |
| 2716 break; | |
| 2717 case kMips64r6: | |
| 2718 switch (instr->SaValue()) { | |
| 2719 case DIV_OP: | |
| 2720 if (rs == INT_MIN && rt == -1) { | |
| 2721 set_register(rd_reg, INT_MIN); | |
| 2722 } else if (rt != 0) { | |
| 2723 set_register(rd_reg, rs / rt); | |
| 2724 } | |
| 2725 break; | |
| 2726 case MOD_OP: | |
| 2727 if (rs == INT_MIN && rt == -1) { | |
| 2728 set_register(rd_reg, 0); | |
| 2729 } else if (rt != 0) { | |
| 2730 set_register(rd_reg, rs % rt); | |
| 2731 } | |
| 2732 break; | |
| 2733 default: | |
| 2734 UNIMPLEMENTED_MIPS(); | |
| 2735 break; | |
| 2736 } | |
| 2737 break; | |
| 2738 default: | |
| 2739 break; | |
| 2740 } | |
| 2741 break; | |
| 2742 case DIVU: | |
| 2743 if (rt_u != 0) { | |
| 2744 set_register(LO, rs_u / rt_u); | |
| 2745 set_register(HI, rs_u % rt_u); | |
| 2746 } | |
| 2747 break; | |
| 2748 // Break and trap instructions. | |
| 2749 case BREAK: | |
| 2750 case TGE: | |
| 2751 case TGEU: | |
| 2752 case TLT: | |
| 2753 case TLTU: | |
| 2754 case TEQ: | |
| 2755 case TNE: | |
| 2756 if (do_interrupt) { | |
| 2757 SoftwareInterrupt(instr); | |
| 2758 } | |
| 2759 break; | |
| 2760 // Conditional moves. | |
| 2761 case MOVN: | |
| 2762 if (rt) { | |
| 2763 set_register(rd_reg, rs); | |
| 2764 TraceRegWr(rs); | |
| 2765 } | |
| 2766 break; | |
| 2767 case MOVCI: { | |
| 2768 uint32_t cc = instr->FBccValue(); | |
| 2769 uint32_t fcsr_cc = get_fcsr_condition_bit(cc); | |
| 2770 if (instr->Bit(16)) { // Read Tf bit. | |
| 2771 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | |
| 2772 } else { | |
| 2773 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | |
| 2774 } | |
| 2775 break; | |
| 2776 } | |
| 2777 case MOVZ: | |
| 2778 if (!rt) { | |
| 2779 set_register(rd_reg, rs); | |
| 2780 TraceRegWr(rs); | |
| 2781 } | |
| 2782 break; | |
| 2783 default: // For other special opcodes we do the default operation. | |
| 2784 set_register(rd_reg, alu_out); | |
| 2785 TraceRegWr(alu_out); | |
| 2786 } | |
| 2787 } | |
| 2788 | |
| 2789 | |
| 2790 void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr, | |
| 2791 const int64_t& rd_reg, | |
| 2792 int64_t& alu_out) { | |
| 2793 switch (instr->FunctionFieldRaw()) { | |
| 2794 case MUL: | |
| 2795 set_register(rd_reg, alu_out); | |
| 2796 TraceRegWr(alu_out); | |
| 2797 // HI and LO are UNPREDICTABLE after the operation. | |
| 2798 set_register(LO, Unpredictable); | |
| 2799 set_register(HI, Unpredictable); | |
| 2800 break; | |
| 2801 default: // For other special2 opcodes we do the default operation. | |
| 2802 set_register(rd_reg, alu_out); | |
| 2803 } | |
| 2804 } | |
| 2805 | |
| 2806 | |
| 2807 void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr, | |
| 2808 const int64_t& rt_reg, | |
| 2809 int64_t& alu_out) { | |
| 2810 switch (instr->FunctionFieldRaw()) { | |
| 2811 case INS: | |
| 2812 // Ins instr leaves result in Rt, rather than Rd. | |
| 2813 set_register(rt_reg, alu_out); | |
| 2814 TraceRegWr(alu_out); | |
| 2815 break; | |
| 2816 case EXT: | |
| 2817 case DEXT: | |
| 2818 // Dext/Ext instr leaves result in Rt, rather than Rd. | |
| 2819 set_register(rt_reg, alu_out); | |
| 2820 TraceRegWr(alu_out); | |
| 2821 break; | |
| 2822 default: | |
| 2823 UNREACHABLE(); | |
| 2824 } | |
| 2825 } | |
| 2826 | |
| 2827 | |
| 2270 void Simulator::DecodeTypeRegister(Instruction* instr) { | 2828 void Simulator::DecodeTypeRegister(Instruction* instr) { |
| 2271 // Instruction fields. | 2829 // Instruction fields. |
| 2272 const Opcode op = instr->OpcodeFieldRaw(); | 2830 const Opcode op = instr->OpcodeFieldRaw(); |
| 2273 const int64_t rs_reg = instr->RsValue(); | 2831 const int64_t rs_reg = instr->RsValue(); |
| 2274 const int64_t rs = get_register(rs_reg); | 2832 const int64_t rs = get_register(rs_reg); |
| 2275 const uint64_t rs_u = static_cast<uint32_t>(rs); | 2833 const uint64_t rs_u = static_cast<uint32_t>(rs); |
| 2276 const int64_t rt_reg = instr->RtValue(); | 2834 const int64_t rt_reg = instr->RtValue(); |
| 2277 const int64_t rt = get_register(rt_reg); | 2835 const int64_t rt = get_register(rt_reg); |
| 2278 const uint64_t rt_u = static_cast<uint32_t>(rt); | 2836 const uint64_t rt_u = static_cast<uint32_t>(rt); |
| 2279 const int64_t rd_reg = instr->RdValue(); | 2837 const int64_t rd_reg = instr->RdValue(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2313 &do_interrupt, | 2871 &do_interrupt, |
| 2314 &i128resultH, | 2872 &i128resultH, |
| 2315 &i128resultL); | 2873 &i128resultL); |
| 2316 | 2874 |
| 2317 // ---------- Raise exceptions triggered. | 2875 // ---------- Raise exceptions triggered. |
| 2318 SignalExceptions(); | 2876 SignalExceptions(); |
| 2319 | 2877 |
| 2320 // ---------- Execution. | 2878 // ---------- Execution. |
| 2321 switch (op) { | 2879 switch (op) { |
| 2322 case COP1: | 2880 case COP1: |
| 2323 switch (instr->RsFieldRaw()) { | 2881 DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, |
| 2324 case BC1: // Branch on coprocessor condition. | 2882 fr_reg, fs_reg, ft_reg, fd_reg, alu_out); |
| 2325 case BC1EQZ: | |
| 2326 case BC1NEZ: | |
| 2327 UNREACHABLE(); | |
| 2328 break; | |
| 2329 case CFC1: | |
| 2330 set_register(rt_reg, alu_out); | |
| 2331 break; | |
| 2332 case MFC1: | |
| 2333 case DMFC1: | |
| 2334 case MFHC1: | |
| 2335 set_register(rt_reg, alu_out); | |
| 2336 break; | |
| 2337 case CTC1: | |
| 2338 // At the moment only FCSR is supported. | |
| 2339 DCHECK(fs_reg == kFCSRRegister); | |
| 2340 FCSR_ = registers_[rt_reg]; | |
| 2341 break; | |
| 2342 case MTC1: | |
| 2343 // Hardware writes upper 32-bits to zero on mtc1. | |
| 2344 set_fpu_register_hi_word(fs_reg, 0); | |
| 2345 set_fpu_register_word(fs_reg, registers_[rt_reg]); | |
| 2346 break; | |
| 2347 case DMTC1: | |
| 2348 set_fpu_register(fs_reg, registers_[rt_reg]); | |
| 2349 break; | |
| 2350 case MTHC1: | |
| 2351 set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); | |
| 2352 break; | |
| 2353 case S: | |
| 2354 float f; | |
| 2355 switch (instr->FunctionFieldRaw()) { | |
| 2356 case CVT_D_S: | |
| 2357 f = get_fpu_register_float(fs_reg); | |
| 2358 set_fpu_register_double(fd_reg, static_cast<double>(f)); | |
| 2359 break; | |
| 2360 default: | |
| 2361 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S | |
| 2362 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. | |
| 2363 UNREACHABLE(); | |
| 2364 } | |
| 2365 break; | |
| 2366 case D: | |
| 2367 double ft, fs; | |
| 2368 uint32_t cc, fcsr_cc; | |
| 2369 int64_t i64; | |
| 2370 fs = get_fpu_register_double(fs_reg); | |
| 2371 ft = get_fpu_register_double(ft_reg); | |
| 2372 cc = instr->FCccValue(); | |
| 2373 fcsr_cc = get_fcsr_condition_bit(cc); | |
| 2374 switch (instr->FunctionFieldRaw()) { | |
| 2375 case ADD_D: | |
| 2376 set_fpu_register_double(fd_reg, fs + ft); | |
| 2377 break; | |
| 2378 case SUB_D: | |
| 2379 set_fpu_register_double(fd_reg, fs - ft); | |
| 2380 break; | |
| 2381 case MUL_D: | |
| 2382 set_fpu_register_double(fd_reg, fs * ft); | |
| 2383 break; | |
| 2384 case DIV_D: | |
| 2385 set_fpu_register_double(fd_reg, fs / ft); | |
| 2386 break; | |
| 2387 case ABS_D: | |
| 2388 set_fpu_register_double(fd_reg, fabs(fs)); | |
| 2389 break; | |
| 2390 case MOV_D: | |
| 2391 set_fpu_register_double(fd_reg, fs); | |
| 2392 break; | |
| 2393 case NEG_D: | |
| 2394 set_fpu_register_double(fd_reg, -fs); | |
| 2395 break; | |
| 2396 case SQRT_D: | |
| 2397 set_fpu_register_double(fd_reg, fast_sqrt(fs)); | |
| 2398 break; | |
| 2399 case C_UN_D: | |
| 2400 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); | |
| 2401 break; | |
| 2402 case C_EQ_D: | |
| 2403 set_fcsr_bit(fcsr_cc, (fs == ft)); | |
| 2404 break; | |
| 2405 case C_UEQ_D: | |
| 2406 set_fcsr_bit(fcsr_cc, | |
| 2407 (fs == ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2408 break; | |
| 2409 case C_OLT_D: | |
| 2410 set_fcsr_bit(fcsr_cc, (fs < ft)); | |
| 2411 break; | |
| 2412 case C_ULT_D: | |
| 2413 set_fcsr_bit(fcsr_cc, | |
| 2414 (fs < ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2415 break; | |
| 2416 case C_OLE_D: | |
| 2417 set_fcsr_bit(fcsr_cc, (fs <= ft)); | |
| 2418 break; | |
| 2419 case C_ULE_D: | |
| 2420 set_fcsr_bit(fcsr_cc, | |
| 2421 (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); | |
| 2422 break; | |
| 2423 case CVT_W_D: // Convert double to word. | |
| 2424 // Rounding modes are not yet supported. | |
| 2425 DCHECK((FCSR_ & 3) == 0); | |
| 2426 // In rounding mode 0 it should behave like ROUND. | |
| 2427 // No break. | |
| 2428 case ROUND_W_D: // Round double to word (round half to even). | |
| 2429 { | |
| 2430 double rounded = std::floor(fs + 0.5); | |
| 2431 int32_t result = static_cast<int32_t>(rounded); | |
| 2432 if ((result & 1) != 0 && result - fs == 0.5) { | |
| 2433 // If the number is halfway between two integers, | |
| 2434 // round to the even one. | |
| 2435 result--; | |
| 2436 } | |
| 2437 set_fpu_register_word(fd_reg, result); | |
| 2438 if (set_fcsr_round_error(fs, rounded)) { | |
| 2439 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2440 } | |
| 2441 } | |
| 2442 break; | |
| 2443 case TRUNC_W_D: // Truncate double to word (round towards 0). | |
| 2444 { | |
| 2445 double rounded = trunc(fs); | |
| 2446 int32_t result = static_cast<int32_t>(rounded); | |
| 2447 set_fpu_register_word(fd_reg, result); | |
| 2448 if (set_fcsr_round_error(fs, rounded)) { | |
| 2449 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2450 } | |
| 2451 } | |
| 2452 break; | |
| 2453 case FLOOR_W_D: // Round double to word towards negative infinity. | |
| 2454 { | |
| 2455 double rounded = std::floor(fs); | |
| 2456 int32_t result = static_cast<int32_t>(rounded); | |
| 2457 set_fpu_register_word(fd_reg, result); | |
| 2458 if (set_fcsr_round_error(fs, rounded)) { | |
| 2459 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2460 } | |
| 2461 } | |
| 2462 break; | |
| 2463 case CEIL_W_D: // Round double to word towards positive infinity. | |
| 2464 { | |
| 2465 double rounded = std::ceil(fs); | |
| 2466 int32_t result = static_cast<int32_t>(rounded); | |
| 2467 set_fpu_register_word(fd_reg, result); | |
| 2468 if (set_fcsr_round_error(fs, rounded)) { | |
| 2469 set_fpu_register(fd_reg, kFPUInvalidResult); | |
| 2470 } | |
| 2471 } | |
| 2472 break; | |
| 2473 case CVT_S_D: // Convert double to float (single). | |
| 2474 set_fpu_register_float(fd_reg, static_cast<float>(fs)); | |
| 2475 break; | |
| 2476 case CVT_L_D: // Mips64r2: Truncate double to 64-bit long-word. | |
| 2477 // Rounding modes are not yet supported. | |
| 2478 DCHECK((FCSR_ & 3) == 0); | |
| 2479 // In rounding mode 0 it should behave like ROUND. | |
| 2480 // No break. | |
| 2481 case ROUND_L_D: { // Mips64r2 instruction. | |
| 2482 // check error cases | |
| 2483 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); | |
| 2484 int64_t result = static_cast<int64_t>(rounded); | |
| 2485 set_fpu_register(fd_reg, result); | |
| 2486 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2487 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2488 } | |
| 2489 break; | |
| 2490 } | |
| 2491 case TRUNC_L_D: { // Mips64r2 instruction. | |
| 2492 double rounded = trunc(fs); | |
| 2493 int64_t result = static_cast<int64_t>(rounded); | |
| 2494 set_fpu_register(fd_reg, result); | |
| 2495 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2496 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2497 } | |
| 2498 break; | |
| 2499 } | |
| 2500 case FLOOR_L_D: { // Mips64r2 instruction. | |
| 2501 double rounded = floor(fs); | |
| 2502 int64_t result = static_cast<int64_t>(rounded); | |
| 2503 set_fpu_register(fd_reg, result); | |
| 2504 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2505 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2506 } | |
| 2507 break; | |
| 2508 } | |
| 2509 case CEIL_L_D: { // Mips64r2 instruction. | |
| 2510 double rounded = ceil(fs); | |
| 2511 int64_t result = static_cast<int64_t>(rounded); | |
| 2512 set_fpu_register(fd_reg, result); | |
| 2513 if (set_fcsr_round64_error(fs, rounded)) { | |
| 2514 set_fpu_register(fd_reg, kFPU64InvalidResult); | |
| 2515 } | |
| 2516 break; | |
| 2517 } | |
| 2518 case C_F_D: | |
| 2519 UNIMPLEMENTED_MIPS(); | |
| 2520 break; | |
| 2521 default: | |
| 2522 UNREACHABLE(); | |
| 2523 } | |
| 2524 break; | |
| 2525 case W: | |
| 2526 switch (instr->FunctionFieldRaw()) { | |
| 2527 case CVT_S_W: // Convert word to float (single). | |
| 2528 alu_out = get_fpu_register_signed_word(fs_reg); | |
| 2529 set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); | |
| 2530 break; | |
| 2531 case CVT_D_W: // Convert word to double. | |
| 2532 alu_out = get_fpu_register_signed_word(fs_reg); | |
| 2533 set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); | |
| 2534 break; | |
| 2535 default: // Mips64r6 CMP.S instructions unimplemented. | |
| 2536 UNREACHABLE(); | |
| 2537 } | |
| 2538 break; | |
| 2539 case L: | |
| 2540 fs = get_fpu_register_double(fs_reg); | |
| 2541 ft = get_fpu_register_double(ft_reg); | |
| 2542 switch (instr->FunctionFieldRaw()) { | |
| 2543 case CVT_D_L: // Mips32r2 instruction. | |
| 2544 i64 = get_fpu_register(fs_reg); | |
| 2545 set_fpu_register_double(fd_reg, static_cast<double>(i64)); | |
| 2546 break; | |
| 2547 case CVT_S_L: | |
| 2548 UNIMPLEMENTED_MIPS(); | |
| 2549 break; | |
| 2550 case CMP_AF: // Mips64r6 CMP.D instructions. | |
| 2551 UNIMPLEMENTED_MIPS(); | |
| 2552 break; | |
| 2553 case CMP_UN: | |
| 2554 if (std::isnan(fs) || std::isnan(ft)) { | |
| 2555 set_fpu_register(fd_reg, -1); | |
| 2556 } else { | |
| 2557 set_fpu_register(fd_reg, 0); | |
| 2558 } | |
| 2559 break; | |
| 2560 case CMP_EQ: | |
| 2561 if (fs == ft) { | |
| 2562 set_fpu_register(fd_reg, -1); | |
| 2563 } else { | |
| 2564 set_fpu_register(fd_reg, 0); | |
| 2565 } | |
| 2566 break; | |
| 2567 case CMP_UEQ: | |
| 2568 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2569 set_fpu_register(fd_reg, -1); | |
| 2570 } else { | |
| 2571 set_fpu_register(fd_reg, 0); | |
| 2572 } | |
| 2573 break; | |
| 2574 case CMP_LT: | |
| 2575 if (fs < ft) { | |
| 2576 set_fpu_register(fd_reg, -1); | |
| 2577 } else { | |
| 2578 set_fpu_register(fd_reg, 0); | |
| 2579 } | |
| 2580 break; | |
| 2581 case CMP_ULT: | |
| 2582 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2583 set_fpu_register(fd_reg, -1); | |
| 2584 } else { | |
| 2585 set_fpu_register(fd_reg, 0); | |
| 2586 } | |
| 2587 break; | |
| 2588 case CMP_LE: | |
| 2589 if (fs <= ft) { | |
| 2590 set_fpu_register(fd_reg, -1); | |
| 2591 } else { | |
| 2592 set_fpu_register(fd_reg, 0); | |
| 2593 } | |
| 2594 break; | |
| 2595 case CMP_ULE: | |
| 2596 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { | |
| 2597 set_fpu_register(fd_reg, -1); | |
| 2598 } else { | |
| 2599 set_fpu_register(fd_reg, 0); | |
| 2600 } | |
| 2601 break; | |
| 2602 default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED | |
| 2603 UNREACHABLE(); | |
| 2604 } | |
| 2605 break; | |
| 2606 default: | |
| 2607 UNREACHABLE(); | |
| 2608 } | |
| 2609 break; | 2883 break; |
| 2610 case COP1X: | 2884 case COP1X: |
| 2611 switch (instr->FunctionFieldRaw()) { | 2885 DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg); |
| 2612 case MADD_D: | |
| 2613 double fr, ft, fs; | |
| 2614 fr = get_fpu_register_double(fr_reg); | |
| 2615 fs = get_fpu_register_double(fs_reg); | |
| 2616 ft = get_fpu_register_double(ft_reg); | |
| 2617 set_fpu_register_double(fd_reg, fs * ft + fr); | |
| 2618 break; | |
| 2619 default: | |
| 2620 UNREACHABLE(); | |
| 2621 } | |
| 2622 break; | 2886 break; |
| 2623 case SPECIAL: | 2887 case SPECIAL: |
| 2624 switch (instr->FunctionFieldRaw()) { | 2888 DecodeTypeRegisterSPECIAL( |
| 2625 case JR: { | 2889 instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, fr_reg, fs_reg, |
| 2626 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | 2890 ft_reg, fd_reg, i64hilo, u64hilo, alu_out, do_interrupt, current_pc, |
| 2627 current_pc+Instruction::kInstrSize); | 2891 next_pc, return_addr_reg, i128resultH, i128resultL); |
| 2628 BranchDelayInstructionDecode(branch_delay_instr); | |
| 2629 set_pc(next_pc); | |
| 2630 pc_modified_ = true; | |
| 2631 break; | |
| 2632 } | |
| 2633 case JALR: { | |
| 2634 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | |
| 2635 current_pc+Instruction::kInstrSize); | |
| 2636 BranchDelayInstructionDecode(branch_delay_instr); | |
| 2637 set_register(return_addr_reg, | |
| 2638 current_pc + 2 * Instruction::kInstrSize); | |
| 2639 set_pc(next_pc); | |
| 2640 pc_modified_ = true; | |
| 2641 break; | |
| 2642 } | |
| 2643 // Instructions using HI and LO registers. | |
| 2644 case MULT: | |
| 2645 if (kArchVariant != kMips64r6) { | |
| 2646 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); | |
| 2647 set_register(HI, static_cast<int32_t>(i64hilo >> 32)); | |
| 2648 } else { | |
| 2649 switch (instr->SaValue()) { | |
| 2650 case MUL_OP: | |
| 2651 set_register(rd_reg, | |
| 2652 static_cast<int32_t>(i64hilo & 0xffffffff)); | |
| 2653 break; | |
| 2654 case MUH_OP: | |
| 2655 set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32)); | |
| 2656 break; | |
| 2657 default: | |
| 2658 UNIMPLEMENTED_MIPS(); | |
| 2659 break; | |
| 2660 } | |
| 2661 } | |
| 2662 break; | |
| 2663 case MULTU: | |
| 2664 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); | |
| 2665 set_register(HI, static_cast<int32_t>(u64hilo >> 32)); | |
| 2666 break; | |
| 2667 case DMULT: // DMULT == D_MUL_MUH. | |
| 2668 if (kArchVariant != kMips64r6) { | |
| 2669 set_register(LO, static_cast<int64_t>(i128resultL)); | |
| 2670 set_register(HI, static_cast<int64_t>(i128resultH)); | |
| 2671 } else { | |
| 2672 switch (instr->SaValue()) { | |
| 2673 case MUL_OP: | |
| 2674 set_register(rd_reg, static_cast<int64_t>(i128resultL)); | |
| 2675 break; | |
| 2676 case MUH_OP: | |
| 2677 set_register(rd_reg, static_cast<int64_t>(i128resultH)); | |
| 2678 break; | |
| 2679 default: | |
| 2680 UNIMPLEMENTED_MIPS(); | |
| 2681 break; | |
| 2682 } | |
| 2683 } | |
| 2684 break; | |
| 2685 case DMULTU: | |
| 2686 UNIMPLEMENTED_MIPS(); | |
| 2687 break; | |
| 2688 case DSLL: | |
| 2689 set_register(rd_reg, alu_out); | |
| 2690 break; | |
| 2691 case DIV: | |
| 2692 case DDIV: | |
| 2693 switch (kArchVariant) { | |
| 2694 case kMips64r2: | |
| 2695 // Divide by zero and overflow was not checked in the | |
| 2696 // configuration step - div and divu do not raise exceptions. On | |
| 2697 // division by 0 the result will be UNPREDICTABLE. On overflow | |
| 2698 // (INT_MIN/-1), return INT_MIN which is what the hardware does. | |
| 2699 if (rs == INT_MIN && rt == -1) { | |
| 2700 set_register(LO, INT_MIN); | |
| 2701 set_register(HI, 0); | |
| 2702 } else if (rt != 0) { | |
| 2703 set_register(LO, rs / rt); | |
| 2704 set_register(HI, rs % rt); | |
| 2705 } | |
| 2706 break; | |
| 2707 case kMips64r6: | |
| 2708 switch (instr->SaValue()) { | |
| 2709 case DIV_OP: | |
| 2710 if (rs == INT_MIN && rt == -1) { | |
| 2711 set_register(rd_reg, INT_MIN); | |
| 2712 } else if (rt != 0) { | |
| 2713 set_register(rd_reg, rs / rt); | |
| 2714 } | |
| 2715 break; | |
| 2716 case MOD_OP: | |
| 2717 if (rs == INT_MIN && rt == -1) { | |
| 2718 set_register(rd_reg, 0); | |
| 2719 } else if (rt != 0) { | |
| 2720 set_register(rd_reg, rs % rt); | |
| 2721 } | |
| 2722 break; | |
| 2723 default: | |
| 2724 UNIMPLEMENTED_MIPS(); | |
| 2725 break; | |
| 2726 } | |
| 2727 break; | |
| 2728 default: | |
| 2729 break; | |
| 2730 } | |
| 2731 break; | |
| 2732 case DIVU: | |
| 2733 if (rt_u != 0) { | |
| 2734 set_register(LO, rs_u / rt_u); | |
| 2735 set_register(HI, rs_u % rt_u); | |
| 2736 } | |
| 2737 break; | |
| 2738 // Break and trap instructions. | |
| 2739 case BREAK: | |
| 2740 case TGE: | |
| 2741 case TGEU: | |
| 2742 case TLT: | |
| 2743 case TLTU: | |
| 2744 case TEQ: | |
| 2745 case TNE: | |
| 2746 if (do_interrupt) { | |
| 2747 SoftwareInterrupt(instr); | |
| 2748 } | |
| 2749 break; | |
| 2750 // Conditional moves. | |
| 2751 case MOVN: | |
| 2752 if (rt) { | |
| 2753 set_register(rd_reg, rs); | |
| 2754 TraceRegWr(rs); | |
| 2755 } | |
| 2756 break; | |
| 2757 case MOVCI: { | |
| 2758 uint32_t cc = instr->FBccValue(); | |
| 2759 uint32_t fcsr_cc = get_fcsr_condition_bit(cc); | |
| 2760 if (instr->Bit(16)) { // Read Tf bit. | |
| 2761 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | |
| 2762 } else { | |
| 2763 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | |
| 2764 } | |
| 2765 break; | |
| 2766 } | |
| 2767 case MOVZ: | |
| 2768 if (!rt) { | |
| 2769 set_register(rd_reg, rs); | |
| 2770 TraceRegWr(rs); | |
| 2771 } | |
| 2772 break; | |
| 2773 default: // For other special opcodes we do the default operation. | |
| 2774 set_register(rd_reg, alu_out); | |
| 2775 TraceRegWr(alu_out); | |
| 2776 } | |
| 2777 break; | 2892 break; |
| 2778 case SPECIAL2: | 2893 case SPECIAL2: |
| 2779 switch (instr->FunctionFieldRaw()) { | 2894 DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out); |
| 2780 case MUL: | |
| 2781 set_register(rd_reg, alu_out); | |
| 2782 TraceRegWr(alu_out); | |
| 2783 // HI and LO are UNPREDICTABLE after the operation. | |
| 2784 set_register(LO, Unpredictable); | |
| 2785 set_register(HI, Unpredictable); | |
| 2786 break; | |
| 2787 default: // For other special2 opcodes we do the default operation. | |
| 2788 set_register(rd_reg, alu_out); | |
| 2789 } | |
| 2790 break; | 2895 break; |
| 2791 case SPECIAL3: | 2896 case SPECIAL3: |
| 2792 switch (instr->FunctionFieldRaw()) { | 2897 DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out); |
| 2793 case INS: | |
| 2794 // Ins instr leaves result in Rt, rather than Rd. | |
| 2795 set_register(rt_reg, alu_out); | |
| 2796 TraceRegWr(alu_out); | |
| 2797 break; | |
| 2798 case EXT: | |
| 2799 case DEXT: | |
| 2800 // Dext/Ext instr leaves result in Rt, rather than Rd. | |
| 2801 set_register(rt_reg, alu_out); | |
| 2802 TraceRegWr(alu_out); | |
| 2803 break; | |
| 2804 default: | |
| 2805 UNREACHABLE(); | |
| 2806 } | |
| 2807 break; | 2898 break; |
| 2808 // Unimplemented opcodes raised an error in the configuration step before, | 2899 // Unimplemented opcodes raised an error in the configuration step before, |
| 2809 // so we can use the default here to set the destination register in common | 2900 // so we can use the default here to set the destination register in common |
| 2810 // cases. | 2901 // cases. |
| 2811 default: | 2902 default: |
| 2812 set_register(rd_reg, alu_out); | 2903 set_register(rd_reg, alu_out); |
| 2813 TraceRegWr(alu_out); | 2904 TraceRegWr(alu_out); |
| 2814 } | 2905 } |
| 2815 } | 2906 } |
| 2816 | 2907 |
| (...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3450 } | 3541 } |
| 3451 | 3542 |
| 3452 | 3543 |
| 3453 #undef UNSUPPORTED | 3544 #undef UNSUPPORTED |
| 3454 | 3545 |
| 3455 } } // namespace v8::internal | 3546 } } // namespace v8::internal |
| 3456 | 3547 |
| 3457 #endif // USE_SIMULATOR | 3548 #endif // USE_SIMULATOR |
| 3458 | 3549 |
| 3459 #endif // V8_TARGET_ARCH_MIPS64 | 3550 #endif // V8_TARGET_ARCH_MIPS64 |
| OLD | NEW |