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