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 3 // found in the LICENSE file. 4 5 #include <limits.h> 6 #include <stdarg.h> 7 #include <stdlib.h> 8 #include <cmath> 9 10 #if V8_TARGET_ARCH_MIPS 11 12 #include "src/assembler.h" 13 #include "src/base/bits.h" 14 #include "src/codegen.h" 15 #include "src/disasm.h" 16 #include "src/mips/constants-mips.h" 17 #include "src/mips/simulator-mips.h" 18 #include "src/ostreams.h" 19 20 21 // Only build the simulator if not compiling for real MIPS hardware. 22 #if defined(USE_SIMULATOR) 23 24 namespace v8 { 25 namespace internal { 26 27 // Utils functions. 28 bool HaveSameSign(int32_t a, int32_t b) { 29 return ((a ^ b) >= 0); 30 } 31 32 33 uint32_t get_fcsr_condition_bit(uint32_t cc) { 34 if (cc == 0) { 35 return 23; 36 } else { 37 return 24 + cc; 38 } 39 } 40 41 42 // This macro provides a platform independent use of sscanf. The reason for 43 // SScanF not being implemented in a platform independent was through 44 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time 45 // Library does not provide vsscanf. 46 #define SScanF sscanf // NOLINT 47 48 // The MipsDebugger class is used by the simulator while debugging simulated 49 // code. 50 class MipsDebugger { 51 public: 52 explicit MipsDebugger(Simulator* sim) : sim_(sim) { } 53 ~MipsDebugger(); 54 55 void Stop(Instruction* instr); 56 void Debug(); 57 // Print all registers with a nice formatting. 58 void PrintAllRegs(); 59 void PrintAllRegsIncludingFPU(); 60 61 private: 62 // We set the breakpoint code to 0xfffff to easily recognize it. 63 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6; 64 static const Instr kNopInstr = 0x0; 65 66 Simulator* sim_; 67 68 int32_t GetRegisterValue(int regnum); 69 int32_t GetFPURegisterValue32(int regnum); 70 int64_t GetFPURegisterValue64(int regnum); 71 float GetFPURegisterValueFloat(int regnum); 72 double GetFPURegisterValueDouble(int regnum); 73 bool GetValue(const char* desc, int32_t* value); 74 bool GetValue(const char* desc, int64_t* value); 75 76 // Set or delete a breakpoint. Returns true if successful. 77 bool SetBreakpoint(Instruction* breakpc); 78 bool DeleteBreakpoint(Instruction* breakpc); 79 80 // Undo and redo all breakpoints. This is needed to bracket disassembly and 81 // execution to skip past breakpoints when run from the debugger. 82 void UndoBreakpoints(); 83 void RedoBreakpoints(); 84 }; 85 86 87 MipsDebugger::~MipsDebugger() { 88 } 89 90 91 #ifdef GENERATED_CODE_COVERAGE 92 static FILE* coverage_log = NULL; 93 94 95 static void InitializeCoverage() { 96 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); 97 if (file_name != NULL) { 98 coverage_log = fopen(file_name, "aw+"); 99 } 100 } 101 102 103 void MipsDebugger::Stop(Instruction* instr) { 104 // Get the stop code. 105 uint32_t code = instr->Bits(25, 6); 106 // Retrieve the encoded address, which comes just after this stop. 107 char** msg_address = 108 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize); 109 char* msg = *msg_address; 110 DCHECK(msg != NULL); 111 112 // Update this stop description. 113 if (!watched_stops_[code].desc) { 114 watched_stops_[code].desc = msg; 115 } 116 117 if (strlen(msg) > 0) { 118 if (coverage_log != NULL) { 119 fprintf(coverage_log, "%s\n", str); 120 fflush(coverage_log); 121 } 122 // Overwrite the instruction and address with nops. 123 instr->SetInstructionBits(kNopInstr); 124 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr); 125 } 126 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize); 127 } 128 129 130 #else // GENERATED_CODE_COVERAGE 131 132 #define UNSUPPORTED() printf("Sim: Unsupported instruction.\n"); 133 134 static void InitializeCoverage() {} 135 136 137 void MipsDebugger::Stop(Instruction* instr) { 138 // Get the stop code. 139 uint32_t code = instr->Bits(25, 6); 140 // Retrieve the encoded address, which comes just after this stop. 141 char* msg = *reinterpret_cast<char**>(sim_->get_pc() + 142 Instruction::kInstrSize); 143 // Update this stop description. 144 if (!sim_->watched_stops_[code].desc) { 145 sim_->watched_stops_[code].desc = msg; 146 } 147 PrintF("Simulator hit %s (%u)\n", msg, code); 148 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize); 149 Debug(); 150 } 151 #endif // GENERATED_CODE_COVERAGE 152 153 154 int32_t MipsDebugger::GetRegisterValue(int regnum) { 155 if (regnum == kNumSimuRegisters) { 156 return sim_->get_pc(); 157 } else { 158 return sim_->get_register(regnum); 159 } 160 } 161 162 163 int32_t MipsDebugger::GetFPURegisterValue32(int regnum) { 164 if (regnum == kNumFPURegisters) { 165 return sim_->get_pc(); 166 } else { 167 return sim_->get_fpu_register_word(regnum); 168 } 169 } 170 171 172 int64_t MipsDebugger::GetFPURegisterValue64(int regnum) { 173 if (regnum == kNumFPURegisters) { 174 return sim_->get_pc(); 175 } else { 176 return sim_->get_fpu_register(regnum); 177 } 178 } 179 180 181 float MipsDebugger::GetFPURegisterValueFloat(int regnum) { 182 if (regnum == kNumFPURegisters) { 183 return sim_->get_pc(); 184 } else { 185 return sim_->get_fpu_register_float(regnum); 186 } 187 } 188 189 190 double MipsDebugger::GetFPURegisterValueDouble(int regnum) { 191 if (regnum == kNumFPURegisters) { 192 return sim_->get_pc(); 193 } else { 194 return sim_->get_fpu_register_double(regnum); 195 } 196 } 197 198 199 bool MipsDebugger::GetValue(const char* desc, int32_t* value) { 200 int regnum = Registers::Number(desc); 201 int fpuregnum = FPURegisters::Number(desc); 202 203 if (regnum != kInvalidRegister) { 204 *value = GetRegisterValue(regnum); 205 return true; 206 } else if (fpuregnum != kInvalidFPURegister) { 207 *value = GetFPURegisterValue32(fpuregnum); 208 return true; 209 } else if (strncmp(desc, "0x", 2) == 0) { 210 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1; 211 } else { 212 return SScanF(desc, "%i", value) == 1; 213 } 214 return false; 215 } 216 217 218 bool MipsDebugger::GetValue(const char* desc, int64_t* value) { 219 int regnum = Registers::Number(desc); 220 int fpuregnum = FPURegisters::Number(desc); 221 222 if (regnum != kInvalidRegister) { 223 *value = GetRegisterValue(regnum); 224 return true; 225 } else if (fpuregnum != kInvalidFPURegister) { 226 *value = GetFPURegisterValue64(fpuregnum); 227 return true; 228 } else if (strncmp(desc, "0x", 2) == 0) { 229 return SScanF(desc + 2, "%" SCNx64, 230 reinterpret_cast<uint64_t*>(value)) == 1; 231 } else { 232 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1; 233 } 234 return false; 235 } 236 237 238 bool MipsDebugger::SetBreakpoint(Instruction* breakpc) { 239 // Check if a breakpoint can be set. If not return without any side-effects. 240 if (sim_->break_pc_ != NULL) { 241 return false; 242 } 243 244 // Set the breakpoint. 245 sim_->break_pc_ = breakpc; 246 sim_->break_instr_ = breakpc->InstructionBits(); 247 // Not setting the breakpoint instruction in the code itself. It will be set 248 // when the debugger shell continues. 249 return true; 250 } 251 252 253 bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) { 254 if (sim_->break_pc_ != NULL) { 255 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); 256 } 257 258 sim_->break_pc_ = NULL; 259 sim_->break_instr_ = 0; 260 return true; 261 } 262 263 264 void MipsDebugger::UndoBreakpoints() { 265 if (sim_->break_pc_ != NULL) { 266 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); 267 } 268 } 269 270 271 void MipsDebugger::RedoBreakpoints() { 272 if (sim_->break_pc_ != NULL) { 273 sim_->break_pc_->SetInstructionBits(kBreakpointInstr); 274 } 275 } 276 277 278 void MipsDebugger::PrintAllRegs() { 279 #define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n) 280 281 PrintF("\n"); 282 // at, v0, a0. 283 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 284 REG_INFO(1), REG_INFO(2), REG_INFO(4)); 285 // v1, a1. 286 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 287 "", REG_INFO(3), REG_INFO(5)); 288 // a2. 289 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6)); 290 // a3. 291 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7)); 292 PrintF("\n"); 293 // t0-t7, s0-s7 294 for (int i = 0; i < 8; i++) { 295 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 296 REG_INFO(8+i), REG_INFO(16+i)); 297 } 298 PrintF("\n"); 299 // t8, k0, LO. 300 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 301 REG_INFO(24), REG_INFO(26), REG_INFO(32)); 302 // t9, k1, HI. 303 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 304 REG_INFO(25), REG_INFO(27), REG_INFO(33)); 305 // sp, fp, gp. 306 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 307 REG_INFO(29), REG_INFO(30), REG_INFO(28)); 308 // pc. 309 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 310 REG_INFO(31), REG_INFO(34)); 311 312 #undef REG_INFO 313 #undef FPU_REG_INFO 314 } 315 316 317 void MipsDebugger::PrintAllRegsIncludingFPU() { 318 #define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \ 319 GetFPURegisterValue32(n+1), \ 320 GetFPURegisterValue32(n), \ 321 GetFPURegisterValueDouble(n) 322 323 #define FPU_REG_INFO64(n) FPURegisters::Name(n), \ 324 GetFPURegisterValue64(n), \ 325 GetFPURegisterValueDouble(n) 326 327 PrintAllRegs(); 328 329 PrintF("\n\n"); 330 // f0, f1, f2, ... f31. 331 // This must be a compile-time switch, 332 // compiler will throw out warnings otherwise. 333 if (kFpuMode == kFP64) { 334 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) ); 335 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) ); 336 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) ); 337 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) ); 338 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) ); 339 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) ); 340 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) ); 341 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) ); 342 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) ); 343 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) ); 344 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10)); 345 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11)); 346 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12)); 347 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13)); 348 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14)); 349 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15)); 350 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16)); 351 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17)); 352 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18)); 353 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19)); 354 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20)); 355 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21)); 356 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22)); 357 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23)); 358 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24)); 359 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25)); 360 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26)); 361 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27)); 362 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28)); 363 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29)); 364 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30)); 365 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31)); 366 } else { 367 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) ); 368 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) ); 369 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) ); 370 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) ); 371 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) ); 372 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10)); 373 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12)); 374 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14)); 375 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16)); 376 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18)); 377 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20)); 378 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22)); 379 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24)); 380 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26)); 381 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28)); 382 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30)); 383 } 384 385 #undef REG_INFO 386 #undef FPU_REG_INFO32 387 #undef FPU_REG_INFO64 388 } 389 390 391 void MipsDebugger::Debug() { 392 intptr_t last_pc = -1; 393 bool done = false; 394 395 #define COMMAND_SIZE 63 396 #define ARG_SIZE 255 397 398 #define STR(a) #a 399 #define XSTR(a) STR(a) 400 401 char cmd[COMMAND_SIZE + 1]; 402 char arg1[ARG_SIZE + 1]; 403 char arg2[ARG_SIZE + 1]; 404 char* argv[3] = { cmd, arg1, arg2 }; 405 406 // Make sure to have a proper terminating character if reaching the limit. 407 cmd[COMMAND_SIZE] = 0; 408 arg1[ARG_SIZE] = 0; 409 arg2[ARG_SIZE] = 0; 410 411 // Undo all set breakpoints while running in the debugger shell. This will 412 // make them invisible to all commands. 413 UndoBreakpoints(); 414 415 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) { 416 if (last_pc != sim_->get_pc()) { 417 disasm::NameConverter converter; 418 disasm::Disassembler dasm(converter); 419 // Use a reasonably large buffer. 420 v8::internal::EmbeddedVector<char, 256> buffer; 421 dasm.InstructionDecode(buffer, 422 reinterpret_cast<byte*>(sim_->get_pc())); 423 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start()); 424 last_pc = sim_->get_pc(); 425 } 426 char* line = ReadLine("sim> "); 427 if (line == NULL) { 428 break; 429 } else { 430 char* last_input = sim_->last_debugger_input(); 431 if (strcmp(line, "\n") == 0 && last_input != NULL) { 432 line = last_input; 433 } else { 434 // Ownership is transferred to sim_; 435 sim_->set_last_debugger_input(line); 436 } 437 // Use sscanf to parse the individual parts of the command line. At the 438 // moment no command expects more than two parameters. 439 int argc = SScanF(line, 440 "%" XSTR(COMMAND_SIZE) "s " 441 "%" XSTR(ARG_SIZE) "s " 442 "%" XSTR(ARG_SIZE) "s", 443 cmd, arg1, arg2); 444 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { 445 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc()); 446 if (!(instr->IsTrap()) || 447 instr->InstructionBits() == rtCallRedirInstr) { 448 sim_->InstructionDecode( 449 reinterpret_cast<Instruction*>(sim_->get_pc())); 450 } else { 451 // Allow si to jump over generated breakpoints. 452 PrintF("/!\\ Jumping over generated breakpoint.\n"); 453 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); 454 } 455 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { 456 // Execute the one instruction we broke at with breakpoints disabled. 457 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc())); 458 // Leave the debugger shell. 459 done = true; 460 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { 461 if (argc == 2) { 462 if (strcmp(arg1, "all") == 0) { 463 PrintAllRegs(); 464 } else if (strcmp(arg1, "allf") == 0) { 465 PrintAllRegsIncludingFPU(); 466 } else { 467 int regnum = Registers::Number(arg1); 468 int fpuregnum = FPURegisters::Number(arg1); 469 470 if (regnum != kInvalidRegister) { 471 int32_t value; 472 value = GetRegisterValue(regnum); 473 PrintF("%s: 0x%08x %d \n", arg1, value, value); 474 } else if (fpuregnum != kInvalidFPURegister) { 475 if (IsFp64Mode()) { 476 int64_t value; 477 double dvalue; 478 value = GetFPURegisterValue64(fpuregnum); 479 dvalue = GetFPURegisterValueDouble(fpuregnum); 480 PrintF("%3s: 0x%016llx %16.4e\n", 481 FPURegisters::Name(fpuregnum), value, dvalue); 482 } else { 483 if (fpuregnum % 2 == 1) { 484 int32_t value; 485 float fvalue; 486 value = GetFPURegisterValue32(fpuregnum); 487 fvalue = GetFPURegisterValueFloat(fpuregnum); 488 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); 489 } else { 490 double dfvalue; 491 int32_t lvalue1 = GetFPURegisterValue32(fpuregnum); 492 int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1); 493 dfvalue = GetFPURegisterValueDouble(fpuregnum); 494 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", 495 FPURegisters::Name(fpuregnum+1), 496 FPURegisters::Name(fpuregnum), 497 lvalue1, 498 lvalue2, 499 dfvalue); 500 } 501 } 502 } else { 503 PrintF("%s unrecognized\n", arg1); 504 } 505 } 506 } else { 507 if (argc == 3) { 508 if (strcmp(arg2, "single") == 0) { 509 int32_t value; 510 float fvalue; 511 int fpuregnum = FPURegisters::Number(arg1); 512 513 if (fpuregnum != kInvalidFPURegister) { 514 value = GetFPURegisterValue32(fpuregnum); 515 fvalue = GetFPURegisterValueFloat(fpuregnum); 516 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); 517 } else { 518 PrintF("%s unrecognized\n", arg1); 519 } 520 } else { 521 PrintF("print <fpu register> single\n"); 522 } 523 } else { 524 PrintF("print <register> or print <fpu register> single\n"); 525 } 526 } 527 } else if ((strcmp(cmd, "po") == 0) 528 || (strcmp(cmd, "printobject") == 0)) { 529 if (argc == 2) { 530 int32_t value; 531 OFStream os(stdout); 532 if (GetValue(arg1, &value)) { 533 Object* obj = reinterpret_cast<Object*>(value); 534 os << arg1 << ": \n"; 535 #ifdef DEBUG 536 obj->Print(os); 537 os << "\n"; 538 #else 539 os << Brief(obj) << "\n"; 540 #endif 541 } else { 542 os << arg1 << " unrecognized\n"; 543 } 544 } else { 545 PrintF("printobject <value>\n"); 546 } 547 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { 548 int32_t* cur = NULL; 549 int32_t* end = NULL; 550 int next_arg = 1; 551 552 if (strcmp(cmd, "stack") == 0) { 553 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp)); 554 } else { // Command "mem". 555 int32_t value; 556 if (!GetValue(arg1, &value)) { 557 PrintF("%s unrecognized\n", arg1); 558 continue; 559 } 560 cur = reinterpret_cast<int32_t*>(value); 561 next_arg++; 562 } 563 564 // TODO(palfia): optimize this. 565 if (IsFp64Mode()) { 566 int64_t words; 567 if (argc == next_arg) { 568 words = 10; 569 } else { 570 if (!GetValue(argv[next_arg], &words)) { 571 words = 10; 572 } 573 } 574 end = cur + words; 575 } else { 576 int32_t words; 577 if (argc == next_arg) { 578 words = 10; 579 } else { 580 if (!GetValue(argv[next_arg], &words)) { 581 words = 10; 582 } 583 } 584 end = cur + words; 585 } 586 587 while (cur < end) { 588 PrintF(" 0x%08x: 0x%08x %10d", 589 reinterpret_cast<intptr_t>(cur), *cur, *cur); 590 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); 591 int value = *cur; 592 Heap* current_heap = sim_->isolate_->heap(); 593 if (((value & 1) == 0) || current_heap->Contains(obj)) { 594 PrintF(" ("); 595 if ((value & 1) == 0) { 596 PrintF("smi %d", value / 2); 597 } else { 598 obj->ShortPrint(); 599 } 600 PrintF(")"); 601 } 602 PrintF("\n"); 603 cur++; 604 } 605 606 } else if ((strcmp(cmd, "disasm") == 0) || 607 (strcmp(cmd, "dpc") == 0) || 608 (strcmp(cmd, "di") == 0)) { 609 disasm::NameConverter converter; 610 disasm::Disassembler dasm(converter); 611 // Use a reasonably large buffer. 612 v8::internal::EmbeddedVector<char, 256> buffer; 613 614 byte* cur = NULL; 615 byte* end = NULL; 616 617 if (argc == 1) { 618 cur = reinterpret_cast<byte*>(sim_->get_pc()); 619 end = cur + (10 * Instruction::kInstrSize); 620 } else if (argc == 2) { 621 int regnum = Registers::Number(arg1); 622 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { 623 // The argument is an address or a register name. 624 int32_t value; 625 if (GetValue(arg1, &value)) { 626 cur = reinterpret_cast<byte*>(value); 627 // Disassemble 10 instructions at <arg1>. 628 end = cur + (10 * Instruction::kInstrSize); 629 } 630 } else { 631 // The argument is the number of instructions. 632 int32_t value; 633 if (GetValue(arg1, &value)) { 634 cur = reinterpret_cast<byte*>(sim_->get_pc()); 635 // Disassemble <arg1> instructions. 636 end = cur + (value * Instruction::kInstrSize); 637 } 638 } 639 } else { 640 int32_t value1; 641 int32_t value2; 642 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { 643 cur = reinterpret_cast<byte*>(value1); 644 end = cur + (value2 * Instruction::kInstrSize); 645 } 646 } 647 648 while (cur < end) { 649 dasm.InstructionDecode(buffer, cur); 650 PrintF(" 0x%08x %s\n", 651 reinterpret_cast<intptr_t>(cur), buffer.start()); 652 cur += Instruction::kInstrSize; 653 } 654 } else if (strcmp(cmd, "gdb") == 0) { 655 PrintF("relinquishing control to gdb\n"); 656 v8::base::OS::DebugBreak(); 657 PrintF("regaining control from gdb\n"); 658 } else if (strcmp(cmd, "break") == 0) { 659 if (argc == 2) { 660 int32_t value; 661 if (GetValue(arg1, &value)) { 662 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) { 663 PrintF("setting breakpoint failed\n"); 664 } 665 } else { 666 PrintF("%s unrecognized\n", arg1); 667 } 668 } else { 669 PrintF("break <address>\n"); 670 } 671 } else if (strcmp(cmd, "del") == 0) { 672 if (!DeleteBreakpoint(NULL)) { 673 PrintF("deleting breakpoint failed\n"); 674 } 675 } else if (strcmp(cmd, "flags") == 0) { 676 PrintF("No flags on MIPS !\n"); 677 } else if (strcmp(cmd, "stop") == 0) { 678 int32_t value; 679 intptr_t stop_pc = sim_->get_pc() - 680 2 * Instruction::kInstrSize; 681 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc); 682 Instruction* msg_address = 683 reinterpret_cast<Instruction*>(stop_pc + 684 Instruction::kInstrSize); 685 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { 686 // Remove the current stop. 687 if (sim_->IsStopInstruction(stop_instr)) { 688 stop_instr->SetInstructionBits(kNopInstr); 689 msg_address->SetInstructionBits(kNopInstr); 690 } else { 691 PrintF("Not at debugger stop.\n"); 692 } 693 } else if (argc == 3) { 694 // Print information about all/the specified breakpoint(s). 695 if (strcmp(arg1, "info") == 0) { 696 if (strcmp(arg2, "all") == 0) { 697 PrintF("Stop information:\n"); 698 for (uint32_t i = kMaxWatchpointCode + 1; 699 i <= kMaxStopCode; 700 i++) { 701 sim_->PrintStopInfo(i); 702 } 703 } else if (GetValue(arg2, &value)) { 704 sim_->PrintStopInfo(value); 705 } else { 706 PrintF("Unrecognized argument.\n"); 707 } 708 } else if (strcmp(arg1, "enable") == 0) { 709 // Enable all/the specified breakpoint(s). 710 if (strcmp(arg2, "all") == 0) { 711 for (uint32_t i = kMaxWatchpointCode + 1; 712 i <= kMaxStopCode; 713 i++) { 714 sim_->EnableStop(i); 715 } 716 } else if (GetValue(arg2, &value)) { 717 sim_->EnableStop(value); 718 } else { 719 PrintF("Unrecognized argument.\n"); 720 } 721 } else if (strcmp(arg1, "disable") == 0) { 722 // Disable all/the specified breakpoint(s). 723 if (strcmp(arg2, "all") == 0) { 724 for (uint32_t i = kMaxWatchpointCode + 1; 725 i <= kMaxStopCode; 726 i++) { 727 sim_->DisableStop(i); 728 } 729 } else if (GetValue(arg2, &value)) { 730 sim_->DisableStop(value); 731 } else { 732 PrintF("Unrecognized argument.\n"); 733 } 734 } 735 } else { 736 PrintF("Wrong usage. Use help command for more information.\n"); 737 } 738 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) { 739 // Print registers and disassemble. 740 PrintAllRegs(); 741 PrintF("\n"); 742 743 disasm::NameConverter converter; 744 disasm::Disassembler dasm(converter); 745 // Use a reasonably large buffer. 746 v8::internal::EmbeddedVector<char, 256> buffer; 747 748 byte* cur = NULL; 749 byte* end = NULL; 750 751 if (argc == 1) { 752 cur = reinterpret_cast<byte*>(sim_->get_pc()); 753 end = cur + (10 * Instruction::kInstrSize); 754 } else if (argc == 2) { 755 int32_t value; 756 if (GetValue(arg1, &value)) { 757 cur = reinterpret_cast<byte*>(value); 758 // no length parameter passed, assume 10 instructions 759 end = cur + (10 * Instruction::kInstrSize); 760 } 761 } else { 762 int32_t value1; 763 int32_t value2; 764 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { 765 cur = reinterpret_cast<byte*>(value1); 766 end = cur + (value2 * Instruction::kInstrSize); 767 } 768 } 769 770 while (cur < end) { 771 dasm.InstructionDecode(buffer, cur); 772 PrintF(" 0x%08x %s\n", 773 reinterpret_cast<intptr_t>(cur), buffer.start()); 774 cur += Instruction::kInstrSize; 775 } 776 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { 777 PrintF("cont\n"); 778 PrintF(" continue execution (alias 'c')\n"); 779 PrintF("stepi\n"); 780 PrintF(" step one instruction (alias 'si')\n"); 781 PrintF("print <register>\n"); 782 PrintF(" print register content (alias 'p')\n"); 783 PrintF(" use register name 'all' to print all registers\n"); 784 PrintF("printobject <register>\n"); 785 PrintF(" print an object from a register (alias 'po')\n"); 786 PrintF("stack [<words>]\n"); 787 PrintF(" dump stack content, default dump 10 words)\n"); 788 PrintF("mem <address> [<words>]\n"); 789 PrintF(" dump memory content, default dump 10 words)\n"); 790 PrintF("flags\n"); 791 PrintF(" print flags\n"); 792 PrintF("disasm [<instructions>]\n"); 793 PrintF("disasm [<address/register>]\n"); 794 PrintF("disasm [[<address/register>] <instructions>]\n"); 795 PrintF(" disassemble code, default is 10 instructions\n"); 796 PrintF(" from pc (alias 'di')\n"); 797 PrintF("gdb\n"); 798 PrintF(" enter gdb\n"); 799 PrintF("break <address>\n"); 800 PrintF(" set a break point on the address\n"); 801 PrintF("del\n"); 802 PrintF(" delete the breakpoint\n"); 803 PrintF("stop feature:\n"); 804 PrintF(" Description:\n"); 805 PrintF(" Stops are debug instructions inserted by\n"); 806 PrintF(" the Assembler::stop() function.\n"); 807 PrintF(" When hitting a stop, the Simulator will\n"); 808 PrintF(" stop and and give control to the Debugger.\n"); 809 PrintF(" All stop codes are watched:\n"); 810 PrintF(" - They can be enabled / disabled: the Simulator\n"); 811 PrintF(" will / won't stop when hitting them.\n"); 812 PrintF(" - The Simulator keeps track of how many times they \n"); 813 PrintF(" are met. (See the info command.) Going over a\n"); 814 PrintF(" disabled stop still increases its counter. \n"); 815 PrintF(" Commands:\n"); 816 PrintF(" stop info all/<code> : print infos about number <code>\n"); 817 PrintF(" or all stop(s).\n"); 818 PrintF(" stop enable/disable all/<code> : enables / disables\n"); 819 PrintF(" all or number <code> stop(s)\n"); 820 PrintF(" stop unstop\n"); 821 PrintF(" ignore the stop instruction at the current location\n"); 822 PrintF(" from now on\n"); 823 } else { 824 PrintF("Unknown command: %s\n", cmd); 825 } 826 } 827 } 828 829 // Add all the breakpoints back to stop execution and enter the debugger 830 // shell when hit. 831 RedoBreakpoints(); 832 833 #undef COMMAND_SIZE 834 #undef ARG_SIZE 835 836 #undef STR 837 #undef XSTR 838 } 839 840 841 static bool ICacheMatch(void* one, void* two) { 842 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0); 843 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0); 844 return one == two; 845 } 846 847 848 static uint32_t ICacheHash(void* key) { 849 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2; 850 } 851 852 853 static bool AllOnOnePage(uintptr_t start, int size) { 854 intptr_t start_page = (start & ~CachePage::kPageMask); 855 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); 856 return start_page == end_page; 857 } 858 859 860 void Simulator::set_last_debugger_input(char* input) { 861 DeleteArray(last_debugger_input_); 862 last_debugger_input_ = input; 863 } 864 865 866 void Simulator::FlushICache(v8::internal::HashMap* i_cache, 867 void* start_addr, 868 size_t size) { 869 intptr_t start = reinterpret_cast<intptr_t>(start_addr); 870 int intra_line = (start & CachePage::kLineMask); 871 start -= intra_line; 872 size += intra_line; 873 size = ((size - 1) | CachePage::kLineMask) + 1; 874 int offset = (start & CachePage::kPageMask); 875 while (!AllOnOnePage(start, size - 1)) { 876 int bytes_to_flush = CachePage::kPageSize - offset; 877 FlushOnePage(i_cache, start, bytes_to_flush); 878 start += bytes_to_flush; 879 size -= bytes_to_flush; 880 DCHECK_EQ(0, start & CachePage::kPageMask); 881 offset = 0; 882 } 883 if (size != 0) { 884 FlushOnePage(i_cache, start, size); 885 } 886 } 887 888 889 CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) { 890 v8::internal::HashMap::Entry* entry = 891 i_cache->LookupOrInsert(page, ICacheHash(page)); 892 if (entry->value == NULL) { 893 CachePage* new_page = new CachePage(); 894 entry->value = new_page; 895 } 896 return reinterpret_cast<CachePage*>(entry->value); 897 } 898 899 900 // Flush from start up to and not including start + size. 901 void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, 902 intptr_t start, 903 int size) { 904 DCHECK(size <= CachePage::kPageSize); 905 DCHECK(AllOnOnePage(start, size - 1)); 906 DCHECK((start & CachePage::kLineMask) == 0); 907 DCHECK((size & CachePage::kLineMask) == 0); 908 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); 909 int offset = (start & CachePage::kPageMask); 910 CachePage* cache_page = GetCachePage(i_cache, page); 911 char* valid_bytemap = cache_page->ValidityByte(offset); 912 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); 913 } 914 915 916 void Simulator::CheckICache(v8::internal::HashMap* i_cache, 917 Instruction* instr) { 918 intptr_t address = reinterpret_cast<intptr_t>(instr); 919 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); 920 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); 921 int offset = (address & CachePage::kPageMask); 922 CachePage* cache_page = GetCachePage(i_cache, page); 923 char* cache_valid_byte = cache_page->ValidityByte(offset); 924 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); 925 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); 926 if (cache_hit) { 927 // Check that the data in memory matches the contents of the I-cache. 928 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr), 929 cache_page->CachedData(offset), 930 Instruction::kInstrSize)); 931 } else { 932 // Cache miss. Load memory into the cache. 933 memcpy(cached_line, line, CachePage::kLineLength); 934 *cache_valid_byte = CachePage::LINE_VALID; 935 } 936 } 937 938 939 void Simulator::Initialize(Isolate* isolate) { 940 if (isolate->simulator_initialized()) return; 941 isolate->set_simulator_initialized(true); 942 ::v8::internal::ExternalReference::set_redirector(isolate, 943 &RedirectExternalReference); 944 } 945 946 947 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { 948 i_cache_ = isolate_->simulator_i_cache(); 949 if (i_cache_ == NULL) { 950 i_cache_ = new v8::internal::HashMap(&ICacheMatch); 951 isolate_->set_simulator_i_cache(i_cache_); 952 } 953 Initialize(isolate); 954 // Set up simulator support first. Some of this information is needed to 955 // setup the architecture state. 956 stack_ = reinterpret_cast<char*>(malloc(stack_size_)); 957 pc_modified_ = false; 958 icount_ = 0; 959 break_count_ = 0; 960 break_pc_ = NULL; 961 break_instr_ = 0; 962 963 // Set up architecture state. 964 // All registers are initialized to zero to start with. 965 for (int i = 0; i < kNumSimuRegisters; i++) { 966 registers_[i] = 0; 967 } 968 for (int i = 0; i < kNumFPURegisters; i++) { 969 FPUregisters_[i] = 0; 970 } 971 if (IsMipsArchVariant(kMips32r6)) { 972 FCSR_ = kFCSRNaN2008FlagMask; 973 } else { 974 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2)); 975 FCSR_ = 0; 976 } 977 978 // The sp is initialized to point to the bottom (high address) of the 979 // allocated stack area. To be safe in potential stack underflows we leave 980 // some buffer below. 981 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64; 982 // The ra and pc are initialized to a known bad value that will cause an 983 // access violation if the simulator ever tries to execute it. 984 registers_[pc] = bad_ra; 985 registers_[ra] = bad_ra; 986 InitializeCoverage(); 987 last_debugger_input_ = NULL; 988 } 989 990 991 Simulator::~Simulator() { free(stack_); } 992 993 994 // When the generated code calls an external reference we need to catch that in 995 // the simulator. The external reference will be a function compiled for the 996 // host architecture. We need to call that function instead of trying to 997 // execute it with the simulator. We do that by redirecting the external 998 // reference to a swi (software-interrupt) instruction that is handled by 999 // the simulator. We write the original destination of the jump just at a known 1000 // offset from the swi instruction so the simulator knows what to call. 1001 class Redirection { 1002 public: 1003 Redirection(Isolate* isolate, void* external_function, 1004 ExternalReference::Type type) 1005 : external_function_(external_function), 1006 swi_instruction_(rtCallRedirInstr), 1007 type_(type), 1008 next_(NULL) { 1009 next_ = isolate->simulator_redirection(); 1010 Simulator::current(isolate)-> 1011 FlushICache(isolate->simulator_i_cache(), 1012 reinterpret_cast<void*>(&swi_instruction_), 1013 Instruction::kInstrSize); 1014 isolate->set_simulator_redirection(this); 1015 } 1016 1017 void* address_of_swi_instruction() { 1018 return reinterpret_cast<void*>(&swi_instruction_); 1019 } 1020 1021 void* external_function() { return external_function_; } 1022 ExternalReference::Type type() { return type_; } 1023 1024 static Redirection* Get(Isolate* isolate, void* external_function, 1025 ExternalReference::Type type) { 1026 Redirection* current = isolate->simulator_redirection(); 1027 for (; current != NULL; current = current->next_) { 1028 if (current->external_function_ == external_function) return current; 1029 } 1030 return new Redirection(isolate, external_function, type); 1031 } 1032 1033 static Redirection* FromSwiInstruction(Instruction* swi_instruction) { 1034 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); 1035 char* addr_of_redirection = 1036 addr_of_swi - offsetof(Redirection, swi_instruction_); 1037 return reinterpret_cast<Redirection*>(addr_of_redirection); 1038 } 1039 1040 static void* ReverseRedirection(int32_t reg) { 1041 Redirection* redirection = FromSwiInstruction( 1042 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg))); 1043 return redirection->external_function(); 1044 } 1045 1046 static void DeleteChain(Redirection* redirection) { 1047 while (redirection != nullptr) { 1048 Redirection* next = redirection->next_; 1049 delete redirection; 1050 redirection = next; 1051 } 1052 } 1053 1054 private: 1055 void* external_function_; 1056 uint32_t swi_instruction_; 1057 ExternalReference::Type type_; 1058 Redirection* next_; 1059 }; 1060 1061 1062 // static 1063 void Simulator::TearDown(HashMap* i_cache, Redirection* first) { 1064 Redirection::DeleteChain(first); 1065 if (i_cache != nullptr) { 1066 for (HashMap::Entry* entry = i_cache->Start(); entry != nullptr; 1067 entry = i_cache->Next(entry)) { 1068 delete static_cast<CachePage*>(entry->value); 1069 } 1070 delete i_cache; 1071 } 1072 } 1073 1074 1075 void* Simulator::RedirectExternalReference(Isolate* isolate, 1076 void* external_function, 1077 ExternalReference::Type type) { 1078 Redirection* redirection = Redirection::Get(isolate, external_function, type); 1079 return redirection->address_of_swi_instruction(); 1080 } 1081 1082 1083 // Get the active Simulator for the current thread. 1084 Simulator* Simulator::current(Isolate* isolate) { 1085 v8::internal::Isolate::PerIsolateThreadData* isolate_data = 1086 isolate->FindOrAllocatePerThreadDataForThisThread(); 1087 DCHECK(isolate_data != NULL); 1088 DCHECK(isolate_data != NULL); 1089 1090 Simulator* sim = isolate_data->simulator(); 1091 if (sim == NULL) { 1092 // TODO(146): delete the simulator object when a thread/isolate goes away. 1093 sim = new Simulator(isolate); 1094 isolate_data->set_simulator(sim); 1095 } 1096 return sim; 1097 } 1098 1099 1100 // Sets the register in the architecture state. It will also deal with updating 1101 // Simulator internal state for special registers such as PC. 1102 void Simulator::set_register(int reg, int32_t value) { 1103 DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); 1104 if (reg == pc) { 1105 pc_modified_ = true; 1106 } 1107 1108 // Zero register always holds 0. 1109 registers_[reg] = (reg == 0) ? 0 : value; 1110 } 1111 1112 1113 void Simulator::set_dw_register(int reg, const int* dbl) { 1114 DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); 1115 registers_[reg] = dbl[0]; 1116 registers_[reg + 1] = dbl[1]; 1117 } 1118 1119 1120 void Simulator::set_fpu_register(int fpureg, int64_t value) { 1121 DCHECK(IsFp64Mode()); 1122 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1123 FPUregisters_[fpureg] = value; 1124 } 1125 1126 1127 void Simulator::set_fpu_register_word(int fpureg, int32_t value) { 1128 // Set ONLY lower 32-bits, leaving upper bits untouched. 1129 // TODO(plind): big endian issue. 1130 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1131 int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); 1132 *pword = value; 1133 } 1134 1135 1136 void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) { 1137 // Set ONLY upper 32-bits, leaving lower bits untouched. 1138 // TODO(plind): big endian issue. 1139 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1140 int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1; 1141 *phiword = value; 1142 } 1143 1144 1145 void Simulator::set_fpu_register_float(int fpureg, float value) { 1146 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1147 *bit_cast<float*>(&FPUregisters_[fpureg]) = value; 1148 } 1149 1150 1151 void Simulator::set_fpu_register_double(int fpureg, double value) { 1152 if (IsFp64Mode()) { 1153 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1154 *bit_cast<double*>(&FPUregisters_[fpureg]) = value; 1155 } else { 1156 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); 1157 int64_t i64 = bit_cast<int64_t>(value); 1158 set_fpu_register_word(fpureg, i64 & 0xffffffff); 1159 set_fpu_register_word(fpureg + 1, i64 >> 32); 1160 } 1161 } 1162 1163 1164 // Get the register from the architecture state. This function does handle 1165 // the special case of accessing the PC register. 1166 int32_t Simulator::get_register(int reg) const { 1167 DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); 1168 if (reg == 0) 1169 return 0; 1170 else 1171 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); 1172 } 1173 1174 1175 double Simulator::get_double_from_register_pair(int reg) { 1176 // TODO(plind): bad ABI stuff, refactor or remove. 1177 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0)); 1178 1179 double dm_val = 0.0; 1180 // Read the bits from the unsigned integer register_[] array 1181 // into the double precision floating point value and return it. 1182 char buffer[2 * sizeof(registers_[0])]; 1183 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0])); 1184 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0])); 1185 return(dm_val); 1186 } 1187 1188 1189 int64_t Simulator::get_fpu_register(int fpureg) const { 1190 DCHECK(IsFp64Mode()); 1191 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1192 return FPUregisters_[fpureg]; 1193 } 1194 1195 1196 int32_t Simulator::get_fpu_register_word(int fpureg) const { 1197 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1198 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff); 1199 } 1200 1201 1202 int32_t Simulator::get_fpu_register_signed_word(int fpureg) const { 1203 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1204 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff); 1205 } 1206 1207 1208 int32_t Simulator::get_fpu_register_hi_word(int fpureg) const { 1209 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1210 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff); 1211 } 1212 1213 1214 float Simulator::get_fpu_register_float(int fpureg) const { 1215 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1216 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg])); 1217 } 1218 1219 1220 double Simulator::get_fpu_register_double(int fpureg) const { 1221 if (IsFp64Mode()) { 1222 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); 1223 return *bit_cast<double*>(&FPUregisters_[fpureg]); 1224 } else { 1225 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); 1226 int64_t i64; 1227 i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg)); 1228 i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32; 1229 return bit_cast<double>(i64); 1230 } 1231 } 1232 1233 1234 // Runtime FP routines take up to two double arguments and zero 1235 // or one integer arguments. All are constructed here, 1236 // from a0-a3 or f12 and f14. 1237 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) { 1238 if (!IsMipsSoftFloatABI) { 1239 *x = get_fpu_register_double(12); 1240 *y = get_fpu_register_double(14); 1241 *z = get_register(a2); 1242 } else { 1243 // TODO(plind): bad ABI stuff, refactor or remove. 1244 // We use a char buffer to get around the strict-aliasing rules which 1245 // otherwise allow the compiler to optimize away the copy. 1246 char buffer[sizeof(*x)]; 1247 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 1248 1249 // Registers a0 and a1 -> x. 1250 reg_buffer[0] = get_register(a0); 1251 reg_buffer[1] = get_register(a1); 1252 memcpy(x, buffer, sizeof(buffer)); 1253 // Registers a2 and a3 -> y. 1254 reg_buffer[0] = get_register(a2); 1255 reg_buffer[1] = get_register(a3); 1256 memcpy(y, buffer, sizeof(buffer)); 1257 // Register 2 -> z. 1258 reg_buffer[0] = get_register(a2); 1259 memcpy(z, buffer, sizeof(*z)); 1260 } 1261 } 1262 1263 1264 // The return value is either in v0/v1 or f0. 1265 void Simulator::SetFpResult(const double& result) { 1266 if (!IsMipsSoftFloatABI) { 1267 set_fpu_register_double(0, result); 1268 } else { 1269 char buffer[2 * sizeof(registers_[0])]; 1270 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 1271 memcpy(buffer, &result, sizeof(buffer)); 1272 // Copy result to v0 and v1. 1273 set_register(v0, reg_buffer[0]); 1274 set_register(v1, reg_buffer[1]); 1275 } 1276 } 1277 1278 1279 // Helper functions for setting and testing the FCSR register's bits. 1280 void Simulator::set_fcsr_bit(uint32_t cc, bool value) { 1281 if (value) { 1282 FCSR_ |= (1 << cc); 1283 } else { 1284 FCSR_ &= ~(1 << cc); 1285 } 1286 } 1287 1288 1289 bool Simulator::test_fcsr_bit(uint32_t cc) { 1290 return FCSR_ & (1 << cc); 1291 } 1292 1293 1294 void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) { 1295 FCSR_ |= mode & kFPURoundingModeMask; 1296 } 1297 1298 1299 unsigned int Simulator::get_fcsr_rounding_mode() { 1300 return FCSR_ & kFPURoundingModeMask; 1301 } 1302 1303 1304 void Simulator::set_fpu_register_word_invalid_result(float original, 1305 float rounded) { 1306 if (FCSR_ & kFCSRNaN2008FlagMask) { 1307 double max_int32 = std::numeric_limits<int32_t>::max(); 1308 double min_int32 = std::numeric_limits<int32_t>::min(); 1309 if (std::isnan(original)) { 1310 set_fpu_register_word(fd_reg(), 0); 1311 } else if (rounded > max_int32) { 1312 set_fpu_register_word(fd_reg(), kFPUInvalidResult); 1313 } else if (rounded < min_int32) { 1314 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative); 1315 } else { 1316 UNREACHABLE(); 1317 } 1318 } else { 1319 set_fpu_register_word(fd_reg(), kFPUInvalidResult); 1320 } 1321 } 1322 1323 1324 void Simulator::set_fpu_register_invalid_result(float original, float rounded) { 1325 if (FCSR_ & kFCSRNaN2008FlagMask) { 1326 double max_int32 = std::numeric_limits<int32_t>::max(); 1327 double min_int32 = std::numeric_limits<int32_t>::min(); 1328 if (std::isnan(original)) { 1329 set_fpu_register(fd_reg(), 0); 1330 } else if (rounded > max_int32) { 1331 set_fpu_register(fd_reg(), kFPUInvalidResult); 1332 } else if (rounded < min_int32) { 1333 set_fpu_register(fd_reg(), kFPUInvalidResultNegative); 1334 } else { 1335 UNREACHABLE(); 1336 } 1337 } else { 1338 set_fpu_register(fd_reg(), kFPUInvalidResult); 1339 } 1340 } 1341 1342 1343 void Simulator::set_fpu_register_invalid_result64(float original, 1344 float rounded) { 1345 if (FCSR_ & kFCSRNaN2008FlagMask) { 1346 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1347 // loading the most accurate representation into max_int64, which is 2^63. 1348 double max_int64 = std::numeric_limits<int64_t>::max(); 1349 double min_int64 = std::numeric_limits<int64_t>::min(); 1350 if (std::isnan(original)) { 1351 set_fpu_register(fd_reg(), 0); 1352 } else if (rounded >= max_int64) { 1353 set_fpu_register(fd_reg(), kFPU64InvalidResult); 1354 } else if (rounded < min_int64) { 1355 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative); 1356 } else { 1357 UNREACHABLE(); 1358 } 1359 } else { 1360 set_fpu_register(fd_reg(), kFPU64InvalidResult); 1361 } 1362 } 1363 1364 1365 void Simulator::set_fpu_register_word_invalid_result(double original, 1366 double rounded) { 1367 if (FCSR_ & kFCSRNaN2008FlagMask) { 1368 double max_int32 = std::numeric_limits<int32_t>::max(); 1369 double min_int32 = std::numeric_limits<int32_t>::min(); 1370 if (std::isnan(original)) { 1371 set_fpu_register_word(fd_reg(), 0); 1372 } else if (rounded > max_int32) { 1373 set_fpu_register_word(fd_reg(), kFPUInvalidResult); 1374 } else if (rounded < min_int32) { 1375 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative); 1376 } else { 1377 UNREACHABLE(); 1378 } 1379 } else { 1380 set_fpu_register_word(fd_reg(), kFPUInvalidResult); 1381 } 1382 } 1383 1384 1385 void Simulator::set_fpu_register_invalid_result(double original, 1386 double rounded) { 1387 if (FCSR_ & kFCSRNaN2008FlagMask) { 1388 double max_int32 = std::numeric_limits<int32_t>::max(); 1389 double min_int32 = std::numeric_limits<int32_t>::min(); 1390 if (std::isnan(original)) { 1391 set_fpu_register(fd_reg(), 0); 1392 } else if (rounded > max_int32) { 1393 set_fpu_register(fd_reg(), kFPUInvalidResult); 1394 } else if (rounded < min_int32) { 1395 set_fpu_register(fd_reg(), kFPUInvalidResultNegative); 1396 } else { 1397 UNREACHABLE(); 1398 } 1399 } else { 1400 set_fpu_register(fd_reg(), kFPUInvalidResult); 1401 } 1402 } 1403 1404 1405 void Simulator::set_fpu_register_invalid_result64(double original, 1406 double rounded) { 1407 if (FCSR_ & kFCSRNaN2008FlagMask) { 1408 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1409 // loading the most accurate representation into max_int64, which is 2^63. 1410 double max_int64 = std::numeric_limits<int64_t>::max(); 1411 double min_int64 = std::numeric_limits<int64_t>::min(); 1412 if (std::isnan(original)) { 1413 set_fpu_register(fd_reg(), 0); 1414 } else if (rounded >= max_int64) { 1415 set_fpu_register(fd_reg(), kFPU64InvalidResult); 1416 } else if (rounded < min_int64) { 1417 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative); 1418 } else { 1419 UNREACHABLE(); 1420 } 1421 } else { 1422 set_fpu_register(fd_reg(), kFPU64InvalidResult); 1423 } 1424 } 1425 1426 1427 // Sets the rounding error codes in FCSR based on the result of the rounding. 1428 // Returns true if the operation was invalid. 1429 bool Simulator::set_fcsr_round_error(double original, double rounded) { 1430 bool ret = false; 1431 double max_int32 = std::numeric_limits<int32_t>::max(); 1432 double min_int32 = std::numeric_limits<int32_t>::min(); 1433 1434 if (!std::isfinite(original) || !std::isfinite(rounded)) { 1435 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1436 ret = true; 1437 } 1438 1439 if (original != rounded) { 1440 set_fcsr_bit(kFCSRInexactFlagBit, true); 1441 } 1442 1443 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { 1444 set_fcsr_bit(kFCSRUnderflowFlagBit, true); 1445 ret = true; 1446 } 1447 1448 if (rounded > max_int32 || rounded < min_int32) { 1449 set_fcsr_bit(kFCSROverflowFlagBit, true); 1450 // The reference is not really clear but it seems this is required: 1451 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1452 ret = true; 1453 } 1454 1455 return ret; 1456 } 1457 1458 1459 // Sets the rounding error codes in FCSR based on the result of the rounding. 1460 // Returns true if the operation was invalid. 1461 bool Simulator::set_fcsr_round64_error(double original, double rounded) { 1462 bool ret = false; 1463 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1464 // loading the most accurate representation into max_int64, which is 2^63. 1465 double max_int64 = std::numeric_limits<int64_t>::max(); 1466 double min_int64 = std::numeric_limits<int64_t>::min(); 1467 1468 if (!std::isfinite(original) || !std::isfinite(rounded)) { 1469 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1470 ret = true; 1471 } 1472 1473 if (original != rounded) { 1474 set_fcsr_bit(kFCSRInexactFlagBit, true); 1475 } 1476 1477 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { 1478 set_fcsr_bit(kFCSRUnderflowFlagBit, true); 1479 ret = true; 1480 } 1481 1482 if (rounded >= max_int64 || rounded < min_int64) { 1483 set_fcsr_bit(kFCSROverflowFlagBit, true); 1484 // The reference is not really clear but it seems this is required: 1485 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1486 ret = true; 1487 } 1488 1489 return ret; 1490 } 1491 1492 1493 // Sets the rounding error codes in FCSR based on the result of the rounding. 1494 // Returns true if the operation was invalid. 1495 bool Simulator::set_fcsr_round_error(float original, float rounded) { 1496 bool ret = false; 1497 double max_int32 = std::numeric_limits<int32_t>::max(); 1498 double min_int32 = std::numeric_limits<int32_t>::min(); 1499 1500 if (!std::isfinite(original) || !std::isfinite(rounded)) { 1501 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1502 ret = true; 1503 } 1504 1505 if (original != rounded) { 1506 set_fcsr_bit(kFCSRInexactFlagBit, true); 1507 } 1508 1509 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { 1510 set_fcsr_bit(kFCSRUnderflowFlagBit, true); 1511 ret = true; 1512 } 1513 1514 if (rounded > max_int32 || rounded < min_int32) { 1515 set_fcsr_bit(kFCSROverflowFlagBit, true); 1516 // The reference is not really clear but it seems this is required: 1517 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1518 ret = true; 1519 } 1520 1521 return ret; 1522 } 1523 1524 1525 // Sets the rounding error codes in FCSR based on the result of the rounding. 1526 // Returns true if the operation was invalid. 1527 bool Simulator::set_fcsr_round64_error(float original, float rounded) { 1528 bool ret = false; 1529 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1530 // loading the most accurate representation into max_int64, which is 2^63. 1531 double max_int64 = std::numeric_limits<int64_t>::max(); 1532 double min_int64 = std::numeric_limits<int64_t>::min(); 1533 1534 if (!std::isfinite(original) || !std::isfinite(rounded)) { 1535 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1536 ret = true; 1537 } 1538 1539 if (original != rounded) { 1540 set_fcsr_bit(kFCSRInexactFlagBit, true); 1541 } 1542 1543 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { 1544 set_fcsr_bit(kFCSRUnderflowFlagBit, true); 1545 ret = true; 1546 } 1547 1548 if (rounded >= max_int64 || rounded < min_int64) { 1549 set_fcsr_bit(kFCSROverflowFlagBit, true); 1550 // The reference is not really clear but it seems this is required: 1551 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); 1552 ret = true; 1553 } 1554 1555 return ret; 1556 } 1557 1558 1559 void Simulator::round_according_to_fcsr(double toRound, double& rounded, 1560 int32_t& rounded_int, double fs) { 1561 // 0 RN (round to nearest): Round a result to the nearest 1562 // representable value; if the result is exactly halfway between 1563 // two representable values, round to zero. Behave like round_w_d. 1564 1565 // 1 RZ (round toward zero): Round a result to the closest 1566 // representable value whose absolute value is less than or 1567 // equal to the infinitely accurate result. Behave like trunc_w_d. 1568 1569 // 2 RP (round up, or toward infinity): Round a result to the 1570 // next representable value up. Behave like ceil_w_d. 1571 1572 // 3 RD (round down, or toward infinity): Round a result to 1573 // the next representable value down. Behave like floor_w_d. 1574 switch (get_fcsr_rounding_mode()) { 1575 case kRoundToNearest: 1576 rounded = std::floor(fs + 0.5); 1577 rounded_int = static_cast<int32_t>(rounded); 1578 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) { 1579 // If the number is halfway between two integers, 1580 // round to the even one. 1581 rounded_int--; 1582 } 1583 break; 1584 case kRoundToZero: 1585 rounded = trunc(fs); 1586 rounded_int = static_cast<int32_t>(rounded); 1587 break; 1588 case kRoundToPlusInf: 1589 rounded = std::ceil(fs); 1590 rounded_int = static_cast<int32_t>(rounded); 1591 break; 1592 case kRoundToMinusInf: 1593 rounded = std::floor(fs); 1594 rounded_int = static_cast<int32_t>(rounded); 1595 break; 1596 } 1597 } 1598 1599 1600 void Simulator::round_according_to_fcsr(float toRound, float& rounded, 1601 int32_t& rounded_int, float fs) { 1602 // 0 RN (round to nearest): Round a result to the nearest 1603 // representable value; if the result is exactly halfway between 1604 // two representable values, round to zero. Behave like round_w_d. 1605 1606 // 1 RZ (round toward zero): Round a result to the closest 1607 // representable value whose absolute value is less than or 1608 // equal to the infinitely accurate result. Behave like trunc_w_d. 1609 1610 // 2 RP (round up, or toward infinity): Round a result to the 1611 // next representable value up. Behave like ceil_w_d. 1612 1613 // 3 RD (round down, or toward infinity): Round a result to 1614 // the next representable value down. Behave like floor_w_d. 1615 switch (get_fcsr_rounding_mode()) { 1616 case kRoundToNearest: 1617 rounded = std::floor(fs + 0.5); 1618 rounded_int = static_cast<int32_t>(rounded); 1619 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) { 1620 // If the number is halfway between two integers, 1621 // round to the even one. 1622 rounded_int--; 1623 } 1624 break; 1625 case kRoundToZero: 1626 rounded = trunc(fs); 1627 rounded_int = static_cast<int32_t>(rounded); 1628 break; 1629 case kRoundToPlusInf: 1630 rounded = std::ceil(fs); 1631 rounded_int = static_cast<int32_t>(rounded); 1632 break; 1633 case kRoundToMinusInf: 1634 rounded = std::floor(fs); 1635 rounded_int = static_cast<int32_t>(rounded); 1636 break; 1637 } 1638 } 1639 1640 1641 void Simulator::round64_according_to_fcsr(double toRound, double& rounded, 1642 int64_t& rounded_int, double fs) { 1643 // 0 RN (round to nearest): Round a result to the nearest 1644 // representable value; if the result is exactly halfway between 1645 // two representable values, round to zero. Behave like round_w_d. 1646 1647 // 1 RZ (round toward zero): Round a result to the closest 1648 // representable value whose absolute value is less than or. 1649 // equal to the infinitely accurate result. Behave like trunc_w_d. 1650 1651 // 2 RP (round up, or toward +infinity): Round a result to the 1652 // next representable value up. Behave like ceil_w_d. 1653 1654 // 3 RN (round down, or toward infinity): Round a result to 1655 // the next representable value down. Behave like floor_w_d. 1656 switch (FCSR_ & 3) { 1657 case kRoundToNearest: 1658 rounded = std::floor(fs + 0.5); 1659 rounded_int = static_cast<int64_t>(rounded); 1660 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) { 1661 // If the number is halfway between two integers, 1662 // round to the even one. 1663 rounded_int--; 1664 } 1665 break; 1666 case kRoundToZero: 1667 rounded = trunc(fs); 1668 rounded_int = static_cast<int64_t>(rounded); 1669 break; 1670 case kRoundToPlusInf: 1671 rounded = std::ceil(fs); 1672 rounded_int = static_cast<int64_t>(rounded); 1673 break; 1674 case kRoundToMinusInf: 1675 rounded = std::floor(fs); 1676 rounded_int = static_cast<int64_t>(rounded); 1677 break; 1678 } 1679 } 1680 1681 1682 void Simulator::round64_according_to_fcsr(float toRound, float& rounded, 1683 int64_t& rounded_int, float fs) { 1684 // 0 RN (round to nearest): Round a result to the nearest 1685 // representable value; if the result is exactly halfway between 1686 // two representable values, round to zero. Behave like round_w_d. 1687 1688 // 1 RZ (round toward zero): Round a result to the closest 1689 // representable value whose absolute value is less than or. 1690 // equal to the infinitely accurate result. Behave like trunc_w_d. 1691 1692 // 2 RP (round up, or toward +infinity): Round a result to the 1693 // next representable value up. Behave like ceil_w_d. 1694 1695 // 3 RN (round down, or toward infinity): Round a result to 1696 // the next representable value down. Behave like floor_w_d. 1697 switch (FCSR_ & 3) { 1698 case kRoundToNearest: 1699 rounded = std::floor(fs + 0.5); 1700 rounded_int = static_cast<int64_t>(rounded); 1701 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) { 1702 // If the number is halfway between two integers, 1703 // round to the even one. 1704 rounded_int--; 1705 } 1706 break; 1707 case kRoundToZero: 1708 rounded = trunc(fs); 1709 rounded_int = static_cast<int64_t>(rounded); 1710 break; 1711 case kRoundToPlusInf: 1712 rounded = std::ceil(fs); 1713 rounded_int = static_cast<int64_t>(rounded); 1714 break; 1715 case kRoundToMinusInf: 1716 rounded = std::floor(fs); 1717 rounded_int = static_cast<int64_t>(rounded); 1718 break; 1719 } 1720 } 1721 1722 1723 // Raw access to the PC register. 1724 void Simulator::set_pc(int32_t value) { 1725 pc_modified_ = true; 1726 registers_[pc] = value; 1727 } 1728 1729 1730 bool Simulator::has_bad_pc() const { 1731 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); 1732 } 1733 1734 1735 // Raw access to the PC register without the special adjustment when reading. 1736 int32_t Simulator::get_pc() const { 1737 return registers_[pc]; 1738 } 1739 1740 1741 // The MIPS cannot do unaligned reads and writes. On some MIPS platforms an 1742 // interrupt is caused. On others it does a funky rotation thing. For now we 1743 // simply disallow unaligned reads, but at some point we may want to move to 1744 // emulating the rotate behaviour. Note that simulator runs have the runtime 1745 // system running directly on the host system and only generated code is 1746 // executed in the simulator. Since the host is typically IA32 we will not 1747 // get the correct MIPS-like behaviour on unaligned accesses. 1748 1749 void Simulator::TraceRegWr(int32_t value) { 1750 if (::v8::internal::FLAG_trace_sim) { 1751 SNPrintF(trace_buf_, "%08x", value); 1752 } 1753 } 1754 1755 1756 // TODO(plind): consider making icount_ printing a flag option. 1757 void Simulator::TraceMemRd(int32_t addr, int32_t value) { 1758 if (::v8::internal::FLAG_trace_sim) { 1759 SNPrintF(trace_buf_, "%08x <-- [%08x] (%" PRIu64 ")", value, addr, 1760 icount_); 1761 } 1762 } 1763 1764 1765 void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) { 1766 if (::v8::internal::FLAG_trace_sim) { 1767 switch (t) { 1768 case BYTE: 1769 SNPrintF(trace_buf_, " %02x --> [%08x]", 1770 static_cast<int8_t>(value), addr); 1771 break; 1772 case HALF: 1773 SNPrintF(trace_buf_, " %04x --> [%08x]", static_cast<int16_t>(value), 1774 addr); 1775 break; 1776 case WORD: 1777 SNPrintF(trace_buf_, "%08x --> [%08x]", value, addr); 1778 break; 1779 } 1780 } 1781 } 1782 1783 1784 int Simulator::ReadW(int32_t addr, Instruction* instr) { 1785 if (addr >=0 && addr < 0x400) { 1786 // This has to be a NULL-dereference, drop into debugger. 1787 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n", 1788 addr, reinterpret_cast<intptr_t>(instr)); 1789 MipsDebugger dbg(this); 1790 dbg.Debug(); 1791 } 1792 if ((addr & kPointerAlignmentMask) == 0) { 1793 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1794 TraceMemRd(addr, static_cast<int32_t>(*ptr)); 1795 return *ptr; 1796 } 1797 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1798 addr, 1799 reinterpret_cast<intptr_t>(instr)); 1800 MipsDebugger dbg(this); 1801 dbg.Debug(); 1802 return 0; 1803 } 1804 1805 1806 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { 1807 if (addr >= 0 && addr < 0x400) { 1808 // This has to be a NULL-dereference, drop into debugger. 1809 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n", 1810 addr, reinterpret_cast<intptr_t>(instr)); 1811 MipsDebugger dbg(this); 1812 dbg.Debug(); 1813 } 1814 if ((addr & kPointerAlignmentMask) == 0) { 1815 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1816 TraceMemWr(addr, value, WORD); 1817 *ptr = value; 1818 return; 1819 } 1820 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1821 addr, 1822 reinterpret_cast<intptr_t>(instr)); 1823 MipsDebugger dbg(this); 1824 dbg.Debug(); 1825 } 1826 1827 1828 double Simulator::ReadD(int32_t addr, Instruction* instr) { 1829 if ((addr & kDoubleAlignmentMask) == 0) { 1830 double* ptr = reinterpret_cast<double*>(addr); 1831 return *ptr; 1832 } 1833 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1834 addr, 1835 reinterpret_cast<intptr_t>(instr)); 1836 base::OS::Abort(); 1837 return 0; 1838 } 1839 1840 1841 void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { 1842 if ((addr & kDoubleAlignmentMask) == 0) { 1843 double* ptr = reinterpret_cast<double*>(addr); 1844 *ptr = value; 1845 return; 1846 } 1847 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1848 addr, 1849 reinterpret_cast<intptr_t>(instr)); 1850 base::OS::Abort(); 1851 } 1852 1853 1854 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { 1855 if ((addr & 1) == 0) { 1856 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1857 TraceMemRd(addr, static_cast<int32_t>(*ptr)); 1858 return *ptr; 1859 } 1860 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1861 addr, 1862 reinterpret_cast<intptr_t>(instr)); 1863 base::OS::Abort(); 1864 return 0; 1865 } 1866 1867 1868 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { 1869 if ((addr & 1) == 0) { 1870 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1871 TraceMemRd(addr, static_cast<int32_t>(*ptr)); 1872 return *ptr; 1873 } 1874 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1875 addr, 1876 reinterpret_cast<intptr_t>(instr)); 1877 base::OS::Abort(); 1878 return 0; 1879 } 1880 1881 1882 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { 1883 if ((addr & 1) == 0) { 1884 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1885 TraceMemWr(addr, value, HALF); 1886 *ptr = value; 1887 return; 1888 } 1889 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1890 addr, 1891 reinterpret_cast<intptr_t>(instr)); 1892 base::OS::Abort(); 1893 } 1894 1895 1896 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { 1897 if ((addr & 1) == 0) { 1898 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1899 TraceMemWr(addr, value, HALF); 1900 *ptr = value; 1901 return; 1902 } 1903 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1904 addr, 1905 reinterpret_cast<intptr_t>(instr)); 1906 base::OS::Abort(); 1907 } 1908 1909 1910 uint32_t Simulator::ReadBU(int32_t addr) { 1911 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1912 TraceMemRd(addr, static_cast<int32_t>(*ptr)); 1913 return *ptr & 0xff; 1914 } 1915 1916 1917 int32_t Simulator::ReadB(int32_t addr) { 1918 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1919 TraceMemRd(addr, static_cast<int32_t>(*ptr)); 1920 return *ptr; 1921 } 1922 1923 1924 void Simulator::WriteB(int32_t addr, uint8_t value) { 1925 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1926 TraceMemWr(addr, value, BYTE); 1927 *ptr = value; 1928 } 1929 1930 1931 void Simulator::WriteB(int32_t addr, int8_t value) { 1932 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1933 TraceMemWr(addr, value, BYTE); 1934 *ptr = value; 1935 } 1936 1937 1938 // Returns the limit of the stack area to enable checking for stack overflows. 1939 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { 1940 // The simulator uses a separate JS stack. If we have exhausted the C stack, 1941 // we also drop down the JS limit to reflect the exhaustion on the JS stack. 1942 if (GetCurrentStackPosition() < c_limit) { 1943 return reinterpret_cast<uintptr_t>(get_sp()); 1944 } 1945 1946 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes 1947 // to prevent overrunning the stack when pushing values. 1948 return reinterpret_cast<uintptr_t>(stack_) + 1024; 1949 } 1950 1951 1952 // Unsupported instructions use Format to print an error and stop execution. 1953 void Simulator::Format(Instruction* instr, const char* format) { 1954 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", 1955 reinterpret_cast<intptr_t>(instr), format); 1956 UNIMPLEMENTED_MIPS(); 1957 } 1958 1959 1960 // Calls into the V8 runtime are based on this very simple interface. 1961 // Note: To be able to return two values from some calls the code in runtime.cc 1962 // uses the ObjectPair which is essentially two 32-bit values stuffed into a 1963 // 64-bit value. With the code below we assume that all runtime calls return 1964 // 64 bits of result. If they don't, the v1 result register contains a bogus 1965 // value, which is fine because it is caller-saved. 1966 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, 1967 int32_t arg1, 1968 int32_t arg2, 1969 int32_t arg3, 1970 int32_t arg4, 1971 int32_t arg5); 1972 1973 // These prototypes handle the four types of FP calls. 1974 typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1); 1975 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1); 1976 typedef double (*SimulatorRuntimeFPCall)(double darg0); 1977 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0); 1978 1979 // This signature supports direct call in to API function native callback 1980 // (refer to InvocationCallback in v8.h). 1981 typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0); 1982 typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1); 1983 1984 // This signature supports direct call to accessor getter callback. 1985 typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1); 1986 typedef void (*SimulatorRuntimeProfilingGetterCall)( 1987 int32_t arg0, int32_t arg1, void* arg2); 1988 1989 // Software interrupt instructions are used by the simulator to call into the 1990 // C-based V8 runtime. They are also used for debugging with simulator. 1991 void Simulator::SoftwareInterrupt(Instruction* instr) { 1992 // There are several instructions that could get us here, 1993 // the break_ instruction, or several variants of traps. All 1994 // Are "SPECIAL" class opcode, and are distinuished by function. 1995 int32_t func = instr->FunctionFieldRaw(); 1996 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; 1997 1998 // We first check if we met a call_rt_redirected. 1999 if (instr->InstructionBits() == rtCallRedirInstr) { 2000 Redirection* redirection = Redirection::FromSwiInstruction(instr); 2001 int32_t arg0 = get_register(a0); 2002 int32_t arg1 = get_register(a1); 2003 int32_t arg2 = get_register(a2); 2004 int32_t arg3 = get_register(a3); 2005 2006 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); 2007 // Args 4 and 5 are on the stack after the reserved space for args 0..3. 2008 int32_t arg4 = stack_pointer[4]; 2009 int32_t arg5 = stack_pointer[5]; 2010 2011 bool fp_call = 2012 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || 2013 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || 2014 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || 2015 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); 2016 2017 if (!IsMipsSoftFloatABI) { 2018 // With the hard floating point calling convention, double 2019 // arguments are passed in FPU registers. Fetch the arguments 2020 // from there and call the builtin using soft floating point 2021 // convention. 2022 switch (redirection->type()) { 2023 case ExternalReference::BUILTIN_FP_FP_CALL: 2024 case ExternalReference::BUILTIN_COMPARE_CALL: 2025 if (IsFp64Mode()) { 2026 arg0 = get_fpu_register_word(f12); 2027 arg1 = get_fpu_register_hi_word(f12); 2028 arg2 = get_fpu_register_word(f14); 2029 arg3 = get_fpu_register_hi_word(f14); 2030 } else { 2031 arg0 = get_fpu_register_word(f12); 2032 arg1 = get_fpu_register_word(f13); 2033 arg2 = get_fpu_register_word(f14); 2034 arg3 = get_fpu_register_word(f15); 2035 } 2036 break; 2037 case ExternalReference::BUILTIN_FP_CALL: 2038 if (IsFp64Mode()) { 2039 arg0 = get_fpu_register_word(f12); 2040 arg1 = get_fpu_register_hi_word(f12); 2041 } else { 2042 arg0 = get_fpu_register_word(f12); 2043 arg1 = get_fpu_register_word(f13); 2044 } 2045 break; 2046 case ExternalReference::BUILTIN_FP_INT_CALL: 2047 if (IsFp64Mode()) { 2048 arg0 = get_fpu_register_word(f12); 2049 arg1 = get_fpu_register_hi_word(f12); 2050 } else { 2051 arg0 = get_fpu_register_word(f12); 2052 arg1 = get_fpu_register_word(f13); 2053 } 2054 arg2 = get_register(a2); 2055 break; 2056 default: 2057 break; 2058 } 2059 } 2060 2061 // This is dodgy but it works because the C entry stubs are never moved. 2062 // See comment in codegen-arm.cc and bug 1242173. 2063 int32_t saved_ra = get_register(ra); 2064 2065 intptr_t external = 2066 reinterpret_cast<intptr_t>(redirection->external_function()); 2067 2068 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware 2069 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this 2070 // simulator. Soft-float has additional abstraction of ExternalReference, 2071 // to support serialization. 2072 if (fp_call) { 2073 double dval0, dval1; // one or two double parameters 2074 int32_t ival; // zero or one integer parameters 2075 int64_t iresult = 0; // integer return value 2076 double dresult = 0; // double return value 2077 GetFpArgs(&dval0, &dval1, &ival); 2078 SimulatorRuntimeCall generic_target = 2079 reinterpret_cast<SimulatorRuntimeCall>(external); 2080 if (::v8::internal::FLAG_trace_sim) { 2081 switch (redirection->type()) { 2082 case ExternalReference::BUILTIN_FP_FP_CALL: 2083 case ExternalReference::BUILTIN_COMPARE_CALL: 2084 PrintF("Call to host function at %p with args %f, %f", 2085 FUNCTION_ADDR(generic_target), dval0, dval1); 2086 break; 2087 case ExternalReference::BUILTIN_FP_CALL: 2088 PrintF("Call to host function at %p with arg %f", 2089 FUNCTION_ADDR(generic_target), dval0); 2090 break; 2091 case ExternalReference::BUILTIN_FP_INT_CALL: 2092 PrintF("Call to host function at %p with args %f, %d", 2093 FUNCTION_ADDR(generic_target), dval0, ival); 2094 break; 2095 default: 2096 UNREACHABLE(); 2097 break; 2098 } 2099 } 2100 switch (redirection->type()) { 2101 case ExternalReference::BUILTIN_COMPARE_CALL: { 2102 SimulatorRuntimeCompareCall target = 2103 reinterpret_cast<SimulatorRuntimeCompareCall>(external); 2104 iresult = target(dval0, dval1); 2105 set_register(v0, static_cast<int32_t>(iresult)); 2106 set_register(v1, static_cast<int32_t>(iresult >> 32)); 2107 break; 2108 } 2109 case ExternalReference::BUILTIN_FP_FP_CALL: { 2110 SimulatorRuntimeFPFPCall target = 2111 reinterpret_cast<SimulatorRuntimeFPFPCall>(external); 2112 dresult = target(dval0, dval1); 2113 SetFpResult(dresult); 2114 break; 2115 } 2116 case ExternalReference::BUILTIN_FP_CALL: { 2117 SimulatorRuntimeFPCall target = 2118 reinterpret_cast<SimulatorRuntimeFPCall>(external); 2119 dresult = target(dval0); 2120 SetFpResult(dresult); 2121 break; 2122 } 2123 case ExternalReference::BUILTIN_FP_INT_CALL: { 2124 SimulatorRuntimeFPIntCall target = 2125 reinterpret_cast<SimulatorRuntimeFPIntCall>(external); 2126 dresult = target(dval0, ival); 2127 SetFpResult(dresult); 2128 break; 2129 } 2130 default: 2131 UNREACHABLE(); 2132 break; 2133 } 2134 if (::v8::internal::FLAG_trace_sim) { 2135 switch (redirection->type()) { 2136 case ExternalReference::BUILTIN_COMPARE_CALL: 2137 PrintF("Returned %08x\n", static_cast<int32_t>(iresult)); 2138 break; 2139 case ExternalReference::BUILTIN_FP_FP_CALL: 2140 case ExternalReference::BUILTIN_FP_CALL: 2141 case ExternalReference::BUILTIN_FP_INT_CALL: 2142 PrintF("Returned %f\n", dresult); 2143 break; 2144 default: 2145 UNREACHABLE(); 2146 break; 2147 } 2148 } 2149 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { 2150 if (::v8::internal::FLAG_trace_sim) { 2151 PrintF("Call to host function at %p args %08x\n", 2152 reinterpret_cast<void*>(external), arg0); 2153 } 2154 SimulatorRuntimeDirectApiCall target = 2155 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); 2156 target(arg0); 2157 } else if ( 2158 redirection->type() == ExternalReference::PROFILING_API_CALL) { 2159 if (::v8::internal::FLAG_trace_sim) { 2160 PrintF("Call to host function at %p args %08x %08x\n", 2161 reinterpret_cast<void*>(external), arg0, arg1); 2162 } 2163 SimulatorRuntimeProfilingApiCall target = 2164 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external); 2165 target(arg0, Redirection::ReverseRedirection(arg1)); 2166 } else if ( 2167 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { 2168 if (::v8::internal::FLAG_trace_sim) { 2169 PrintF("Call to host function at %p args %08x %08x\n", 2170 reinterpret_cast<void*>(external), arg0, arg1); 2171 } 2172 SimulatorRuntimeDirectGetterCall target = 2173 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); 2174 target(arg0, arg1); 2175 } else if ( 2176 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) { 2177 if (::v8::internal::FLAG_trace_sim) { 2178 PrintF("Call to host function at %p args %08x %08x %08x\n", 2179 reinterpret_cast<void*>(external), arg0, arg1, arg2); 2180 } 2181 SimulatorRuntimeProfilingGetterCall target = 2182 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external); 2183 target(arg0, arg1, Redirection::ReverseRedirection(arg2)); 2184 } else { 2185 SimulatorRuntimeCall target = 2186 reinterpret_cast<SimulatorRuntimeCall>(external); 2187 if (::v8::internal::FLAG_trace_sim) { 2188 PrintF( 2189 "Call to host function at %p " 2190 "args %08x, %08x, %08x, %08x, %08x, %08x\n", 2191 FUNCTION_ADDR(target), 2192 arg0, 2193 arg1, 2194 arg2, 2195 arg3, 2196 arg4, 2197 arg5); 2198 } 2199 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); 2200 set_register(v0, static_cast<int32_t>(result)); 2201 set_register(v1, static_cast<int32_t>(result >> 32)); 2202 } 2203 if (::v8::internal::FLAG_trace_sim) { 2204 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0)); 2205 } 2206 set_register(ra, saved_ra); 2207 set_pc(get_register(ra)); 2208 2209 } else if (func == BREAK && code <= kMaxStopCode) { 2210 if (IsWatchpoint(code)) { 2211 PrintWatchpoint(code); 2212 } else { 2213 IncreaseStopCounter(code); 2214 HandleStop(code, instr); 2215 } 2216 } else { 2217 // All remaining break_ codes, and all traps are handled here. 2218 MipsDebugger dbg(this); 2219 dbg.Debug(); 2220 } 2221 } 2222 2223 2224 // Stop helper functions. 2225 bool Simulator::IsWatchpoint(uint32_t code) { 2226 return (code <= kMaxWatchpointCode); 2227 } 2228 2229 2230 void Simulator::PrintWatchpoint(uint32_t code) { 2231 MipsDebugger dbg(this); 2232 ++break_count_; 2233 PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64 2234 ") ----------" 2235 "----------------------------------", 2236 code, break_count_, icount_); 2237 dbg.PrintAllRegs(); // Print registers and continue running. 2238 } 2239 2240 2241 void Simulator::HandleStop(uint32_t code, Instruction* instr) { 2242 // Stop if it is enabled, otherwise go on jumping over the stop 2243 // and the message address. 2244 if (IsEnabledStop(code)) { 2245 MipsDebugger dbg(this); 2246 dbg.Stop(instr); 2247 } else { 2248 set_pc(get_pc() + 2 * Instruction::kInstrSize); 2249 } 2250 } 2251 2252 2253 bool Simulator::IsStopInstruction(Instruction* instr) { 2254 int32_t func = instr->FunctionFieldRaw(); 2255 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6)); 2256 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode; 2257 } 2258 2259 2260 bool Simulator::IsEnabledStop(uint32_t code) { 2261 DCHECK(code <= kMaxStopCode); 2262 DCHECK(code > kMaxWatchpointCode); 2263 return !(watched_stops_[code].count & kStopDisabledBit); 2264 } 2265 2266 2267 void Simulator::EnableStop(uint32_t code) { 2268 if (!IsEnabledStop(code)) { 2269 watched_stops_[code].count &= ~kStopDisabledBit; 2270 } 2271 } 2272 2273 2274 void Simulator::DisableStop(uint32_t code) { 2275 if (IsEnabledStop(code)) { 2276 watched_stops_[code].count |= kStopDisabledBit; 2277 } 2278 } 2279 2280 2281 void Simulator::IncreaseStopCounter(uint32_t code) { 2282 DCHECK(code <= kMaxStopCode); 2283 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { 2284 PrintF("Stop counter for code %i has overflowed.\n" 2285 "Enabling this code and reseting the counter to 0.\n", code); 2286 watched_stops_[code].count = 0; 2287 EnableStop(code); 2288 } else { 2289 watched_stops_[code].count++; 2290 } 2291 } 2292 2293 2294 // Print a stop status. 2295 void Simulator::PrintStopInfo(uint32_t code) { 2296 if (code <= kMaxWatchpointCode) { 2297 PrintF("That is a watchpoint, not a stop.\n"); 2298 return; 2299 } else if (code > kMaxStopCode) { 2300 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1); 2301 return; 2302 } 2303 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled"; 2304 int32_t count = watched_stops_[code].count & ~kStopDisabledBit; 2305 // Don't print the state of unused breakpoints. 2306 if (count != 0) { 2307 if (watched_stops_[code].desc) { 2308 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", 2309 code, code, state, count, watched_stops_[code].desc); 2310 } else { 2311 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", 2312 code, code, state, count); 2313 } 2314 } 2315 } 2316 2317 2318 void Simulator::SignalException(Exception e) { 2319 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", 2320 static_cast<int>(e)); 2321 } 2322 2323 2324 void Simulator::DecodeTypeRegisterDRsType() { 2325 double ft, fs, fd; 2326 uint32_t cc, fcsr_cc; 2327 int64_t i64; 2328 fs = get_fpu_register_double(fs_reg()); 2329 ft = (get_instr()->FunctionFieldRaw() != MOVF) 2330 ? get_fpu_register_double(ft_reg()) 2331 : 0.0; 2332 fd = get_fpu_register_double(fd_reg()); 2333 int64_t ft_int = bit_cast<int64_t>(ft); 2334 int64_t fd_int = bit_cast<int64_t>(fd); 2335 cc = get_instr()->FCccValue(); 2336 fcsr_cc = get_fcsr_condition_bit(cc); 2337 switch (get_instr()->FunctionFieldRaw()) { 2338 case RINT: { 2339 DCHECK(IsMipsArchVariant(kMips32r6)); 2340 double result, temp, temp_result; 2341 double upper = std::ceil(fs); 2342 double lower = std::floor(fs); 2343 switch (get_fcsr_rounding_mode()) { 2344 case kRoundToNearest: 2345 if (upper - fs < fs - lower) { 2346 result = upper; 2347 } else if (upper - fs > fs - lower) { 2348 result = lower; 2349 } else { 2350 temp_result = upper / 2; 2351 double reminder = modf(temp_result, &temp); 2352 if (reminder == 0) { 2353 result = upper; 2354 } else { 2355 result = lower; 2356 } 2357 } 2358 break; 2359 case kRoundToZero: 2360 result = (fs > 0 ? lower : upper); 2361 break; 2362 case kRoundToPlusInf: 2363 result = upper; 2364 break; 2365 case kRoundToMinusInf: 2366 result = lower; 2367 break; 2368 } 2369 set_fpu_register_double(fd_reg(), result); 2370 if (result != fs) { 2371 set_fcsr_bit(kFCSRInexactFlagBit, true); 2372 } 2373 break; 2374 } 2375 case SEL: 2376 DCHECK(IsMipsArchVariant(kMips32r6)); 2377 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); 2378 break; 2379 case SELEQZ_C: 2380 DCHECK(IsMipsArchVariant(kMips32r6)); 2381 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0); 2382 break; 2383 case SELNEZ_C: 2384 DCHECK(IsMipsArchVariant(kMips32r6)); 2385 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0); 2386 break; 2387 case MOVZ_C: { 2388 DCHECK(IsMipsArchVariant(kMips32r2)); 2389 if (rt() == 0) { 2390 set_fpu_register_double(fd_reg(), fs); 2391 } 2392 break; 2393 } 2394 case MOVN_C: { 2395 DCHECK(IsMipsArchVariant(kMips32r2)); 2396 int32_t rt_reg = get_instr()->RtValue(); 2397 int32_t rt = get_register(rt_reg); 2398 if (rt != 0) { 2399 set_fpu_register_double(fd_reg(), fs); 2400 } 2401 break; 2402 } 2403 case MOVF: { 2404 // Same function field for MOVT.D and MOVF.D 2405 uint32_t ft_cc = (ft_reg() >> 2) & 0x7; 2406 ft_cc = get_fcsr_condition_bit(ft_cc); 2407 if (get_instr()->Bit(16)) { // Read Tf bit. 2408 // MOVT.D 2409 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs); 2410 } else { 2411 // MOVF.D 2412 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs); 2413 } 2414 break; 2415 } 2416 case MIN: 2417 DCHECK(IsMipsArchVariant(kMips32r6)); 2418 fs = get_fpu_register_double(fs_reg()); 2419 if (std::isnan(fs) && std::isnan(ft)) { 2420 set_fpu_register_double(fd_reg(), fs); 2421 } else if (std::isnan(fs) && !std::isnan(ft)) { 2422 set_fpu_register_double(fd_reg(), ft); 2423 } else if (!std::isnan(fs) && std::isnan(ft)) { 2424 set_fpu_register_double(fd_reg(), fs); 2425 } else { 2426 set_fpu_register_double(fd_reg(), (fs >= ft) ? ft : fs); 2427 } 2428 break; 2429 case MINA: 2430 DCHECK(IsMipsArchVariant(kMips32r6)); 2431 fs = get_fpu_register_double(fs_reg()); 2432 if (std::isnan(fs) && std::isnan(ft)) { 2433 set_fpu_register_double(fd_reg(), fs); 2434 } else if (std::isnan(fs) && !std::isnan(ft)) { 2435 set_fpu_register_double(fd_reg(), ft); 2436 } else if (!std::isnan(fs) && std::isnan(ft)) { 2437 set_fpu_register_double(fd_reg(), fs); 2438 } else { 2439 double result; 2440 if (fabs(fs) > fabs(ft)) { 2441 result = ft; 2442 } else if (fabs(fs) < fabs(ft)) { 2443 result = fs; 2444 } else { 2445 result = (fs < ft ? fs : ft); 2446 } 2447 set_fpu_register_double(fd_reg(), result); 2448 } 2449 break; 2450 case MAXA: 2451 DCHECK(IsMipsArchVariant(kMips32r6)); 2452 fs = get_fpu_register_double(fs_reg()); 2453 if (std::isnan(fs) && std::isnan(ft)) { 2454 set_fpu_register_double(fd_reg(), fs); 2455 } else if (std::isnan(fs) && !std::isnan(ft)) { 2456 set_fpu_register_double(fd_reg(), ft); 2457 } else if (!std::isnan(fs) && std::isnan(ft)) { 2458 set_fpu_register_double(fd_reg(), fs); 2459 } else { 2460 double result; 2461 if (fabs(fs) < fabs(ft)) { 2462 result = ft; 2463 } else if (fabs(fs) > fabs(ft)) { 2464 result = fs; 2465 } else { 2466 result = (fs > ft ? fs : ft); 2467 } 2468 set_fpu_register_double(fd_reg(), result); 2469 } 2470 break; 2471 case MAX: 2472 DCHECK(IsMipsArchVariant(kMips32r6)); 2473 fs = get_fpu_register_double(fs_reg()); 2474 if (std::isnan(fs) && std::isnan(ft)) { 2475 set_fpu_register_double(fd_reg(), fs); 2476 } else if (std::isnan(fs) && !std::isnan(ft)) { 2477 set_fpu_register_double(fd_reg(), ft); 2478 } else if (!std::isnan(fs) && std::isnan(ft)) { 2479 set_fpu_register_double(fd_reg(), fs); 2480 } else { 2481 set_fpu_register_double(fd_reg(), (fs <= ft) ? ft : fs); 2482 } 2483 break; 2484 break; 2485 case ADD_D: 2486 set_fpu_register_double(fd_reg(), fs + ft); 2487 break; 2488 case SUB_D: 2489 set_fpu_register_double(fd_reg(), fs - ft); 2490 break; 2491 case MUL_D: 2492 set_fpu_register_double(fd_reg(), fs * ft); 2493 break; 2494 case DIV_D: 2495 set_fpu_register_double(fd_reg(), fs / ft); 2496 break; 2497 case ABS_D: 2498 set_fpu_register_double(fd_reg(), fabs(fs)); 2499 break; 2500 case MOV_D: 2501 set_fpu_register_double(fd_reg(), fs); 2502 break; 2503 case NEG_D: 2504 set_fpu_register_double(fd_reg(), -fs); 2505 break; 2506 case SQRT_D: 2507 lazily_initialize_fast_sqrt(isolate_); 2508 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_)); 2509 break; 2510 case RSQRT_D: { 2511 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2512 lazily_initialize_fast_sqrt(isolate_); 2513 double result = 1.0 / fast_sqrt(fs, isolate_); 2514 set_fpu_register_double(fd_reg(), result); 2515 break; 2516 } 2517 case RECIP_D: { 2518 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2519 double result = 1.0 / fs; 2520 set_fpu_register_double(fd_reg(), result); 2521 break; 2522 } 2523 case C_UN_D: 2524 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); 2525 break; 2526 case C_EQ_D: 2527 set_fcsr_bit(fcsr_cc, (fs == ft)); 2528 break; 2529 case C_UEQ_D: 2530 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); 2531 break; 2532 case C_OLT_D: 2533 set_fcsr_bit(fcsr_cc, (fs < ft)); 2534 break; 2535 case C_ULT_D: 2536 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); 2537 break; 2538 case C_OLE_D: 2539 set_fcsr_bit(fcsr_cc, (fs <= ft)); 2540 break; 2541 case C_ULE_D: 2542 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); 2543 break; 2544 case CVT_W_D: { // Convert double to word. 2545 double rounded; 2546 int32_t result; 2547 round_according_to_fcsr(fs, rounded, result, fs); 2548 set_fpu_register_word(fd_reg(), result); 2549 if (set_fcsr_round_error(fs, rounded)) { 2550 set_fpu_register_word_invalid_result(fs, rounded); 2551 } 2552 } break; 2553 case ROUND_W_D: // Round double to word (round half to even). 2554 { 2555 double rounded = std::floor(fs + 0.5); 2556 int32_t result = static_cast<int32_t>(rounded); 2557 if ((result & 1) != 0 && result - fs == 0.5) { 2558 // If the number is halfway between two integers, 2559 // round to the even one. 2560 result--; 2561 } 2562 set_fpu_register_word(fd_reg(), result); 2563 if (set_fcsr_round_error(fs, rounded)) { 2564 set_fpu_register_word_invalid_result(fs, rounded); 2565 } 2566 } break; 2567 case TRUNC_W_D: // Truncate double to word (round towards 0). 2568 { 2569 double rounded = trunc(fs); 2570 int32_t result = static_cast<int32_t>(rounded); 2571 set_fpu_register_word(fd_reg(), result); 2572 if (set_fcsr_round_error(fs, rounded)) { 2573 set_fpu_register_word_invalid_result(fs, rounded); 2574 } 2575 } break; 2576 case FLOOR_W_D: // Round double to word towards negative infinity. 2577 { 2578 double rounded = std::floor(fs); 2579 int32_t result = static_cast<int32_t>(rounded); 2580 set_fpu_register_word(fd_reg(), result); 2581 if (set_fcsr_round_error(fs, rounded)) { 2582 set_fpu_register_word_invalid_result(fs, rounded); 2583 } 2584 } break; 2585 case CEIL_W_D: // Round double to word towards positive infinity. 2586 { 2587 double rounded = std::ceil(fs); 2588 int32_t result = static_cast<int32_t>(rounded); 2589 set_fpu_register_word(fd_reg(), result); 2590 if (set_fcsr_round_error(fs, rounded)) { 2591 set_fpu_register_word_invalid_result(fs, rounded); 2592 } 2593 } break; 2594 case CVT_S_D: // Convert double to float (single). 2595 set_fpu_register_float(fd_reg(), static_cast<float>(fs)); 2596 break; 2597 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word. 2598 if (IsFp64Mode()) { 2599 int64_t result; 2600 double rounded; 2601 round64_according_to_fcsr(fs, rounded, result, fs); 2602 set_fpu_register(fd_reg(), result); 2603 if (set_fcsr_round64_error(fs, rounded)) { 2604 set_fpu_register_invalid_result64(fs, rounded); 2605 } 2606 } else { 2607 UNSUPPORTED(); 2608 } 2609 break; 2610 break; 2611 } 2612 case TRUNC_L_D: { // Mips32r2 instruction. 2613 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2614 double rounded = trunc(fs); 2615 i64 = static_cast<int64_t>(rounded); 2616 if (IsFp64Mode()) { 2617 set_fpu_register(fd_reg(), i64); 2618 if (set_fcsr_round64_error(fs, rounded)) { 2619 set_fpu_register_invalid_result64(fs, rounded); 2620 } 2621 } else { 2622 UNSUPPORTED(); 2623 } 2624 break; 2625 } 2626 case ROUND_L_D: { // Mips32r2 instruction. 2627 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2628 double rounded = std::floor(fs + 0.5); 2629 int64_t result = static_cast<int64_t>(rounded); 2630 if ((result & 1) != 0 && result - fs == 0.5) { 2631 // If the number is halfway between two integers, 2632 // round to the even one. 2633 result--; 2634 } 2635 int64_t i64 = static_cast<int64_t>(result); 2636 if (IsFp64Mode()) { 2637 set_fpu_register(fd_reg(), i64); 2638 if (set_fcsr_round64_error(fs, rounded)) { 2639 set_fpu_register_invalid_result64(fs, rounded); 2640 } 2641 } else { 2642 UNSUPPORTED(); 2643 } 2644 break; 2645 } 2646 case FLOOR_L_D: { // Mips32r2 instruction. 2647 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2648 double rounded = std::floor(fs); 2649 int64_t i64 = static_cast<int64_t>(rounded); 2650 if (IsFp64Mode()) { 2651 set_fpu_register(fd_reg(), i64); 2652 if (set_fcsr_round64_error(fs, rounded)) { 2653 set_fpu_register_invalid_result64(fs, rounded); 2654 } 2655 } else { 2656 UNSUPPORTED(); 2657 } 2658 break; 2659 } 2660 case CEIL_L_D: { // Mips32r2 instruction. 2661 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2662 double rounded = std::ceil(fs); 2663 int64_t i64 = static_cast<int64_t>(rounded); 2664 if (IsFp64Mode()) { 2665 set_fpu_register(fd_reg(), i64); 2666 if (set_fcsr_round64_error(fs, rounded)) { 2667 set_fpu_register_invalid_result64(fs, rounded); 2668 } 2669 } else { 2670 UNSUPPORTED(); 2671 } 2672 break; 2673 } 2674 case CLASS_D: { // Mips32r6 instruction 2675 // Convert double input to uint64_t for easier bit manipulation 2676 uint64_t classed = bit_cast<uint64_t>(fs); 2677 2678 // Extracting sign, exponent and mantissa from the input double 2679 uint32_t sign = (classed >> 63) & 1; 2680 uint32_t exponent = (classed >> 52) & 0x00000000000007ff; 2681 uint64_t mantissa = classed & 0x000fffffffffffff; 2682 uint64_t result; 2683 double dResult; 2684 2685 // Setting flags if input double is negative infinity, 2686 // positive infinity, negative zero or positive zero 2687 bool negInf = (classed == 0xFFF0000000000000); 2688 bool posInf = (classed == 0x7FF0000000000000); 2689 bool negZero = (classed == 0x8000000000000000); 2690 bool posZero = (classed == 0x0000000000000000); 2691 2692 bool signalingNan; 2693 bool quietNan; 2694 bool negSubnorm; 2695 bool posSubnorm; 2696 bool negNorm; 2697 bool posNorm; 2698 2699 // Setting flags if double is NaN 2700 signalingNan = false; 2701 quietNan = false; 2702 if (!negInf && !posInf && exponent == 0x7ff) { 2703 quietNan = ((mantissa & 0x0008000000000000) != 0) && 2704 ((mantissa & (0x0008000000000000 - 1)) == 0); 2705 signalingNan = !quietNan; 2706 } 2707 2708 // Setting flags if double is subnormal number 2709 posSubnorm = false; 2710 negSubnorm = false; 2711 if ((exponent == 0) && (mantissa != 0)) { 2712 DCHECK(sign == 0 || sign == 1); 2713 posSubnorm = (sign == 0); 2714 negSubnorm = (sign == 1); 2715 } 2716 2717 // Setting flags if double is normal number 2718 posNorm = false; 2719 negNorm = false; 2720 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan && 2721 !quietNan && !negZero && !posZero) { 2722 DCHECK(sign == 0 || sign == 1); 2723 posNorm = (sign == 0); 2724 negNorm = (sign == 1); 2725 } 2726 2727 // Calculating result according to description of CLASS.D instruction 2728 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) | 2729 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) | 2730 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan; 2731 2732 DCHECK(result != 0); 2733 2734 dResult = bit_cast<double>(result); 2735 set_fpu_register_double(fd_reg(), dResult); 2736 2737 break; 2738 } 2739 case C_F_D: { 2740 set_fcsr_bit(fcsr_cc, false); 2741 break; 2742 } 2743 default: 2744 UNREACHABLE(); 2745 } 2746 } 2747 2748 2749 void Simulator::DecodeTypeRegisterWRsType() { 2750 float fs = get_fpu_register_float(fs_reg()); 2751 float ft = get_fpu_register_float(ft_reg()); 2752 int32_t alu_out = 0x12345678; 2753 switch (get_instr()->FunctionFieldRaw()) { 2754 case CVT_S_W: // Convert word to float (single). 2755 alu_out = get_fpu_register_signed_word(fs_reg()); 2756 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out)); 2757 break; 2758 case CVT_D_W: // Convert word to double. 2759 alu_out = get_fpu_register_signed_word(fs_reg()); 2760 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out)); 2761 break; 2762 case CMP_AF: 2763 set_fpu_register_word(fd_reg(), 0); 2764 break; 2765 case CMP_UN: 2766 if (std::isnan(fs) || std::isnan(ft)) { 2767 set_fpu_register_word(fd_reg(), -1); 2768 } else { 2769 set_fpu_register_word(fd_reg(), 0); 2770 } 2771 break; 2772 case CMP_EQ: 2773 if (fs == ft) { 2774 set_fpu_register_word(fd_reg(), -1); 2775 } else { 2776 set_fpu_register_word(fd_reg(), 0); 2777 } 2778 break; 2779 case CMP_UEQ: 2780 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { 2781 set_fpu_register_word(fd_reg(), -1); 2782 } else { 2783 set_fpu_register_word(fd_reg(), 0); 2784 } 2785 break; 2786 case CMP_LT: 2787 if (fs < ft) { 2788 set_fpu_register_word(fd_reg(), -1); 2789 } else { 2790 set_fpu_register_word(fd_reg(), 0); 2791 } 2792 break; 2793 case CMP_ULT: 2794 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { 2795 set_fpu_register_word(fd_reg(), -1); 2796 } else { 2797 set_fpu_register_word(fd_reg(), 0); 2798 } 2799 break; 2800 case CMP_LE: 2801 if (fs <= ft) { 2802 set_fpu_register_word(fd_reg(), -1); 2803 } else { 2804 set_fpu_register_word(fd_reg(), 0); 2805 } 2806 break; 2807 case CMP_ULE: 2808 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { 2809 set_fpu_register_word(fd_reg(), -1); 2810 } else { 2811 set_fpu_register_word(fd_reg(), 0); 2812 } 2813 break; 2814 case CMP_OR: 2815 if (!std::isnan(fs) && !std::isnan(ft)) { 2816 set_fpu_register_word(fd_reg(), -1); 2817 } else { 2818 set_fpu_register_word(fd_reg(), 0); 2819 } 2820 break; 2821 case CMP_UNE: 2822 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) { 2823 set_fpu_register_word(fd_reg(), -1); 2824 } else { 2825 set_fpu_register_word(fd_reg(), 0); 2826 } 2827 break; 2828 case CMP_NE: 2829 if (fs != ft) { 2830 set_fpu_register_word(fd_reg(), -1); 2831 } else { 2832 set_fpu_register_word(fd_reg(), 0); 2833 } 2834 break; 2835 default: 2836 UNREACHABLE(); 2837 } 2838 } 2839 2840 2841 void Simulator::DecodeTypeRegisterSRsType() { 2842 float fs, ft, fd; 2843 fs = get_fpu_register_float(fs_reg()); 2844 ft = get_fpu_register_float(ft_reg()); 2845 fd = get_fpu_register_float(fd_reg()); 2846 int32_t ft_int = bit_cast<int32_t>(ft); 2847 int32_t fd_int = bit_cast<int32_t>(fd); 2848 uint32_t cc, fcsr_cc; 2849 cc = get_instr()->FCccValue(); 2850 fcsr_cc = get_fcsr_condition_bit(cc); 2851 switch (get_instr()->FunctionFieldRaw()) { 2852 case RINT: { 2853 DCHECK(IsMipsArchVariant(kMips32r6)); 2854 float result, temp_result; 2855 double temp; 2856 float upper = std::ceil(fs); 2857 float lower = std::floor(fs); 2858 switch (get_fcsr_rounding_mode()) { 2859 case kRoundToNearest: 2860 if (upper - fs < fs - lower) { 2861 result = upper; 2862 } else if (upper - fs > fs - lower) { 2863 result = lower; 2864 } else { 2865 temp_result = upper / 2; 2866 float reminder = modf(temp_result, &temp); 2867 if (reminder == 0) { 2868 result = upper; 2869 } else { 2870 result = lower; 2871 } 2872 } 2873 break; 2874 case kRoundToZero: 2875 result = (fs > 0 ? lower : upper); 2876 break; 2877 case kRoundToPlusInf: 2878 result = upper; 2879 break; 2880 case kRoundToMinusInf: 2881 result = lower; 2882 break; 2883 } 2884 set_fpu_register_float(fd_reg(), result); 2885 if (result != fs) { 2886 set_fcsr_bit(kFCSRInexactFlagBit, true); 2887 } 2888 break; 2889 } 2890 case ADD_S: 2891 set_fpu_register_float(fd_reg(), fs + ft); 2892 break; 2893 case SUB_S: 2894 set_fpu_register_float(fd_reg(), fs - ft); 2895 break; 2896 case MUL_S: 2897 set_fpu_register_float(fd_reg(), fs * ft); 2898 break; 2899 case DIV_S: 2900 set_fpu_register_float(fd_reg(), fs / ft); 2901 break; 2902 case ABS_S: 2903 set_fpu_register_float(fd_reg(), fabs(fs)); 2904 break; 2905 case MOV_S: 2906 set_fpu_register_float(fd_reg(), fs); 2907 break; 2908 case NEG_S: 2909 set_fpu_register_float(fd_reg(), -fs); 2910 break; 2911 case SQRT_S: 2912 lazily_initialize_fast_sqrt(isolate_); 2913 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_)); 2914 break; 2915 case RSQRT_S: { 2916 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2917 lazily_initialize_fast_sqrt(isolate_); 2918 float result = 1.0 / fast_sqrt(fs, isolate_); 2919 set_fpu_register_float(fd_reg(), result); 2920 break; 2921 } 2922 case RECIP_S: { 2923 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2924 float result = 1.0 / fs; 2925 set_fpu_register_float(fd_reg(), result); 2926 break; 2927 } 2928 case C_F_D: 2929 set_fcsr_bit(fcsr_cc, false); 2930 break; 2931 case C_UN_D: 2932 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); 2933 break; 2934 case C_EQ_D: 2935 set_fcsr_bit(fcsr_cc, (fs == ft)); 2936 break; 2937 case C_UEQ_D: 2938 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); 2939 break; 2940 case C_OLT_D: 2941 set_fcsr_bit(fcsr_cc, (fs < ft)); 2942 break; 2943 case C_ULT_D: 2944 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); 2945 break; 2946 case C_OLE_D: 2947 set_fcsr_bit(fcsr_cc, (fs <= ft)); 2948 break; 2949 case C_ULE_D: 2950 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); 2951 break; 2952 case CVT_D_S: 2953 set_fpu_register_double(fd_reg(), static_cast<double>(fs)); 2954 break; 2955 case SEL: 2956 DCHECK(IsMipsArchVariant(kMips32r6)); 2957 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); 2958 break; 2959 case CLASS_S: { // Mips32r6 instruction 2960 // Convert float input to uint32_t for easier bit manipulation 2961 float fs = get_fpu_register_float(fs_reg()); 2962 uint32_t classed = bit_cast<uint32_t>(fs); 2963 2964 // Extracting sign, exponent and mantissa from the input float 2965 uint32_t sign = (classed >> 31) & 1; 2966 uint32_t exponent = (classed >> 23) & 0x000000ff; 2967 uint32_t mantissa = classed & 0x007fffff; 2968 uint32_t result; 2969 float fResult; 2970 2971 // Setting flags if input float is negative infinity, 2972 // positive infinity, negative zero or positive zero 2973 bool negInf = (classed == 0xFF800000); 2974 bool posInf = (classed == 0x7F800000); 2975 bool negZero = (classed == 0x80000000); 2976 bool posZero = (classed == 0x00000000); 2977 2978 bool signalingNan; 2979 bool quietNan; 2980 bool negSubnorm; 2981 bool posSubnorm; 2982 bool negNorm; 2983 bool posNorm; 2984 2985 // Setting flags if float is NaN 2986 signalingNan = false; 2987 quietNan = false; 2988 if (!negInf && !posInf && (exponent == 0xff)) { 2989 quietNan = ((mantissa & 0x00200000) == 0) && 2990 ((mantissa & (0x00200000 - 1)) == 0); 2991 signalingNan = !quietNan; 2992 } 2993 2994 // Setting flags if float is subnormal number 2995 posSubnorm = false; 2996 negSubnorm = false; 2997 if ((exponent == 0) && (mantissa != 0)) { 2998 DCHECK(sign == 0 || sign == 1); 2999 posSubnorm = (sign == 0); 3000 negSubnorm = (sign == 1); 3001 } 3002 3003 // Setting flags if float is normal number 3004 posNorm = false; 3005 negNorm = false; 3006 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan && 3007 !quietNan && !negZero && !posZero) { 3008 DCHECK(sign == 0 || sign == 1); 3009 posNorm = (sign == 0); 3010 negNorm = (sign == 1); 3011 } 3012 3013 // Calculating result according to description of CLASS.S instruction 3014 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) | 3015 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) | 3016 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan; 3017 3018 DCHECK(result != 0); 3019 3020 fResult = bit_cast<float>(result); 3021 set_fpu_register_float(fd_reg(), fResult); 3022 3023 break; 3024 } 3025 case SELEQZ_C: 3026 DCHECK(IsMipsArchVariant(kMips32r6)); 3027 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0 3028 ? get_fpu_register_float(fs_reg()) 3029 : 0.0); 3030 break; 3031 case SELNEZ_C: 3032 DCHECK(IsMipsArchVariant(kMips32r6)); 3033 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0 3034 ? get_fpu_register_float(fs_reg()) 3035 : 0.0); 3036 break; 3037 case MOVZ_C: { 3038 DCHECK(IsMipsArchVariant(kMips32r2)); 3039 if (rt() == 0) { 3040 set_fpu_register_float(fd_reg(), fs); 3041 } 3042 break; 3043 } 3044 case MOVN_C: { 3045 DCHECK(IsMipsArchVariant(kMips32r2)); 3046 if (rt() != 0) { 3047 set_fpu_register_float(fd_reg(), fs); 3048 } 3049 break; 3050 } 3051 case MOVF: { 3052 // Same function field for MOVT.D and MOVF.D 3053 uint32_t ft_cc = (ft_reg() >> 2) & 0x7; 3054 ft_cc = get_fcsr_condition_bit(ft_cc); 3055 3056 if (get_instr()->Bit(16)) { // Read Tf bit. 3057 // MOVT.D 3058 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs); 3059 } else { 3060 // MOVF.D 3061 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs); 3062 } 3063 break; 3064 } 3065 case TRUNC_W_S: { // Truncate single to word (round towards 0). 3066 float rounded = trunc(fs); 3067 int32_t result = static_cast<int32_t>(rounded); 3068 set_fpu_register_word(fd_reg(), result); 3069 if (set_fcsr_round_error(fs, rounded)) { 3070 set_fpu_register_word_invalid_result(fs, rounded); 3071 } 3072 } break; 3073 case TRUNC_L_S: { // Mips32r2 instruction. 3074 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 3075 float rounded = trunc(fs); 3076 int64_t i64 = static_cast<int64_t>(rounded); 3077 if (IsFp64Mode()) { 3078 set_fpu_register(fd_reg(), i64); 3079 if (set_fcsr_round64_error(fs, rounded)) { 3080 set_fpu_register_invalid_result64(fs, rounded); 3081 } 3082 } else { 3083 UNSUPPORTED(); 3084 } 3085 break; 3086 } 3087 case FLOOR_W_S: // Round double to word towards negative infinity. 3088 { 3089 float rounded = std::floor(fs); 3090 int32_t result = static_cast<int32_t>(rounded); 3091 set_fpu_register_word(fd_reg(), result); 3092 if (set_fcsr_round_error(fs, rounded)) { 3093 set_fpu_register_word_invalid_result(fs, rounded); 3094 } 3095 } break; 3096 case FLOOR_L_S: { // Mips32r2 instruction. 3097 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 3098 float rounded = std::floor(fs); 3099 int64_t i64 = static_cast<int64_t>(rounded); 3100 if (IsFp64Mode()) { 3101 set_fpu_register(fd_reg(), i64); 3102 if (set_fcsr_round64_error(fs, rounded)) { 3103 set_fpu_register_invalid_result64(fs, rounded); 3104 } 3105 } else { 3106 UNSUPPORTED(); 3107 } 3108 break; 3109 } 3110 case ROUND_W_S: { 3111 float rounded = std::floor(fs + 0.5); 3112 int32_t result = static_cast<int32_t>(rounded); 3113 if ((result & 1) != 0 && result - fs == 0.5) { 3114 // If the number is halfway between two integers, 3115 // round to the even one. 3116 result--; 3117 } 3118 set_fpu_register_word(fd_reg(), result); 3119 if (set_fcsr_round_error(fs, rounded)) { 3120 set_fpu_register_word_invalid_result(fs, rounded); 3121 } 3122 break; 3123 } 3124 case ROUND_L_S: { // Mips32r2 instruction. 3125 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 3126 float rounded = std::floor(fs + 0.5); 3127 int64_t result = static_cast<int64_t>(rounded); 3128 if ((result & 1) != 0 && result - fs == 0.5) { 3129 // If the number is halfway between two integers, 3130 // round to the even one. 3131 result--; 3132 } 3133 int64_t i64 = static_cast<int64_t>(result); 3134 if (IsFp64Mode()) { 3135 set_fpu_register(fd_reg(), i64); 3136 if (set_fcsr_round64_error(fs, rounded)) { 3137 set_fpu_register_invalid_result64(fs, rounded); 3138 } 3139 } else { 3140 UNSUPPORTED(); 3141 } 3142 break; 3143 } 3144 case CEIL_W_S: // Round double to word towards positive infinity. 3145 { 3146 float rounded = std::ceil(fs); 3147 int32_t result = static_cast<int32_t>(rounded); 3148 set_fpu_register_word(fd_reg(), result); 3149 if (set_fcsr_round_error(fs, rounded)) { 3150 set_fpu_register_word_invalid_result(fs, rounded); 3151 } 3152 } break; 3153 case CEIL_L_S: { // Mips32r2 instruction. 3154 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 3155 float rounded = std::ceil(fs); 3156 int64_t i64 = static_cast<int64_t>(rounded); 3157 if (IsFp64Mode()) { 3158 set_fpu_register(fd_reg(), i64); 3159 if (set_fcsr_round64_error(fs, rounded)) { 3160 set_fpu_register_invalid_result64(fs, rounded); 3161 } 3162 } else { 3163 UNSUPPORTED(); 3164 } 3165 break; 3166 } 3167 case MIN: 3168 DCHECK(IsMipsArchVariant(kMips32r6)); 3169 fs = get_fpu_register_float(fs_reg()); 3170 if (std::isnan(fs) && std::isnan(ft)) { 3171 set_fpu_register_float(fd_reg(), fs); 3172 } else if (std::isnan(fs) && !std::isnan(ft)) { 3173 set_fpu_register_float(fd_reg(), ft); 3174 } else if (!std::isnan(fs) && std::isnan(ft)) { 3175 set_fpu_register_float(fd_reg(), fs); 3176 } else { 3177 set_fpu_register_float(fd_reg(), (fs >= ft) ? ft : fs); 3178 } 3179 break; 3180 case MAX: 3181 DCHECK(IsMipsArchVariant(kMips32r6)); 3182 fs = get_fpu_register_float(fs_reg()); 3183 if (std::isnan(fs) && std::isnan(ft)) { 3184 set_fpu_register_float(fd_reg(), fs); 3185 } else if (std::isnan(fs) && !std::isnan(ft)) { 3186 set_fpu_register_float(fd_reg(), ft); 3187 } else if (!std::isnan(fs) && std::isnan(ft)) { 3188 set_fpu_register_float(fd_reg(), fs); 3189 } else { 3190 set_fpu_register_float(fd_reg(), (fs <= ft) ? ft : fs); 3191 } 3192 break; 3193 case MINA: 3194 DCHECK(IsMipsArchVariant(kMips32r6)); 3195 fs = get_fpu_register_float(fs_reg()); 3196 if (std::isnan(fs) && std::isnan(ft)) { 3197 set_fpu_register_float(fd_reg(), fs); 3198 } else if (std::isnan(fs) && !std::isnan(ft)) { 3199 set_fpu_register_float(fd_reg(), ft); 3200 } else if (!std::isnan(fs) && std::isnan(ft)) { 3201 set_fpu_register_float(fd_reg(), fs); 3202 } else { 3203 float result; 3204 if (fabs(fs) > fabs(ft)) { 3205 result = ft; 3206 } else if (fabs(fs) < fabs(ft)) { 3207 result = fs; 3208 } else { 3209 result = (fs < ft ? fs : ft); 3210 } 3211 set_fpu_register_float(fd_reg(), result); 3212 } 3213 break; 3214 case MAXA: 3215 DCHECK(IsMipsArchVariant(kMips32r6)); 3216 fs = get_fpu_register_float(fs_reg()); 3217 if (std::isnan(fs) && std::isnan(ft)) { 3218 set_fpu_register_float(fd_reg(), fs); 3219 } else if (std::isnan(fs) && !std::isnan(ft)) { 3220 set_fpu_register_float(fd_reg(), ft); 3221 } else if (!std::isnan(fs) && std::isnan(ft)) { 3222 set_fpu_register_float(fd_reg(), fs); 3223 } else { 3224 float result; 3225 if (fabs(fs) < fabs(ft)) { 3226 result = ft; 3227 } else if (fabs(fs) > fabs(ft)) { 3228 result = fs; 3229 } else { 3230 result = (fs > ft ? fs : ft); 3231 } 3232 set_fpu_register_float(fd_reg(), result); 3233 } 3234 break; 3235 case CVT_L_S: { 3236 if (IsFp64Mode()) { 3237 int64_t result; 3238 float rounded; 3239 round64_according_to_fcsr(fs, rounded, result, fs); 3240 set_fpu_register(fd_reg(), result); 3241 if (set_fcsr_round64_error(fs, rounded)) { 3242 set_fpu_register_invalid_result64(fs, rounded); 3243 } 3244 } else { 3245 UNSUPPORTED(); 3246 } 3247 break; 3248 } 3249 case CVT_W_S: { 3250 float rounded; 3251 int32_t result; 3252 round_according_to_fcsr(fs, rounded, result, fs); 3253 set_fpu_register_word(fd_reg(), result); 3254 if (set_fcsr_round_error(fs, rounded)) { 3255 set_fpu_register_word_invalid_result(fs, rounded); 3256 } 3257 break; 3258 } 3259 default: 3260 // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S 3261 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. 3262 UNREACHABLE(); 3263 } 3264 } 3265 3266 3267 void Simulator::DecodeTypeRegisterLRsType() { 3268 double fs = get_fpu_register_double(fs_reg()); 3269 double ft = get_fpu_register_double(ft_reg()); 3270 switch (get_instr()->FunctionFieldRaw()) { 3271 case CVT_D_L: // Mips32r2 instruction. 3272 // Watch the signs here, we want 2 32-bit vals 3273 // to make a sign-64. 3274 int64_t i64; 3275 if (IsFp64Mode()) { 3276 i64 = get_fpu_register(fs_reg()); 3277 } else { 3278 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg())); 3279 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32; 3280 } 3281 set_fpu_register_double(fd_reg(), static_cast<double>(i64)); 3282 break; 3283 case CVT_S_L: 3284 if (IsFp64Mode()) { 3285 i64 = get_fpu_register(fs_reg()); 3286 } else { 3287 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg())); 3288 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32; 3289 } 3290 set_fpu_register_float(fd_reg(), static_cast<float>(i64)); 3291 break; 3292 case CMP_AF: // Mips64r6 CMP.D instructions. 3293 set_fpu_register(fd_reg(), 0); 3294 break; 3295 case CMP_UN: 3296 if (std::isnan(fs) || std::isnan(ft)) { 3297 set_fpu_register(fd_reg(), -1); 3298 } else { 3299 set_fpu_register(fd_reg(), 0); 3300 } 3301 break; 3302 case CMP_EQ: 3303 if (fs == ft) { 3304 set_fpu_register(fd_reg(), -1); 3305 } else { 3306 set_fpu_register(fd_reg(), 0); 3307 } 3308 break; 3309 case CMP_UEQ: 3310 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { 3311 set_fpu_register(fd_reg(), -1); 3312 } else { 3313 set_fpu_register(fd_reg(), 0); 3314 } 3315 break; 3316 case CMP_LT: 3317 if (fs < ft) { 3318 set_fpu_register(fd_reg(), -1); 3319 } else { 3320 set_fpu_register(fd_reg(), 0); 3321 } 3322 break; 3323 case CMP_ULT: 3324 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { 3325 set_fpu_register(fd_reg(), -1); 3326 } else { 3327 set_fpu_register(fd_reg(), 0); 3328 } 3329 break; 3330 case CMP_LE: 3331 if (fs <= ft) { 3332 set_fpu_register(fd_reg(), -1); 3333 } else { 3334 set_fpu_register(fd_reg(), 0); 3335 } 3336 break; 3337 case CMP_ULE: 3338 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { 3339 set_fpu_register(fd_reg(), -1); 3340 } else { 3341 set_fpu_register(fd_reg(), 0); 3342 } 3343 break; 3344 case CMP_OR: 3345 if (!std::isnan(fs) && !std::isnan(ft)) { 3346 set_fpu_register(fd_reg(), -1); 3347 } else { 3348 set_fpu_register(fd_reg(), 0); 3349 } 3350 break; 3351 case CMP_UNE: 3352 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) { 3353 set_fpu_register(fd_reg(), -1); 3354 } else { 3355 set_fpu_register(fd_reg(), 0); 3356 } 3357 break; 3358 case CMP_NE: 3359 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) { 3360 set_fpu_register(fd_reg(), -1); 3361 } else { 3362 set_fpu_register(fd_reg(), 0); 3363 } 3364 break; 3365 default: 3366 UNREACHABLE(); 3367 } 3368 } 3369 3370 3371 void Simulator::DecodeTypeRegisterCOP1() { 3372 switch (get_instr()->RsFieldRaw()) { 3373 case CFC1: 3374 // At the moment only FCSR is supported. 3375 DCHECK(fs_reg() == kFCSRRegister); 3376 set_register(rt_reg(), FCSR_); 3377 break; 3378 case MFC1: 3379 set_register(rt_reg(), get_fpu_register_word(fs_reg())); 3380 break; 3381 case MFHC1: 3382 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg())); 3383 break; 3384 case CTC1: { 3385 // At the moment only FCSR is supported. 3386 DCHECK(fs_reg() == kFCSRRegister); 3387 int32_t reg = registers_[rt_reg()]; 3388 if (IsMipsArchVariant(kMips32r6)) { 3389 FCSR_ = reg | kFCSRNaN2008FlagMask; 3390 } else { 3391 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2)); 3392 FCSR_ = reg & ~kFCSRNaN2008FlagMask; 3393 } 3394 break; 3395 } 3396 case MTC1: 3397 // Hardware writes upper 32-bits to zero on mtc1. 3398 set_fpu_register_hi_word(fs_reg(), 0); 3399 set_fpu_register_word(fs_reg(), registers_[rt_reg()]); 3400 break; 3401 case MTHC1: 3402 set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]); 3403 break; 3404 case S: { 3405 DecodeTypeRegisterSRsType(); 3406 break; 3407 } 3408 case D: 3409 DecodeTypeRegisterDRsType(); 3410 break; 3411 case W: 3412 DecodeTypeRegisterWRsType(); 3413 break; 3414 case L: 3415 DecodeTypeRegisterLRsType(); 3416 break; 3417 case PS: 3418 // Not implemented. 3419 UNREACHABLE(); 3420 default: 3421 UNREACHABLE(); 3422 } 3423 } 3424 3425 3426 void Simulator::DecodeTypeRegisterCOP1X() { 3427 switch (get_instr()->FunctionFieldRaw()) { 3428 case MADD_D: 3429 double fr, ft, fs; 3430 fr = get_fpu_register_double(fr_reg()); 3431 fs = get_fpu_register_double(fs_reg()); 3432 ft = get_fpu_register_double(ft_reg()); 3433 set_fpu_register_double(fd_reg(), fs * ft + fr); 3434 break; 3435 default: 3436 UNREACHABLE(); 3437 } 3438 } 3439 3440 3441 void Simulator::DecodeTypeRegisterSPECIAL() { 3442 int64_t alu_out = 0x12345678; 3443 int64_t i64hilo = 0; 3444 uint64_t u64hilo = 0; 3445 bool do_interrupt = false; 3446 3447 switch (get_instr()->FunctionFieldRaw()) { 3448 case SELEQZ_S: 3449 DCHECK(IsMipsArchVariant(kMips32r6)); 3450 set_register(rd_reg(), rt() == 0 ? rs() : 0); 3451 break; 3452 case SELNEZ_S: 3453 DCHECK(IsMipsArchVariant(kMips32r6)); 3454 set_register(rd_reg(), rt() != 0 ? rs() : 0); 3455 break; 3456 case JR: { 3457 int32_t next_pc = rs(); 3458 int32_t current_pc = get_pc(); 3459 Instruction* branch_delay_instr = 3460 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); 3461 BranchDelayInstructionDecode(branch_delay_instr); 3462 set_pc(next_pc); 3463 pc_modified_ = true; 3464 break; 3465 } 3466 case JALR: { 3467 int32_t next_pc = rs(); 3468 int32_t return_addr_reg = rd_reg(); 3469 int32_t current_pc = get_pc(); 3470 Instruction* branch_delay_instr = 3471 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); 3472 BranchDelayInstructionDecode(branch_delay_instr); 3473 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize); 3474 set_pc(next_pc); 3475 pc_modified_ = true; 3476 break; 3477 } 3478 case SLL: 3479 alu_out = rt() << sa(); 3480 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3481 break; 3482 case SRL: 3483 if (rs_reg() == 0) { 3484 // Regular logical right shift of a word by a fixed number of 3485 // bits instruction. RS field is always equal to 0. 3486 alu_out = rt_u() >> sa(); 3487 } else { 3488 // Logical right-rotate of a word by a fixed number of bits. This 3489 // is special case of SRL instruction, added in MIPS32 Release 2. 3490 // RS field is equal to 00001. 3491 alu_out = base::bits::RotateRight32(rt_u(), sa()); 3492 } 3493 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3494 break; 3495 case SRA: 3496 alu_out = rt() >> sa(); 3497 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3498 break; 3499 case SLLV: 3500 alu_out = rt() << rs(); 3501 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3502 break; 3503 case SRLV: 3504 if (sa() == 0) { 3505 // Regular logical right-shift of a word by a variable number of 3506 // bits instruction. SA field is always equal to 0. 3507 alu_out = rt_u() >> rs(); 3508 } else { 3509 // Logical right-rotate of a word by a variable number of bits. 3510 // This is special case od SRLV instruction, added in MIPS32 3511 // Release 2. SA field is equal to 00001. 3512 alu_out = base::bits::RotateRight32(rt_u(), rs_u()); 3513 } 3514 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3515 break; 3516 case SRAV: 3517 SetResult(rd_reg(), rt() >> rs()); 3518 break; 3519 case LSA: { 3520 DCHECK(IsMipsArchVariant(kMips32r6)); 3521 int8_t sa = lsa_sa() + 1; 3522 int32_t _rt = rt(); 3523 int32_t _rs = rs(); 3524 int32_t res = _rs << sa; 3525 res += _rt; 3526 DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt()); 3527 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt()); 3528 break; 3529 } 3530 case MFHI: // MFHI == CLZ on R6. 3531 if (!IsMipsArchVariant(kMips32r6)) { 3532 DCHECK(sa() == 0); 3533 alu_out = get_register(HI); 3534 } else { 3535 // MIPS spec: If no bits were set in GPR rs, the result written to 3536 // GPR rd is 32. 3537 DCHECK(sa() == 1); 3538 alu_out = base::bits::CountLeadingZeros32(rs_u()); 3539 } 3540 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3541 break; 3542 case MFLO: 3543 alu_out = get_register(LO); 3544 SetResult(rd_reg(), static_cast<int32_t>(alu_out)); 3545 break; 3546 // Instructions using HI and LO registers. 3547 case MULT: 3548 i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt()); 3549 if (!IsMipsArchVariant(kMips32r6)) { 3550 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); 3551 set_register(HI, static_cast<int32_t>(i64hilo >> 32)); 3552 } else { 3553 switch (sa()) { 3554 case MUL_OP: 3555 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff)); 3556 break; 3557 case MUH_OP: 3558 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32)); 3559 break; 3560 default: 3561 UNIMPLEMENTED_MIPS(); 3562 break; 3563 } 3564 } 3565 break; 3566 case MULTU: 3567 u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u()); 3568 if (!IsMipsArchVariant(kMips32r6)) { 3569 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); 3570 set_register(HI, static_cast<int32_t>(u64hilo >> 32)); 3571 } else { 3572 switch (sa()) { 3573 case MUL_OP: 3574 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff)); 3575 break; 3576 case MUH_OP: 3577 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32)); 3578 break; 3579 default: 3580 UNIMPLEMENTED_MIPS(); 3581 break; 3582 } 3583 } 3584 break; 3585 case DIV: 3586 if (IsMipsArchVariant(kMips32r6)) { 3587 switch (get_instr()->SaValue()) { 3588 case DIV_OP: 3589 if (rs() == INT_MIN && rt() == -1) { 3590 set_register(rd_reg(), INT_MIN); 3591 } else if (rt() != 0) { 3592 set_register(rd_reg(), rs() / rt()); 3593 } 3594 break; 3595 case MOD_OP: 3596 if (rs() == INT_MIN && rt() == -1) { 3597 set_register(rd_reg(), 0); 3598 } else if (rt() != 0) { 3599 set_register(rd_reg(), rs() % rt()); 3600 } 3601 break; 3602 default: 3603 UNIMPLEMENTED_MIPS(); 3604 break; 3605 } 3606 } else { 3607 // Divide by zero and overflow was not checked in the 3608 // configuration step - div and divu do not raise exceptions. On 3609 // division by 0 the result will be UNPREDICTABLE. On overflow 3610 // (INT_MIN/-1), return INT_MIN which is what the hardware does. 3611 if (rs() == INT_MIN && rt() == -1) { 3612 set_register(LO, INT_MIN); 3613 set_register(HI, 0); 3614 } else if (rt() != 0) { 3615 set_register(LO, rs() / rt()); 3616 set_register(HI, rs() % rt()); 3617 } 3618 } 3619 break; 3620 case DIVU: 3621 if (IsMipsArchVariant(kMips32r6)) { 3622 switch (get_instr()->SaValue()) { 3623 case DIV_OP: 3624 if (rt_u() != 0) { 3625 set_register(rd_reg(), rs_u() / rt_u()); 3626 } 3627 break; 3628 case MOD_OP: 3629 if (rt_u() != 0) { 3630 set_register(rd_reg(), rs_u() % rt_u()); 3631 } 3632 break; 3633 default: 3634 UNIMPLEMENTED_MIPS(); 3635 break; 3636 } 3637 } else { 3638 if (rt_u() != 0) { 3639 set_register(LO, rs_u() / rt_u()); 3640 set_register(HI, rs_u() % rt_u()); 3641 } 3642 } 3643 break; 3644 case ADD: 3645 if (HaveSameSign(rs(), rt())) { 3646 if (rs() > 0) { 3647 if (rs() <= (Registers::kMaxValue - rt())) { 3648 SignalException(kIntegerOverflow); 3649 } 3650 } else if (rs() < 0) { 3651 if (rs() >= (Registers::kMinValue - rt())) { 3652 SignalException(kIntegerUnderflow); 3653 } 3654 } 3655 } 3656 SetResult(rd_reg(), rs() + rt()); 3657 break; 3658 case ADDU: 3659 SetResult(rd_reg(), rs() + rt()); 3660 break; 3661 case SUB: 3662 if (!HaveSameSign(rs(), rt())) { 3663 if (rs() > 0) { 3664 if (rs() <= (Registers::kMaxValue + rt())) { 3665 SignalException(kIntegerOverflow); 3666 } 3667 } else if (rs() < 0) { 3668 if (rs() >= (Registers::kMinValue + rt())) { 3669 SignalException(kIntegerUnderflow); 3670 } 3671 } 3672 } 3673 SetResult(rd_reg(), rs() - rt()); 3674 break; 3675 case SUBU: 3676 SetResult(rd_reg(), rs() - rt()); 3677 break; 3678 case AND: 3679 SetResult(rd_reg(), rs() & rt()); 3680 break; 3681 case OR: 3682 SetResult(rd_reg(), rs() | rt()); 3683 break; 3684 case XOR: 3685 SetResult(rd_reg(), rs() ^ rt()); 3686 break; 3687 case NOR: 3688 SetResult(rd_reg(), ~(rs() | rt())); 3689 break; 3690 case SLT: 3691 SetResult(rd_reg(), rs() < rt() ? 1 : 0); 3692 break; 3693 case SLTU: 3694 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0); 3695 break; 3696 // Break and trap instructions. 3697 case BREAK: 3698 do_interrupt = true; 3699 break; 3700 case TGE: 3701 do_interrupt = rs() >= rt(); 3702 break; 3703 case TGEU: 3704 do_interrupt = rs_u() >= rt_u(); 3705 break; 3706 case TLT: 3707 do_interrupt = rs() < rt(); 3708 break; 3709 case TLTU: 3710 do_interrupt = rs_u() < rt_u(); 3711 break; 3712 case TEQ: 3713 do_interrupt = rs() == rt(); 3714 break; 3715 case TNE: 3716 do_interrupt = rs() != rt(); 3717 break; 3718 // Conditional moves. 3719 case MOVN: 3720 if (rt()) { 3721 set_register(rd_reg(), rs()); 3722 TraceRegWr(rs()); 3723 } 3724 break; 3725 case MOVCI: { 3726 uint32_t cc = get_instr()->FBccValue(); 3727 uint32_t fcsr_cc = get_fcsr_condition_bit(cc); 3728 if (get_instr()->Bit(16)) { // Read Tf bit. 3729 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); 3730 } else { 3731 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); 3732 } 3733 break; 3734 } 3735 case MOVZ: 3736 if (!rt()) { 3737 set_register(rd_reg(), rs()); 3738 TraceRegWr(rs()); 3739 } 3740 break; 3741 default: 3742 UNREACHABLE(); 3743 } 3744 if (do_interrupt) { 3745 SoftwareInterrupt(get_instr()); 3746 } 3747 } 3748 3749 3750 void Simulator::DecodeTypeRegisterSPECIAL2() { 3751 int32_t alu_out; 3752 switch (get_instr()->FunctionFieldRaw()) { 3753 case MUL: 3754 // Only the lower 32 bits are kept. 3755 alu_out = rs_u() * rt_u(); 3756 // HI and LO are UNPREDICTABLE after the operation. 3757 set_register(LO, Unpredictable); 3758 set_register(HI, Unpredictable); 3759 break; 3760 case CLZ: 3761 // MIPS32 spec: If no bits were set in GPR rs, the result written to 3762 // GPR rd is 32. 3763 alu_out = base::bits::CountLeadingZeros32(rs_u()); 3764 break; 3765 default: 3766 alu_out = 0x12345678; 3767 UNREACHABLE(); 3768 } 3769 SetResult(rd_reg(), alu_out); 3770 } 3771 3772 3773 void Simulator::DecodeTypeRegisterSPECIAL3() { 3774 int32_t alu_out; 3775 switch (get_instr()->FunctionFieldRaw()) { 3776 case INS: { // Mips32r2 instruction. 3777 // Interpret rd field as 5-bit msb of insert. 3778 uint16_t msb = rd_reg(); 3779 // Interpret sa field as 5-bit lsb of insert. 3780 uint16_t lsb = sa(); 3781 uint16_t size = msb - lsb + 1; 3782 uint32_t mask = (1 << size) - 1; 3783 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb); 3784 // Ins instr leaves result in Rt, rather than Rd. 3785 SetResult(rt_reg(), alu_out); 3786 break; 3787 } 3788 case EXT: { // Mips32r2 instruction. 3789 // Interpret rd field as 5-bit msb of extract. 3790 uint16_t msb = rd_reg(); 3791 // Interpret sa field as 5-bit lsb of extract. 3792 uint16_t lsb = sa(); 3793 uint16_t size = msb + 1; 3794 uint32_t mask = (1 << size) - 1; 3795 alu_out = (rs_u() & (mask << lsb)) >> lsb; 3796 SetResult(rt_reg(), alu_out); 3797 break; 3798 } 3799 case BSHFL: { 3800 int sa = get_instr()->SaFieldRaw() >> kSaShift; 3801 switch (sa) { 3802 case BITSWAP: { 3803 uint32_t input = static_cast<uint32_t>(rt()); 3804 uint32_t output = 0; 3805 uint8_t i_byte, o_byte; 3806 3807 // Reverse the bit in byte for each individual byte 3808 for (int i = 0; i < 4; i++) { 3809 output = output >> 8; 3810 i_byte = input & 0xff; 3811 3812 // Fast way to reverse bits in byte 3813 // Devised by Sean Anderson, July 13, 2001 3814 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | 3815 (i_byte * 0x8020LU & 0x88440LU)) * 3816 0x10101LU >> 3817 16); 3818 3819 output = output | (static_cast<uint32_t>(o_byte << 24)); 3820 input = input >> 8; 3821 } 3822 3823 alu_out = static_cast<int32_t>(output); 3824 break; 3825 } 3826 case SEB: 3827 case SEH: 3828 case WSBH: 3829 alu_out = 0x12345678; 3830 UNREACHABLE(); 3831 break; 3832 default: { 3833 const uint8_t bp = get_instr()->Bp2Value(); 3834 sa >>= kBp2Bits; 3835 switch (sa) { 3836 case ALIGN: { 3837 if (bp == 0) { 3838 alu_out = static_cast<int32_t>(rt()); 3839 } else { 3840 uint32_t rt_hi = rt() << (8 * bp); 3841 uint32_t rs_lo = rs() >> (8 * (4 - bp)); 3842 alu_out = static_cast<int32_t>(rt_hi | rs_lo); 3843 } 3844 break; 3845 } 3846 default: 3847 alu_out = 0x12345678; 3848 UNREACHABLE(); 3849 break; 3850 } 3851 } 3852 } 3853 SetResult(rd_reg(), alu_out); 3854 break; 3855 } 3856 default: 3857 UNREACHABLE(); 3858 } 3859 } 3860 3861 3862 void Simulator::DecodeTypeRegister(Instruction* instr) { 3863 const Opcode op = instr->OpcodeFieldRaw(); 3864 3865 // Set up the variables if needed before executing the instruction. 3866 // ConfigureTypeRegister(instr); 3867 set_instr(instr); 3868 3869 // ---------- Execution. 3870 switch (op) { 3871 case COP1: 3872 DecodeTypeRegisterCOP1(); 3873 break; 3874 case COP1X: 3875 DecodeTypeRegisterCOP1X(); 3876 break; 3877 case SPECIAL: 3878 DecodeTypeRegisterSPECIAL(); 3879 break; 3880 case SPECIAL2: 3881 DecodeTypeRegisterSPECIAL2(); 3882 break; 3883 case SPECIAL3: 3884 DecodeTypeRegisterSPECIAL3(); 3885 break; 3886 default: 3887 UNREACHABLE(); 3888 } 3889 } 3890 3891 3892 // Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc). 3893 void Simulator::DecodeTypeImmediate(Instruction* instr) { 3894 // Instruction fields. 3895 Opcode op = instr->OpcodeFieldRaw(); 3896 int32_t rs_reg = instr->RsValue(); 3897 int32_t rs = get_register(instr->RsValue()); 3898 uint32_t rs_u = static_cast<uint32_t>(rs); 3899 int32_t rt_reg = instr->RtValue(); // Destination register. 3900 int32_t rt = get_register(rt_reg); 3901 int16_t imm16 = instr->Imm16Value(); 3902 3903 int32_t ft_reg = instr->FtValue(); // Destination register. 3904 3905 // Zero extended immediate. 3906 uint32_t oe_imm16 = 0xffff & imm16; 3907 // Sign extended immediate. 3908 int32_t se_imm16 = imm16; 3909 3910 // Next pc. 3911 int32_t next_pc = bad_ra; 3912 3913 // Used for conditional branch instructions. 3914 bool execute_branch_delay_instruction = false; 3915 3916 // Used for arithmetic instructions. 3917 int32_t alu_out = 0; 3918 3919 // Used for memory instructions. 3920 int32_t addr = 0x0; 3921 3922 // Branch instructions common part. 3923 auto BranchAndLinkHelper = [this, instr, &next_pc, 3924 &execute_branch_delay_instruction]( 3925 bool do_branch) { 3926 execute_branch_delay_instruction = true; 3927 int32_t current_pc = get_pc(); 3928 if (do_branch) { 3929 int16_t imm16 = instr->Imm16Value(); 3930 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; 3931 set_register(31, current_pc + 2 * Instruction::kInstrSize); 3932 } else { 3933 next_pc = current_pc + 2 * Instruction::kInstrSize; 3934 } 3935 }; 3936 3937 auto BranchHelper = [this, instr, &next_pc, 3938 &execute_branch_delay_instruction](bool do_branch) { 3939 execute_branch_delay_instruction = true; 3940 int32_t current_pc = get_pc(); 3941 if (do_branch) { 3942 int16_t imm16 = instr->Imm16Value(); 3943 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; 3944 } else { 3945 next_pc = current_pc + 2 * Instruction::kInstrSize; 3946 } 3947 }; 3948 3949 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch, 3950 int bits) { 3951 int32_t current_pc = get_pc(); 3952 CheckForbiddenSlot(current_pc); 3953 if (do_branch) { 3954 int32_t imm = instr->ImmValue(bits); 3955 imm <<= 32 - bits; 3956 imm >>= 32 - bits; 3957 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize; 3958 set_register(31, current_pc + Instruction::kInstrSize); 3959 } 3960 }; 3961 3962 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) { 3963 int32_t current_pc = get_pc(); 3964 CheckForbiddenSlot(current_pc); 3965 if (do_branch) { 3966 int32_t imm = instr->ImmValue(bits); 3967 imm <<= 32 - bits; 3968 imm >>= 32 - bits; 3969 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize; 3970 } 3971 }; 3972 3973 3974 switch (op) { 3975 // ------------- COP1. Coprocessor instructions. 3976 case COP1: 3977 switch (instr->RsFieldRaw()) { 3978 case BC1: { // Branch on coprocessor condition. 3979 // Floating point. 3980 uint32_t cc = instr->FBccValue(); 3981 uint32_t fcsr_cc = get_fcsr_condition_bit(cc); 3982 uint32_t cc_value = test_fcsr_bit(fcsr_cc); 3983 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; 3984 BranchHelper(do_branch); 3985 break; 3986 } 3987 case BC1EQZ: 3988 BranchHelper(!(get_fpu_register(ft_reg) & 0x1)); 3989 break; 3990 case BC1NEZ: 3991 BranchHelper(get_fpu_register(ft_reg) & 0x1); 3992 break; 3993 default: 3994 UNREACHABLE(); 3995 } 3996 break; 3997 // ------------- REGIMM class. 3998 case REGIMM: 3999 switch (instr->RtFieldRaw()) { 4000 case BLTZ: 4001 BranchHelper(rs < 0); 4002 break; 4003 case BGEZ: 4004 BranchHelper(rs >= 0); 4005 break; 4006 case BLTZAL: 4007 BranchAndLinkHelper(rs < 0); 4008 break; 4009 case BGEZAL: 4010 BranchAndLinkHelper(rs >= 0); 4011 break; 4012 default: 4013 UNREACHABLE(); 4014 } 4015 break; // case REGIMM. 4016 // ------------- Branch instructions. 4017 // When comparing to zero, the encoding of rt field is always 0, so we don't 4018 // need to replace rt with zero. 4019 case BEQ: 4020 BranchHelper(rs == rt); 4021 break; 4022 case BNE: 4023 BranchHelper(rs != rt); 4024 break; 4025 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6) 4026 if (IsMipsArchVariant(kMips32r6)) { 4027 if (rt_reg != 0) { 4028 if (rs_reg == 0) { // BLEZALC 4029 BranchAndLinkCompactHelper(rt <= 0, 16); 4030 } else { 4031 if (rs_reg == rt_reg) { // BGEZALC 4032 BranchAndLinkCompactHelper(rt >= 0, 16); 4033 } else { // BGEUC 4034 BranchCompactHelper( 4035 static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16); 4036 } 4037 } 4038 } else { // BLEZ 4039 BranchHelper(rs <= 0); 4040 } 4041 } else { // BLEZ 4042 BranchHelper(rs <= 0); 4043 } 4044 break; 4045 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6) 4046 if (IsMipsArchVariant(kMips32r6)) { 4047 if (rt_reg != 0) { 4048 if (rs_reg == 0) { // BGTZALC 4049 BranchAndLinkCompactHelper(rt > 0, 16); 4050 } else { 4051 if (rt_reg == rs_reg) { // BLTZALC 4052 BranchAndLinkCompactHelper(rt < 0, 16); 4053 } else { // BLTUC 4054 BranchCompactHelper( 4055 static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16); 4056 } 4057 } 4058 } else { // BGTZ 4059 BranchHelper(rs > 0); 4060 } 4061 } else { // BGTZ 4062 BranchHelper(rs > 0); 4063 } 4064 break; 4065 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6) 4066 if (IsMipsArchVariant(kMips32r6)) { 4067 if (rt_reg != 0) { 4068 if (rs_reg == 0) { // BLEZC 4069 BranchCompactHelper(rt <= 0, 16); 4070 } else { 4071 if (rs_reg == rt_reg) { // BGEZC 4072 BranchCompactHelper(rt >= 0, 16); 4073 } else { // BGEC/BLEC 4074 BranchCompactHelper(rs >= rt, 16); 4075 } 4076 } 4077 } 4078 } else { // BLEZL 4079 BranchAndLinkHelper(rs <= 0); 4080 } 4081 break; 4082 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6) 4083 if (IsMipsArchVariant(kMips32r6)) { 4084 if (rt_reg != 0) { 4085 if (rs_reg == 0) { // BGTZC 4086 BranchCompactHelper(rt > 0, 16); 4087 } else { 4088 if (rs_reg == rt_reg) { // BLTZC 4089 BranchCompactHelper(rt < 0, 16); 4090 } else { // BLTC/BGTC 4091 BranchCompactHelper(rs < rt, 16); 4092 } 4093 } 4094 } 4095 } else { // BGTZL 4096 BranchAndLinkHelper(rs > 0); 4097 } 4098 break; 4099 case POP66: // BEQZC, JIC 4100 if (rs_reg != 0) { // BEQZC 4101 BranchCompactHelper(rs == 0, 21); 4102 } else { // JIC 4103 next_pc = rt + imm16; 4104 } 4105 break; 4106 case POP76: // BNEZC, JIALC 4107 if (rs_reg != 0) { // BNEZC 4108 BranchCompactHelper(rs != 0, 21); 4109 } else { // JIALC 4110 set_register(31, get_pc() + Instruction::kInstrSize); 4111 next_pc = rt + imm16; 4112 } 4113 break; 4114 case BC: 4115 BranchCompactHelper(true, 26); 4116 break; 4117 case BALC: 4118 BranchAndLinkCompactHelper(true, 26); 4119 break; 4120 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6) 4121 if (IsMipsArchVariant(kMips32r6)) { 4122 if (rs_reg >= rt_reg) { // BOVC 4123 if (HaveSameSign(rs, rt)) { 4124 if (rs > 0) { 4125 BranchCompactHelper(rs > Registers::kMaxValue - rt, 16); 4126 } else if (rs < 0) { 4127 BranchCompactHelper(rs < Registers::kMinValue - rt, 16); 4128 } 4129 } 4130 } else { 4131 if (rs_reg == 0) { // BEQZALC 4132 BranchAndLinkCompactHelper(rt == 0, 16); 4133 } else { // BEQC 4134 BranchCompactHelper(rt == rs, 16); 4135 } 4136 } 4137 } else { // ADDI 4138 if (HaveSameSign(rs, se_imm16)) { 4139 if (rs > 0) { 4140 if (rs <= Registers::kMaxValue - se_imm16) { 4141 SignalException(kIntegerOverflow); 4142 } 4143 } else if (rs < 0) { 4144 if (rs >= Registers::kMinValue - se_imm16) { 4145 SignalException(kIntegerUnderflow); 4146 } 4147 } 4148 } 4149 SetResult(rt_reg, rs + se_imm16); 4150 } 4151 break; 4152 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6) 4153 if (IsMipsArchVariant(kMips32r6)) { 4154 if (rs_reg >= rt_reg) { // BNVC 4155 if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) { 4156 BranchCompactHelper(true, 16); 4157 } else { 4158 if (rs > 0) { 4159 BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16); 4160 } else if (rs < 0) { 4161 BranchCompactHelper(rs >= Registers::kMinValue - rt, 16); 4162 } 4163 } 4164 } else { 4165 if (rs_reg == 0) { // BNEZALC 4166 BranchAndLinkCompactHelper(rt != 0, 16); 4167 } else { // BNEC 4168 BranchCompactHelper(rt != rs, 16); 4169 } 4170 } 4171 } 4172 break; 4173 // ------------- Arithmetic instructions. 4174 case ADDIU: 4175 SetResult(rt_reg, rs + se_imm16); 4176 break; 4177 case SLTI: 4178 SetResult(rt_reg, rs < se_imm16 ? 1 : 0); 4179 break; 4180 case SLTIU: 4181 SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0); 4182 break; 4183 case ANDI: 4184 SetResult(rt_reg, rs & oe_imm16); 4185 break; 4186 case ORI: 4187 SetResult(rt_reg, rs | oe_imm16); 4188 break; 4189 case XORI: 4190 SetResult(rt_reg, rs ^ oe_imm16); 4191 break; 4192 case LUI: 4193 if (rs_reg != 0) { 4194 // AUI 4195 DCHECK(IsMipsArchVariant(kMips32r6)); 4196 SetResult(rt_reg, rs + (se_imm16 << 16)); 4197 } else { 4198 // LUI 4199 SetResult(rt_reg, oe_imm16 << 16); 4200 } 4201 break; 4202 // ------------- Memory instructions. 4203 case LB: 4204 set_register(rt_reg, ReadB(rs + se_imm16)); 4205 break; 4206 case LH: 4207 set_register(rt_reg, ReadH(rs + se_imm16, instr)); 4208 break; 4209 case LWL: { 4210 // al_offset is offset of the effective address within an aligned word. 4211 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 4212 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 4213 uint32_t mask = (1 << byte_shift * 8) - 1; 4214 addr = rs + se_imm16 - al_offset; 4215 alu_out = ReadW(addr, instr); 4216 alu_out <<= byte_shift * 8; 4217 alu_out |= rt & mask; 4218 set_register(rt_reg, alu_out); 4219 break; 4220 } 4221 case LW: 4222 set_register(rt_reg, ReadW(rs + se_imm16, instr)); 4223 break; 4224 case LBU: 4225 set_register(rt_reg, ReadBU(rs + se_imm16)); 4226 break; 4227 case LHU: 4228 set_register(rt_reg, ReadHU(rs + se_imm16, instr)); 4229 break; 4230 case LWR: { 4231 // al_offset is offset of the effective address within an aligned word. 4232 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 4233 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 4234 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; 4235 addr = rs + se_imm16 - al_offset; 4236 alu_out = ReadW(addr, instr); 4237 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8; 4238 alu_out |= rt & mask; 4239 set_register(rt_reg, alu_out); 4240 break; 4241 } 4242 case SB: 4243 WriteB(rs + se_imm16, static_cast<int8_t>(rt)); 4244 break; 4245 case SH: 4246 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr); 4247 break; 4248 case SWL: { 4249 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 4250 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 4251 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; 4252 addr = rs + se_imm16 - al_offset; 4253 // Value to be written in memory. 4254 uint32_t mem_value = ReadW(addr, instr) & mask; 4255 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; 4256 WriteW(addr, mem_value, instr); 4257 break; 4258 } 4259 case SW: 4260 WriteW(rs + se_imm16, rt, instr); 4261 break; 4262 case SWR: { 4263 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 4264 uint32_t mask = (1 << al_offset * 8) - 1; 4265 addr = rs + se_imm16 - al_offset; 4266 uint32_t mem_value = ReadW(addr, instr); 4267 mem_value = (rt << al_offset * 8) | (mem_value & mask); 4268 WriteW(addr, mem_value, instr); 4269 break; 4270 } 4271 case LWC1: 4272 set_fpu_register_hi_word(ft_reg, 0); 4273 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr)); 4274 break; 4275 case LDC1: 4276 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr)); 4277 break; 4278 case SWC1: 4279 WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr); 4280 break; 4281 case SDC1: 4282 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); 4283 break; 4284 // ------------- PC-Relative instructions. 4285 case PCREL: { 4286 // rt field: checking 5-bits. 4287 int32_t imm21 = instr->Imm21Value(); 4288 int32_t current_pc = get_pc(); 4289 uint8_t rt = (imm21 >> kImm16Bits); 4290 switch (rt) { 4291 case ALUIPC: 4292 addr = current_pc + (se_imm16 << 16); 4293 alu_out = static_cast<int64_t>(~0x0FFFF) & addr; 4294 break; 4295 case AUIPC: 4296 alu_out = current_pc + (se_imm16 << 16); 4297 break; 4298 default: { 4299 int32_t imm19 = instr->Imm19Value(); 4300 // rt field: checking the most significant 2-bits. 4301 rt = (imm21 >> kImm19Bits); 4302 switch (rt) { 4303 case LWPC: { 4304 // Set sign. 4305 imm19 <<= (kOpcodeBits + kRsBits + 2); 4306 imm19 >>= (kOpcodeBits + kRsBits + 2); 4307 addr = current_pc + (imm19 << 2); 4308 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 4309 alu_out = *ptr; 4310 break; 4311 } 4312 case ADDIUPC: { 4313 int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0); 4314 alu_out = current_pc + (se_imm19 << 2); 4315 break; 4316 } 4317 default: 4318 UNREACHABLE(); 4319 break; 4320 } 4321 } 4322 } 4323 set_register(rs_reg, alu_out); 4324 break; 4325 } 4326 default: 4327 UNREACHABLE(); 4328 } 4329 4330 if (execute_branch_delay_instruction) { 4331 // Execute branch delay slot 4332 // We don't check for end_sim_pc. First it should not be met as the current 4333 // pc is valid. Secondly a jump should always execute its branch delay slot. 4334 Instruction* branch_delay_instr = 4335 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize); 4336 BranchDelayInstructionDecode(branch_delay_instr); 4337 } 4338 4339 // If needed update pc after the branch delay execution. 4340 if (next_pc != bad_ra) { 4341 set_pc(next_pc); 4342 } 4343 } 4344 4345 4346 // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). 4347 void Simulator::DecodeTypeJump(Instruction* instr) { 4348 // Get current pc. 4349 int32_t current_pc = get_pc(); 4350 // Get unchanged bits of pc. 4351 int32_t pc_high_bits = current_pc & 0xf0000000; 4352 // Next pc. 4353 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2); 4354 4355 // Execute branch delay slot. 4356 // We don't check for end_sim_pc. First it should not be met as the current pc 4357 // is valid. Secondly a jump should always execute its branch delay slot. 4358 Instruction* branch_delay_instr = 4359 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); 4360 BranchDelayInstructionDecode(branch_delay_instr); 4361 4362 // Update pc and ra if necessary. 4363 // Do this after the branch delay execution. 4364 if (instr->IsLinkingInstruction()) { 4365 set_register(31, current_pc + 2 * Instruction::kInstrSize); 4366 } 4367 set_pc(next_pc); 4368 pc_modified_ = true; 4369 } 4370 4371 4372 // Executes the current instruction. 4373 void Simulator::InstructionDecode(Instruction* instr) { 4374 if (v8::internal::FLAG_check_icache) { 4375 CheckICache(isolate_->simulator_i_cache(), instr); 4376 } 4377 pc_modified_ = false; 4378 v8::internal::EmbeddedVector<char, 256> buffer; 4379 if (::v8::internal::FLAG_trace_sim) { 4380 SNPrintF(trace_buf_, "%s", ""); 4381 disasm::NameConverter converter; 4382 disasm::Disassembler dasm(converter); 4383 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); 4384 } 4385 4386 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) { 4387 case Instruction::kRegisterType: 4388 DecodeTypeRegister(instr); 4389 break; 4390 case Instruction::kImmediateType: 4391 DecodeTypeImmediate(instr); 4392 break; 4393 case Instruction::kJumpType: 4394 DecodeTypeJump(instr); 4395 break; 4396 default: 4397 UNSUPPORTED(); 4398 } 4399 if (::v8::internal::FLAG_trace_sim) { 4400 PrintF(" 0x%08x %-44s %s\n", reinterpret_cast<intptr_t>(instr), 4401 buffer.start(), trace_buf_.start()); 4402 } 4403 if (!pc_modified_) { 4404 set_register(pc, reinterpret_cast<int32_t>(instr) + 4405 Instruction::kInstrSize); 4406 } 4407 } 4408 4409 4410 4411 void Simulator::Execute() { 4412 // Get the PC to simulate. Cannot use the accessor here as we need the 4413 // raw PC value and not the one used as input to arithmetic instructions. 4414 int program_counter = get_pc(); 4415 if (::v8::internal::FLAG_stop_sim_at == 0) { 4416 // Fast version of the dispatch loop without checking whether the simulator 4417 // should be stopping at a particular executed instruction. 4418 while (program_counter != end_sim_pc) { 4419 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); 4420 icount_++; 4421 InstructionDecode(instr); 4422 program_counter = get_pc(); 4423 } 4424 } else { 4425 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when 4426 // we reach the particular instuction count. 4427 while (program_counter != end_sim_pc) { 4428 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); 4429 icount_++; 4430 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) { 4431 MipsDebugger dbg(this); 4432 dbg.Debug(); 4433 } else { 4434 InstructionDecode(instr); 4435 } 4436 program_counter = get_pc(); 4437 } 4438 } 4439 } 4440 4441 4442 void Simulator::CallInternal(byte* entry) { 4443 // Adjust JS-based stack limit to C-based stack limit. 4444 isolate_->stack_guard()->AdjustStackLimitForSimulator(); 4445 4446 // Prepare to execute the code at entry. 4447 set_register(pc, reinterpret_cast<int32_t>(entry)); 4448 // Put down marker for end of simulation. The simulator will stop simulation 4449 // when the PC reaches this value. By saving the "end simulation" value into 4450 // the LR the simulation stops when returning to this call point. 4451 set_register(ra, end_sim_pc); 4452 4453 // Remember the values of callee-saved registers. 4454 // The code below assumes that r9 is not used as sb (static base) in 4455 // simulator code and therefore is regarded as a callee-saved register. 4456 int32_t s0_val = get_register(s0); 4457 int32_t s1_val = get_register(s1); 4458 int32_t s2_val = get_register(s2); 4459 int32_t s3_val = get_register(s3); 4460 int32_t s4_val = get_register(s4); 4461 int32_t s5_val = get_register(s5); 4462 int32_t s6_val = get_register(s6); 4463 int32_t s7_val = get_register(s7); 4464 int32_t gp_val = get_register(gp); 4465 int32_t sp_val = get_register(sp); 4466 int32_t fp_val = get_register(fp); 4467 4468 // Set up the callee-saved registers with a known value. To be able to check 4469 // that they are preserved properly across JS execution. 4470 int32_t callee_saved_value = icount_; 4471 set_register(s0, callee_saved_value); 4472 set_register(s1, callee_saved_value); 4473 set_register(s2, callee_saved_value); 4474 set_register(s3, callee_saved_value); 4475 set_register(s4, callee_saved_value); 4476 set_register(s5, callee_saved_value); 4477 set_register(s6, callee_saved_value); 4478 set_register(s7, callee_saved_value); 4479 set_register(gp, callee_saved_value); 4480 set_register(fp, callee_saved_value); 4481 4482 // Start the simulation. 4483 Execute(); 4484 4485 // Check that the callee-saved registers have been preserved. 4486 CHECK_EQ(callee_saved_value, get_register(s0)); 4487 CHECK_EQ(callee_saved_value, get_register(s1)); 4488 CHECK_EQ(callee_saved_value, get_register(s2)); 4489 CHECK_EQ(callee_saved_value, get_register(s3)); 4490 CHECK_EQ(callee_saved_value, get_register(s4)); 4491 CHECK_EQ(callee_saved_value, get_register(s5)); 4492 CHECK_EQ(callee_saved_value, get_register(s6)); 4493 CHECK_EQ(callee_saved_value, get_register(s7)); 4494 CHECK_EQ(callee_saved_value, get_register(gp)); 4495 CHECK_EQ(callee_saved_value, get_register(fp)); 4496 4497 // Restore callee-saved registers with the original value. 4498 set_register(s0, s0_val); 4499 set_register(s1, s1_val); 4500 set_register(s2, s2_val); 4501 set_register(s3, s3_val); 4502 set_register(s4, s4_val); 4503 set_register(s5, s5_val); 4504 set_register(s6, s6_val); 4505 set_register(s7, s7_val); 4506 set_register(gp, gp_val); 4507 set_register(sp, sp_val); 4508 set_register(fp, fp_val); 4509 } 4510 4511 4512 int32_t Simulator::Call(byte* entry, int argument_count, ...) { 4513 va_list parameters; 4514 va_start(parameters, argument_count); 4515 // Set up arguments. 4516 4517 // First four arguments passed in registers. 4518 DCHECK(argument_count >= 4); 4519 set_register(a0, va_arg(parameters, int32_t)); 4520 set_register(a1, va_arg(parameters, int32_t)); 4521 set_register(a2, va_arg(parameters, int32_t)); 4522 set_register(a3, va_arg(parameters, int32_t)); 4523 4524 // Remaining arguments passed on stack. 4525 int original_stack = get_register(sp); 4526 // Compute position of stack on entry to generated code. 4527 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) 4528 - kCArgsSlotsSize); 4529 if (base::OS::ActivationFrameAlignment() != 0) { 4530 entry_stack &= -base::OS::ActivationFrameAlignment(); 4531 } 4532 // Store remaining arguments on stack, from low to high memory. 4533 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); 4534 for (int i = 4; i < argument_count; i++) { 4535 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t); 4536 } 4537 va_end(parameters); 4538 set_register(sp, entry_stack); 4539 4540 CallInternal(entry); 4541 4542 // Pop stack passed arguments. 4543 CHECK_EQ(entry_stack, get_register(sp)); 4544 set_register(sp, original_stack); 4545 4546 int32_t result = get_register(v0); 4547 return result; 4548 } 4549 4550 4551 double Simulator::CallFP(byte* entry, double d0, double d1) { 4552 if (!IsMipsSoftFloatABI) { 4553 set_fpu_register_double(f12, d0); 4554 set_fpu_register_double(f14, d1); 4555 } else { 4556 int buffer[2]; 4557 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0)); 4558 memcpy(buffer, &d0, sizeof(d0)); 4559 set_dw_register(a0, buffer); 4560 memcpy(buffer, &d1, sizeof(d1)); 4561 set_dw_register(a2, buffer); 4562 } 4563 CallInternal(entry); 4564 if (!IsMipsSoftFloatABI) { 4565 return get_fpu_register_double(f0); 4566 } else { 4567 return get_double_from_register_pair(v0); 4568 } 4569 } 4570 4571 4572 uintptr_t Simulator::PushAddress(uintptr_t address) { 4573 int new_sp = get_register(sp) - sizeof(uintptr_t); 4574 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); 4575 *stack_slot = address; 4576 set_register(sp, new_sp); 4577 return new_sp; 4578 } 4579 4580 4581 uintptr_t Simulator::PopAddress() { 4582 int current_sp = get_register(sp); 4583 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); 4584 uintptr_t address = *stack_slot; 4585 set_register(sp, current_sp + sizeof(uintptr_t)); 4586 return address; 4587 } 4588 4589 4590 #undef UNSUPPORTED 4591 4592 } // namespace internal 4593 } // namespace v8 4594 4595 #endif // USE_SIMULATOR 4596 4597 #endif // V8_TARGET_ARCH_MIPS 4598