simulator-mips.cc revision 257744e915dfc84d6d07a6b2accf8402d9ffc708
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29#include <math.h> 30#include <limits.h> 31#include <cstdarg> 32#include "v8.h" 33 34#if defined(V8_TARGET_ARCH_MIPS) 35 36#include "disasm.h" 37#include "assembler.h" 38#include "globals.h" // Need the BitCast. 39#include "mips/constants-mips.h" 40#include "mips/simulator-mips.h" 41 42 43// Only build the simulator if not compiling for real MIPS hardware. 44#if defined(USE_SIMULATOR) 45 46namespace v8 { 47namespace internal { 48 49// Utils functions. 50bool HaveSameSign(int32_t a, int32_t b) { 51 return ((a ^ b) >= 0); 52} 53 54 55uint32_t get_fcsr_condition_bit(uint32_t cc) { 56 if (cc == 0) { 57 return 23; 58 } else { 59 return 24 + cc; 60 } 61} 62 63 64// This macro provides a platform independent use of sscanf. The reason for 65// SScanF not being implemented in a platform independent was through 66// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time 67// Library does not provide vsscanf. 68#define SScanF sscanf // NOLINT 69 70// The MipsDebugger class is used by the simulator while debugging simulated 71// code. 72class MipsDebugger { 73 public: 74 explicit MipsDebugger(Simulator* sim); 75 ~MipsDebugger(); 76 77 void Stop(Instruction* instr); 78 void Debug(); 79 // Print all registers with a nice formatting. 80 void PrintAllRegs(); 81 void PrintAllRegsIncludingFPU(); 82 83 private: 84 // We set the breakpoint code to 0xfffff to easily recognize it. 85 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6; 86 static const Instr kNopInstr = 0x0; 87 88 Simulator* sim_; 89 90 int32_t GetRegisterValue(int regnum); 91 int32_t GetFPURegisterValueInt(int regnum); 92 int64_t GetFPURegisterValueLong(int regnum); 93 float GetFPURegisterValueFloat(int regnum); 94 double GetFPURegisterValueDouble(int regnum); 95 bool GetValue(const char* desc, int32_t* value); 96 97 // Set or delete a breakpoint. Returns true if successful. 98 bool SetBreakpoint(Instruction* breakpc); 99 bool DeleteBreakpoint(Instruction* breakpc); 100 101 // Undo and redo all breakpoints. This is needed to bracket disassembly and 102 // execution to skip past breakpoints when run from the debugger. 103 void UndoBreakpoints(); 104 void RedoBreakpoints(); 105}; 106 107MipsDebugger::MipsDebugger(Simulator* sim) { 108 sim_ = sim; 109} 110 111 112MipsDebugger::~MipsDebugger() { 113} 114 115 116#ifdef GENERATED_CODE_COVERAGE 117static FILE* coverage_log = NULL; 118 119 120static void InitializeCoverage() { 121 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); 122 if (file_name != NULL) { 123 coverage_log = fopen(file_name, "aw+"); 124 } 125} 126 127 128void MipsDebugger::Stop(Instruction* instr) { 129 UNIMPLEMENTED_MIPS(); 130 char* str = reinterpret_cast<char*>(instr->InstructionBits()); 131 if (strlen(str) > 0) { 132 if (coverage_log != NULL) { 133 fprintf(coverage_log, "%s\n", str); 134 fflush(coverage_log); 135 } 136 instr->SetInstructionBits(0x0); // Overwrite with nop. 137 } 138 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); 139} 140 141 142#else // GENERATED_CODE_COVERAGE 143 144#define UNSUPPORTED() printf("Unsupported instruction.\n"); 145 146static void InitializeCoverage() {} 147 148 149void MipsDebugger::Stop(Instruction* instr) { 150 const char* str = reinterpret_cast<char*>(instr->InstructionBits()); 151 PrintF("Simulator hit %s\n", str); 152 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); 153 Debug(); 154} 155#endif // GENERATED_CODE_COVERAGE 156 157 158int32_t MipsDebugger::GetRegisterValue(int regnum) { 159 if (regnum == kNumSimuRegisters) { 160 return sim_->get_pc(); 161 } else { 162 return sim_->get_register(regnum); 163 } 164} 165 166 167int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) { 168 if (regnum == kNumFPURegisters) { 169 return sim_->get_pc(); 170 } else { 171 return sim_->get_fpu_register(regnum); 172 } 173} 174 175 176int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) { 177 if (regnum == kNumFPURegisters) { 178 return sim_->get_pc(); 179 } else { 180 return sim_->get_fpu_register_long(regnum); 181 } 182} 183 184 185float MipsDebugger::GetFPURegisterValueFloat(int regnum) { 186 if (regnum == kNumFPURegisters) { 187 return sim_->get_pc(); 188 } else { 189 return sim_->get_fpu_register_float(regnum); 190 } 191} 192 193 194double MipsDebugger::GetFPURegisterValueDouble(int regnum) { 195 if (regnum == kNumFPURegisters) { 196 return sim_->get_pc(); 197 } else { 198 return sim_->get_fpu_register_double(regnum); 199 } 200} 201 202 203bool MipsDebugger::GetValue(const char* desc, int32_t* value) { 204 int regnum = Registers::Number(desc); 205 int fpuregnum = FPURegisters::Number(desc); 206 207 if (regnum != kInvalidRegister) { 208 *value = GetRegisterValue(regnum); 209 return true; 210 } else if (fpuregnum != kInvalidFPURegister) { 211 *value = GetFPURegisterValueInt(fpuregnum); 212 return true; 213 } else if (strncmp(desc, "0x", 2) == 0) { 214 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1; 215 } else { 216 return SScanF(desc, "%i", value) == 1; 217 } 218 return false; 219} 220 221 222bool MipsDebugger::SetBreakpoint(Instruction* breakpc) { 223 // Check if a breakpoint can be set. If not return without any side-effects. 224 if (sim_->break_pc_ != NULL) { 225 return false; 226 } 227 228 // Set the breakpoint. 229 sim_->break_pc_ = breakpc; 230 sim_->break_instr_ = breakpc->InstructionBits(); 231 // Not setting the breakpoint instruction in the code itself. It will be set 232 // when the debugger shell continues. 233 return true; 234} 235 236 237bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) { 238 if (sim_->break_pc_ != NULL) { 239 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); 240 } 241 242 sim_->break_pc_ = NULL; 243 sim_->break_instr_ = 0; 244 return true; 245} 246 247 248void MipsDebugger::UndoBreakpoints() { 249 if (sim_->break_pc_ != NULL) { 250 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); 251 } 252} 253 254 255void MipsDebugger::RedoBreakpoints() { 256 if (sim_->break_pc_ != NULL) { 257 sim_->break_pc_->SetInstructionBits(kBreakpointInstr); 258 } 259} 260 261 262void MipsDebugger::PrintAllRegs() { 263#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n) 264 265 PrintF("\n"); 266 // at, v0, a0. 267 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 268 REG_INFO(1), REG_INFO(2), REG_INFO(4)); 269 // v1, a1. 270 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 271 "", REG_INFO(3), REG_INFO(5)); 272 // a2. 273 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6)); 274 // a3. 275 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7)); 276 PrintF("\n"); 277 // t0-t7, s0-s7 278 for (int i = 0; i < 8; i++) { 279 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 280 REG_INFO(8+i), REG_INFO(16+i)); 281 } 282 PrintF("\n"); 283 // t8, k0, LO. 284 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 285 REG_INFO(24), REG_INFO(26), REG_INFO(32)); 286 // t9, k1, HI. 287 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 288 REG_INFO(25), REG_INFO(27), REG_INFO(33)); 289 // sp, fp, gp. 290 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 291 REG_INFO(29), REG_INFO(30), REG_INFO(28)); 292 // pc. 293 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", 294 REG_INFO(31), REG_INFO(34)); 295 296#undef REG_INFO 297#undef FPU_REG_INFO 298} 299 300 301void MipsDebugger::PrintAllRegsIncludingFPU() { 302#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \ 303 GetFPURegisterValueInt(n+1), \ 304 GetFPURegisterValueInt(n), \ 305 GetFPURegisterValueDouble(n) 306 307 PrintAllRegs(); 308 309 PrintF("\n\n"); 310 // f0, f1, f2, ... f31. 311 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) ); 312 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) ); 313 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) ); 314 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) ); 315 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) ); 316 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10)); 317 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12)); 318 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14)); 319 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16)); 320 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18)); 321 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20)); 322 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22)); 323 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24)); 324 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26)); 325 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28)); 326 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30)); 327 328#undef REG_INFO 329#undef FPU_REG_INFO 330} 331 332 333void MipsDebugger::Debug() { 334 intptr_t last_pc = -1; 335 bool done = false; 336 337#define COMMAND_SIZE 63 338#define ARG_SIZE 255 339 340#define STR(a) #a 341#define XSTR(a) STR(a) 342 343 char cmd[COMMAND_SIZE + 1]; 344 char arg1[ARG_SIZE + 1]; 345 char arg2[ARG_SIZE + 1]; 346 char* argv[3] = { cmd, arg1, arg2 }; 347 348 // Make sure to have a proper terminating character if reaching the limit. 349 cmd[COMMAND_SIZE] = 0; 350 arg1[ARG_SIZE] = 0; 351 arg2[ARG_SIZE] = 0; 352 353 // Undo all set breakpoints while running in the debugger shell. This will 354 // make them invisible to all commands. 355 UndoBreakpoints(); 356 357 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) { 358 if (last_pc != sim_->get_pc()) { 359 disasm::NameConverter converter; 360 disasm::Disassembler dasm(converter); 361 // Use a reasonably large buffer. 362 v8::internal::EmbeddedVector<char, 256> buffer; 363 dasm.InstructionDecode(buffer, 364 reinterpret_cast<byte*>(sim_->get_pc())); 365 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start()); 366 last_pc = sim_->get_pc(); 367 } 368 char* line = ReadLine("sim> "); 369 if (line == NULL) { 370 break; 371 } else { 372 // Use sscanf to parse the individual parts of the command line. At the 373 // moment no command expects more than two parameters. 374 int argc = SScanF(line, 375 "%" XSTR(COMMAND_SIZE) "s " 376 "%" XSTR(ARG_SIZE) "s " 377 "%" XSTR(ARG_SIZE) "s", 378 cmd, arg1, arg2); 379 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { 380 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc()); 381 if (!(instr->IsTrap()) || 382 instr->InstructionBits() == rtCallRedirInstr) { 383 sim_->InstructionDecode( 384 reinterpret_cast<Instruction*>(sim_->get_pc())); 385 } else { 386 // Allow si to jump over generated breakpoints. 387 PrintF("/!\\ Jumping over generated breakpoint.\n"); 388 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); 389 } 390 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { 391 // Execute the one instruction we broke at with breakpoints disabled. 392 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc())); 393 // Leave the debugger shell. 394 done = true; 395 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { 396 if (argc == 2) { 397 int32_t value; 398 float fvalue; 399 if (strcmp(arg1, "all") == 0) { 400 PrintAllRegs(); 401 } else if (strcmp(arg1, "allf") == 0) { 402 PrintAllRegsIncludingFPU(); 403 } else { 404 int regnum = Registers::Number(arg1); 405 int fpuregnum = FPURegisters::Number(arg1); 406 407 if (regnum != kInvalidRegister) { 408 value = GetRegisterValue(regnum); 409 PrintF("%s: 0x%08x %d \n", arg1, value, value); 410 } else if (fpuregnum != kInvalidFPURegister) { 411 if (fpuregnum % 2 == 1) { 412 value = GetFPURegisterValueInt(fpuregnum); 413 fvalue = GetFPURegisterValueFloat(fpuregnum); 414 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); 415 } else { 416 double dfvalue; 417 int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum); 418 int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1); 419 dfvalue = GetFPURegisterValueDouble(fpuregnum); 420 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", 421 FPURegisters::Name(fpuregnum+1), 422 FPURegisters::Name(fpuregnum), 423 lvalue1, 424 lvalue2, 425 dfvalue); 426 } 427 } else { 428 PrintF("%s unrecognized\n", arg1); 429 } 430 } 431 } else { 432 if (argc == 3) { 433 if (strcmp(arg2, "single") == 0) { 434 int32_t value; 435 float fvalue; 436 int fpuregnum = FPURegisters::Number(arg1); 437 438 if (fpuregnum != kInvalidFPURegister) { 439 value = GetFPURegisterValueInt(fpuregnum); 440 fvalue = GetFPURegisterValueFloat(fpuregnum); 441 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); 442 } else { 443 PrintF("%s unrecognized\n", arg1); 444 } 445 } else { 446 PrintF("print <fpu register> single\n"); 447 } 448 } else { 449 PrintF("print <register> or print <fpu register> single\n"); 450 } 451 } 452 } else if ((strcmp(cmd, "po") == 0) 453 || (strcmp(cmd, "printobject") == 0)) { 454 if (argc == 2) { 455 int32_t value; 456 if (GetValue(arg1, &value)) { 457 Object* obj = reinterpret_cast<Object*>(value); 458 PrintF("%s: \n", arg1); 459#ifdef DEBUG 460 obj->PrintLn(); 461#else 462 obj->ShortPrint(); 463 PrintF("\n"); 464#endif 465 } else { 466 PrintF("%s unrecognized\n", arg1); 467 } 468 } else { 469 PrintF("printobject <value>\n"); 470 } 471 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { 472 int32_t* cur = NULL; 473 int32_t* end = NULL; 474 int next_arg = 1; 475 476 if (strcmp(cmd, "stack") == 0) { 477 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp)); 478 } else { // Command "mem". 479 int32_t value; 480 if (!GetValue(arg1, &value)) { 481 PrintF("%s unrecognized\n", arg1); 482 continue; 483 } 484 cur = reinterpret_cast<int32_t*>(value); 485 next_arg++; 486 } 487 488 int32_t words; 489 if (argc == next_arg) { 490 words = 10; 491 } else if (argc == next_arg + 1) { 492 if (!GetValue(argv[next_arg], &words)) { 493 words = 10; 494 } 495 } 496 end = cur + words; 497 498 while (cur < end) { 499 PrintF(" 0x%08x: 0x%08x %10d", 500 reinterpret_cast<intptr_t>(cur), *cur, *cur); 501 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); 502 int value = *cur; 503 Heap* current_heap = v8::internal::Isolate::Current()->heap(); 504 if (current_heap->Contains(obj) || ((value & 1) == 0)) { 505 PrintF(" ("); 506 if ((value & 1) == 0) { 507 PrintF("smi %d", value / 2); 508 } else { 509 obj->ShortPrint(); 510 } 511 PrintF(")"); 512 } 513 PrintF("\n"); 514 cur++; 515 } 516 517 } else if ((strcmp(cmd, "disasm") == 0) || 518 (strcmp(cmd, "dpc") == 0) || 519 (strcmp(cmd, "di") == 0)) { 520 disasm::NameConverter converter; 521 disasm::Disassembler dasm(converter); 522 // Use a reasonably large buffer. 523 v8::internal::EmbeddedVector<char, 256> buffer; 524 525 byte* cur = NULL; 526 byte* end = NULL; 527 528 if (argc == 1) { 529 cur = reinterpret_cast<byte*>(sim_->get_pc()); 530 end = cur + (10 * Instruction::kInstrSize); 531 } else if (argc == 2) { 532 int regnum = Registers::Number(arg1); 533 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { 534 // The argument is an address or a register name. 535 int32_t value; 536 if (GetValue(arg1, &value)) { 537 cur = reinterpret_cast<byte*>(value); 538 // Disassemble 10 instructions at <arg1>. 539 end = cur + (10 * Instruction::kInstrSize); 540 } 541 } else { 542 // The argument is the number of instructions. 543 int32_t value; 544 if (GetValue(arg1, &value)) { 545 cur = reinterpret_cast<byte*>(sim_->get_pc()); 546 // Disassemble <arg1> instructions. 547 end = cur + (value * Instruction::kInstrSize); 548 } 549 } 550 } else { 551 int32_t value1; 552 int32_t value2; 553 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { 554 cur = reinterpret_cast<byte*>(value1); 555 end = cur + (value2 * Instruction::kInstrSize); 556 } 557 } 558 559 while (cur < end) { 560 dasm.InstructionDecode(buffer, cur); 561 PrintF(" 0x%08x %s\n", 562 reinterpret_cast<intptr_t>(cur), buffer.start()); 563 cur += Instruction::kInstrSize; 564 } 565 } else if (strcmp(cmd, "gdb") == 0) { 566 PrintF("relinquishing control to gdb\n"); 567 v8::internal::OS::DebugBreak(); 568 PrintF("regaining control from gdb\n"); 569 } else if (strcmp(cmd, "break") == 0) { 570 if (argc == 2) { 571 int32_t value; 572 if (GetValue(arg1, &value)) { 573 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) { 574 PrintF("setting breakpoint failed\n"); 575 } 576 } else { 577 PrintF("%s unrecognized\n", arg1); 578 } 579 } else { 580 PrintF("break <address>\n"); 581 } 582 } else if (strcmp(cmd, "del") == 0) { 583 if (!DeleteBreakpoint(NULL)) { 584 PrintF("deleting breakpoint failed\n"); 585 } 586 } else if (strcmp(cmd, "flags") == 0) { 587 PrintF("No flags on MIPS !\n"); 588 } else if (strcmp(cmd, "unstop") == 0) { 589 PrintF("Unstop command not implemented on MIPS."); 590 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) { 591 // Print registers and disassemble. 592 PrintAllRegs(); 593 PrintF("\n"); 594 595 disasm::NameConverter converter; 596 disasm::Disassembler dasm(converter); 597 // Use a reasonably large buffer. 598 v8::internal::EmbeddedVector<char, 256> buffer; 599 600 byte* cur = NULL; 601 byte* end = NULL; 602 603 if (argc == 1) { 604 cur = reinterpret_cast<byte*>(sim_->get_pc()); 605 end = cur + (10 * Instruction::kInstrSize); 606 } else if (argc == 2) { 607 int32_t value; 608 if (GetValue(arg1, &value)) { 609 cur = reinterpret_cast<byte*>(value); 610 // no length parameter passed, assume 10 instructions 611 end = cur + (10 * Instruction::kInstrSize); 612 } 613 } else { 614 int32_t value1; 615 int32_t value2; 616 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { 617 cur = reinterpret_cast<byte*>(value1); 618 end = cur + (value2 * Instruction::kInstrSize); 619 } 620 } 621 622 while (cur < end) { 623 dasm.InstructionDecode(buffer, cur); 624 PrintF(" 0x%08x %s\n", 625 reinterpret_cast<intptr_t>(cur), buffer.start()); 626 cur += Instruction::kInstrSize; 627 } 628 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { 629 PrintF("cont\n"); 630 PrintF(" continue execution (alias 'c')\n"); 631 PrintF("stepi\n"); 632 PrintF(" step one instruction (alias 'si')\n"); 633 PrintF("print <register>\n"); 634 PrintF(" print register content (alias 'p')\n"); 635 PrintF(" use register name 'all' to print all registers\n"); 636 PrintF("printobject <register>\n"); 637 PrintF(" print an object from a register (alias 'po')\n"); 638 PrintF("stack [<words>]\n"); 639 PrintF(" dump stack content, default dump 10 words)\n"); 640 PrintF("mem <address> [<words>]\n"); 641 PrintF(" dump memory content, default dump 10 words)\n"); 642 PrintF("flags\n"); 643 PrintF(" print flags\n"); 644 PrintF("disasm [<instructions>]\n"); 645 PrintF("disasm [<address/register>]\n"); 646 PrintF("disasm [[<address/register>] <instructions>]\n"); 647 PrintF(" disassemble code, default is 10 instructions\n"); 648 PrintF(" from pc (alias 'di')\n"); 649 PrintF("gdb\n"); 650 PrintF(" enter gdb\n"); 651 PrintF("break <address>\n"); 652 PrintF(" set a break point on the address\n"); 653 PrintF("del\n"); 654 PrintF(" delete the breakpoint\n"); 655 PrintF("unstop\n"); 656 PrintF(" ignore the stop instruction at the current location"); 657 PrintF(" from now on\n"); 658 } else { 659 PrintF("Unknown command: %s\n", cmd); 660 } 661 } 662 DeleteArray(line); 663 } 664 665 // Add all the breakpoints back to stop execution and enter the debugger 666 // shell when hit. 667 RedoBreakpoints(); 668 669#undef COMMAND_SIZE 670#undef ARG_SIZE 671 672#undef STR 673#undef XSTR 674} 675 676 677static bool ICacheMatch(void* one, void* two) { 678 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0); 679 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0); 680 return one == two; 681} 682 683 684static uint32_t ICacheHash(void* key) { 685 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2; 686} 687 688 689static bool AllOnOnePage(uintptr_t start, int size) { 690 intptr_t start_page = (start & ~CachePage::kPageMask); 691 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); 692 return start_page == end_page; 693} 694 695 696void Simulator::FlushICache(v8::internal::HashMap* i_cache, 697 void* start_addr, 698 size_t size) { 699 intptr_t start = reinterpret_cast<intptr_t>(start_addr); 700 int intra_line = (start & CachePage::kLineMask); 701 start -= intra_line; 702 size += intra_line; 703 size = ((size - 1) | CachePage::kLineMask) + 1; 704 int offset = (start & CachePage::kPageMask); 705 while (!AllOnOnePage(start, size - 1)) { 706 int bytes_to_flush = CachePage::kPageSize - offset; 707 FlushOnePage(i_cache, start, bytes_to_flush); 708 start += bytes_to_flush; 709 size -= bytes_to_flush; 710 ASSERT_EQ(0, start & CachePage::kPageMask); 711 offset = 0; 712 } 713 if (size != 0) { 714 FlushOnePage(i_cache, start, size); 715 } 716} 717 718 719CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) { 720 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page, 721 ICacheHash(page), 722 true); 723 if (entry->value == NULL) { 724 CachePage* new_page = new CachePage(); 725 entry->value = new_page; 726 } 727 return reinterpret_cast<CachePage*>(entry->value); 728} 729 730 731// Flush from start up to and not including start + size. 732void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, 733 intptr_t start, 734 int size) { 735 ASSERT(size <= CachePage::kPageSize); 736 ASSERT(AllOnOnePage(start, size - 1)); 737 ASSERT((start & CachePage::kLineMask) == 0); 738 ASSERT((size & CachePage::kLineMask) == 0); 739 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); 740 int offset = (start & CachePage::kPageMask); 741 CachePage* cache_page = GetCachePage(i_cache, page); 742 char* valid_bytemap = cache_page->ValidityByte(offset); 743 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); 744} 745 746 747void Simulator::CheckICache(v8::internal::HashMap* i_cache, 748 Instruction* instr) { 749 intptr_t address = reinterpret_cast<intptr_t>(instr); 750 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); 751 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); 752 int offset = (address & CachePage::kPageMask); 753 CachePage* cache_page = GetCachePage(i_cache, page); 754 char* cache_valid_byte = cache_page->ValidityByte(offset); 755 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); 756 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); 757 if (cache_hit) { 758 // Check that the data in memory matches the contents of the I-cache. 759 CHECK(memcmp(reinterpret_cast<void*>(instr), 760 cache_page->CachedData(offset), 761 Instruction::kInstrSize) == 0); 762 } else { 763 // Cache miss. Load memory into the cache. 764 memcpy(cached_line, line, CachePage::kLineLength); 765 *cache_valid_byte = CachePage::LINE_VALID; 766 } 767} 768 769 770void Simulator::Initialize(Isolate* isolate) { 771 if (isolate->simulator_initialized()) return; 772 isolate->set_simulator_initialized(true); 773 ::v8::internal::ExternalReference::set_redirector(isolate, 774 &RedirectExternalReference); 775} 776 777 778Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { 779 i_cache_ = isolate_->simulator_i_cache(); 780 if (i_cache_ == NULL) { 781 i_cache_ = new v8::internal::HashMap(&ICacheMatch); 782 isolate_->set_simulator_i_cache(i_cache_); 783 } 784 Initialize(isolate); 785 // Setup simulator support first. Some of this information is needed to 786 // setup the architecture state. 787 stack_ = reinterpret_cast<char*>(malloc(stack_size_)); 788 pc_modified_ = false; 789 icount_ = 0; 790 break_count_ = 0; 791 break_pc_ = NULL; 792 break_instr_ = 0; 793 794 // Setup architecture state. 795 // All registers are initialized to zero to start with. 796 for (int i = 0; i < kNumSimuRegisters; i++) { 797 registers_[i] = 0; 798 } 799 for (int i = 0; i < kNumFPURegisters; i++) { 800 FPUregisters_[i] = 0; 801 } 802 FCSR_ = 0; 803 804 // The sp is initialized to point to the bottom (high address) of the 805 // allocated stack area. To be safe in potential stack underflows we leave 806 // some buffer below. 807 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64; 808 // The ra and pc are initialized to a known bad value that will cause an 809 // access violation if the simulator ever tries to execute it. 810 registers_[pc] = bad_ra; 811 registers_[ra] = bad_ra; 812 InitializeCoverage(); 813 for (int i = 0; i < kNumExceptions; i++) { 814 exceptions[i] = 0; 815 } 816} 817 818 819// When the generated code calls an external reference we need to catch that in 820// the simulator. The external reference will be a function compiled for the 821// host architecture. We need to call that function instead of trying to 822// execute it with the simulator. We do that by redirecting the external 823// reference to a swi (software-interrupt) instruction that is handled by 824// the simulator. We write the original destination of the jump just at a known 825// offset from the swi instruction so the simulator knows what to call. 826class Redirection { 827 public: 828 Redirection(void* external_function, ExternalReference::Type type) 829 : external_function_(external_function), 830 swi_instruction_(rtCallRedirInstr), 831 type_(type), 832 next_(NULL) { 833 Isolate* isolate = Isolate::Current(); 834 next_ = isolate->simulator_redirection(); 835 Simulator::current(isolate)-> 836 FlushICache(isolate->simulator_i_cache(), 837 reinterpret_cast<void*>(&swi_instruction_), 838 Instruction::kInstrSize); 839 isolate->set_simulator_redirection(this); 840 } 841 842 void* address_of_swi_instruction() { 843 return reinterpret_cast<void*>(&swi_instruction_); 844 } 845 846 void* external_function() { return external_function_; } 847 ExternalReference::Type type() { return type_; } 848 849 static Redirection* Get(void* external_function, 850 ExternalReference::Type type) { 851 Isolate* isolate = Isolate::Current(); 852 Redirection* current = isolate->simulator_redirection(); 853 for (; current != NULL; current = current->next_) { 854 if (current->external_function_ == external_function) return current; 855 } 856 return new Redirection(external_function, type); 857 } 858 859 static Redirection* FromSwiInstruction(Instruction* swi_instruction) { 860 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); 861 char* addr_of_redirection = 862 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); 863 return reinterpret_cast<Redirection*>(addr_of_redirection); 864 } 865 866 private: 867 void* external_function_; 868 uint32_t swi_instruction_; 869 ExternalReference::Type type_; 870 Redirection* next_; 871}; 872 873 874void* Simulator::RedirectExternalReference(void* external_function, 875 ExternalReference::Type type) { 876 Redirection* redirection = Redirection::Get(external_function, type); 877 return redirection->address_of_swi_instruction(); 878} 879 880 881// Get the active Simulator for the current thread. 882Simulator* Simulator::current(Isolate* isolate) { 883 v8::internal::Isolate::PerIsolateThreadData* isolate_data = 884 isolate->FindOrAllocatePerThreadDataForThisThread(); 885 ASSERT(isolate_data != NULL); 886 ASSERT(isolate_data != NULL); 887 888 Simulator* sim = isolate_data->simulator(); 889 if (sim == NULL) { 890 // TODO(146): delete the simulator object when a thread/isolate goes away. 891 sim = new Simulator(isolate); 892 isolate_data->set_simulator(sim); 893 } 894 return sim; 895} 896 897 898// Sets the register in the architecture state. It will also deal with updating 899// Simulator internal state for special registers such as PC. 900void Simulator::set_register(int reg, int32_t value) { 901 ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); 902 if (reg == pc) { 903 pc_modified_ = true; 904 } 905 906 // Zero register always holds 0. 907 registers_[reg] = (reg == 0) ? 0 : value; 908} 909 910 911void Simulator::set_fpu_register(int fpureg, int32_t value) { 912 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 913 FPUregisters_[fpureg] = value; 914} 915 916 917void Simulator::set_fpu_register_float(int fpureg, float value) { 918 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 919 *BitCast<float*>(&FPUregisters_[fpureg]) = value; 920} 921 922 923void Simulator::set_fpu_register_double(int fpureg, double value) { 924 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); 925 *BitCast<double*>(&FPUregisters_[fpureg]) = value; 926} 927 928 929// Get the register from the architecture state. This function does handle 930// the special case of accessing the PC register. 931int32_t Simulator::get_register(int reg) const { 932 ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); 933 if (reg == 0) 934 return 0; 935 else 936 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); 937} 938 939 940int32_t Simulator::get_fpu_register(int fpureg) const { 941 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 942 return FPUregisters_[fpureg]; 943} 944 945 946int64_t Simulator::get_fpu_register_long(int fpureg) const { 947 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); 948 return *BitCast<int64_t*>( 949 const_cast<int32_t*>(&FPUregisters_[fpureg])); 950} 951 952 953float Simulator::get_fpu_register_float(int fpureg) const { 954 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); 955 return *BitCast<float*>( 956 const_cast<int32_t*>(&FPUregisters_[fpureg])); 957} 958 959 960double Simulator::get_fpu_register_double(int fpureg) const { 961 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); 962 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); 963} 964 965 966// For use in calls that take two double values, constructed either 967// from a0-a3 or f12 and f14. 968void Simulator::GetFpArgs(double* x, double* y) { 969 if (!IsMipsSoftFloatABI) { 970 *x = get_fpu_register_double(12); 971 *y = get_fpu_register_double(14); 972 } else { 973 // We use a char buffer to get around the strict-aliasing rules which 974 // otherwise allow the compiler to optimize away the copy. 975 char buffer[sizeof(*x)]; 976 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 977 978 // Registers a0 and a1 -> x. 979 reg_buffer[0] = get_register(a0); 980 reg_buffer[1] = get_register(a1); 981 memcpy(x, buffer, sizeof(buffer)); 982 983 // Registers a2 and a3 -> y. 984 reg_buffer[0] = get_register(a2); 985 reg_buffer[1] = get_register(a3); 986 memcpy(y, buffer, sizeof(buffer)); 987 } 988} 989 990 991// For use in calls that take one double value, constructed either 992// from a0 and a1 or f12. 993void Simulator::GetFpArgs(double* x) { 994 if (!IsMipsSoftFloatABI) { 995 *x = get_fpu_register_double(12); 996 } else { 997 // We use a char buffer to get around the strict-aliasing rules which 998 // otherwise allow the compiler to optimize away the copy. 999 char buffer[sizeof(*x)]; 1000 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 1001 // Registers a0 and a1 -> x. 1002 reg_buffer[0] = get_register(a0); 1003 reg_buffer[1] = get_register(a1); 1004 memcpy(x, buffer, sizeof(buffer)); 1005 } 1006} 1007 1008 1009// For use in calls that take one double value constructed either 1010// from a0 and a1 or f12 and one integer value. 1011void Simulator::GetFpArgs(double* x, int32_t* y) { 1012 if (!IsMipsSoftFloatABI) { 1013 *x = get_fpu_register_double(12); 1014 *y = get_register(a2); 1015 } else { 1016 // We use a char buffer to get around the strict-aliasing rules which 1017 // otherwise allow the compiler to optimize away the copy. 1018 char buffer[sizeof(*x)]; 1019 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 1020 // Registers 0 and 1 -> x. 1021 reg_buffer[0] = get_register(a0); 1022 reg_buffer[1] = get_register(a1); 1023 memcpy(x, buffer, sizeof(buffer)); 1024 1025 // Register 2 -> y. 1026 reg_buffer[0] = get_register(a2); 1027 memcpy(y, buffer, sizeof(*y)); 1028 } 1029} 1030 1031 1032// The return value is either in v0/v1 or f0. 1033void Simulator::SetFpResult(const double& result) { 1034 if (!IsMipsSoftFloatABI) { 1035 set_fpu_register_double(0, result); 1036 } else { 1037 char buffer[2 * sizeof(registers_[0])]; 1038 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); 1039 memcpy(buffer, &result, sizeof(buffer)); 1040 // Copy result to v0 and v1. 1041 set_register(v0, reg_buffer[0]); 1042 set_register(v1, reg_buffer[1]); 1043 } 1044} 1045 1046 1047// Helper functions for setting and testing the FCSR register's bits. 1048void Simulator::set_fcsr_bit(uint32_t cc, bool value) { 1049 if (value) { 1050 FCSR_ |= (1 << cc); 1051 } else { 1052 FCSR_ &= ~(1 << cc); 1053 } 1054} 1055 1056 1057bool Simulator::test_fcsr_bit(uint32_t cc) { 1058 return FCSR_ & (1 << cc); 1059} 1060 1061 1062// Sets the rounding error codes in FCSR based on the result of the rounding. 1063// Returns true if the operation was invalid. 1064bool Simulator::set_fcsr_round_error(double original, double rounded) { 1065 if (!isfinite(original) || 1066 rounded > LONG_MAX || 1067 rounded < LONG_MIN) { 1068 set_fcsr_bit(6, true); // Invalid operation. 1069 return true; 1070 } else if (original != static_cast<double>(rounded)) { 1071 set_fcsr_bit(2, true); // Inexact. 1072 } 1073 return false; 1074} 1075 1076 1077// Raw access to the PC register. 1078void Simulator::set_pc(int32_t value) { 1079 pc_modified_ = true; 1080 registers_[pc] = value; 1081} 1082 1083 1084bool Simulator::has_bad_pc() const { 1085 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); 1086} 1087 1088 1089// Raw access to the PC register without the special adjustment when reading. 1090int32_t Simulator::get_pc() const { 1091 return registers_[pc]; 1092} 1093 1094 1095// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an 1096// interrupt is caused. On others it does a funky rotation thing. For now we 1097// simply disallow unaligned reads, but at some point we may want to move to 1098// emulating the rotate behaviour. Note that simulator runs have the runtime 1099// system running directly on the host system and only generated code is 1100// executed in the simulator. Since the host is typically IA32 we will not 1101// get the correct MIPS-like behaviour on unaligned accesses. 1102 1103int Simulator::ReadW(int32_t addr, Instruction* instr) { 1104 if (addr >=0 && addr < 0x400) { 1105 // This has to be a NULL-dereference, drop into debugger. 1106 MipsDebugger dbg(this); 1107 dbg.Debug(); 1108 } 1109 if ((addr & kPointerAlignmentMask) == 0) { 1110 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1111 return *ptr; 1112 } 1113 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1114 addr, 1115 reinterpret_cast<intptr_t>(instr)); 1116 MipsDebugger dbg(this); 1117 dbg.Debug(); 1118 return 0; 1119} 1120 1121 1122void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { 1123 if (addr >= 0 && addr < 0x400) { 1124 // This has to be a NULL-dereference, drop into debugger. 1125 MipsDebugger dbg(this); 1126 dbg.Debug(); 1127 } 1128 if ((addr & kPointerAlignmentMask) == 0) { 1129 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1130 *ptr = value; 1131 return; 1132 } 1133 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1134 addr, 1135 reinterpret_cast<intptr_t>(instr)); 1136 MipsDebugger dbg(this); 1137 dbg.Debug(); 1138} 1139 1140 1141double Simulator::ReadD(int32_t addr, Instruction* instr) { 1142 if ((addr & kDoubleAlignmentMask) == 0) { 1143 double* ptr = reinterpret_cast<double*>(addr); 1144 return *ptr; 1145 } 1146 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1147 addr, 1148 reinterpret_cast<intptr_t>(instr)); 1149 OS::Abort(); 1150 return 0; 1151} 1152 1153 1154void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { 1155 if ((addr & kDoubleAlignmentMask) == 0) { 1156 double* ptr = reinterpret_cast<double*>(addr); 1157 *ptr = value; 1158 return; 1159 } 1160 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1161 addr, 1162 reinterpret_cast<intptr_t>(instr)); 1163 OS::Abort(); 1164} 1165 1166 1167uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { 1168 if ((addr & 1) == 0) { 1169 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1170 return *ptr; 1171 } 1172 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1173 addr, 1174 reinterpret_cast<intptr_t>(instr)); 1175 OS::Abort(); 1176 return 0; 1177} 1178 1179 1180int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { 1181 if ((addr & 1) == 0) { 1182 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1183 return *ptr; 1184 } 1185 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1186 addr, 1187 reinterpret_cast<intptr_t>(instr)); 1188 OS::Abort(); 1189 return 0; 1190} 1191 1192 1193void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { 1194 if ((addr & 1) == 0) { 1195 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1196 *ptr = value; 1197 return; 1198 } 1199 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1200 addr, 1201 reinterpret_cast<intptr_t>(instr)); 1202 OS::Abort(); 1203} 1204 1205 1206void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { 1207 if ((addr & 1) == 0) { 1208 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1209 *ptr = value; 1210 return; 1211 } 1212 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", 1213 addr, 1214 reinterpret_cast<intptr_t>(instr)); 1215 OS::Abort(); 1216} 1217 1218 1219uint32_t Simulator::ReadBU(int32_t addr) { 1220 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1221 return *ptr & 0xff; 1222} 1223 1224 1225int32_t Simulator::ReadB(int32_t addr) { 1226 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1227 return *ptr; 1228} 1229 1230 1231void Simulator::WriteB(int32_t addr, uint8_t value) { 1232 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1233 *ptr = value; 1234} 1235 1236 1237void Simulator::WriteB(int32_t addr, int8_t value) { 1238 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1239 *ptr = value; 1240} 1241 1242 1243// Returns the limit of the stack area to enable checking for stack overflows. 1244uintptr_t Simulator::StackLimit() const { 1245 // Leave a safety margin of 256 bytes to prevent overrunning the stack when 1246 // pushing values. 1247 return reinterpret_cast<uintptr_t>(stack_) + 256; 1248} 1249 1250 1251// Unsupported instructions use Format to print an error and stop execution. 1252void Simulator::Format(Instruction* instr, const char* format) { 1253 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", 1254 reinterpret_cast<intptr_t>(instr), format); 1255 UNIMPLEMENTED_MIPS(); 1256} 1257 1258 1259// Calls into the V8 runtime are based on this very simple interface. 1260// Note: To be able to return two values from some calls the code in runtime.cc 1261// uses the ObjectPair which is essentially two 32-bit values stuffed into a 1262// 64-bit value. With the code below we assume that all runtime calls return 1263// 64 bits of result. If they don't, the v1 result register contains a bogus 1264// value, which is fine because it is caller-saved. 1265typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, 1266 int32_t arg1, 1267 int32_t arg2, 1268 int32_t arg3, 1269 int32_t arg4, 1270 int32_t arg5); 1271typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, 1272 int32_t arg1, 1273 int32_t arg2, 1274 int32_t arg3); 1275 1276// This signature supports direct call in to API function native callback 1277// (refer to InvocationCallback in v8.h). 1278typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0); 1279 1280// This signature supports direct call to accessor getter callback. 1281typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, 1282 int32_t arg1); 1283 1284// Software interrupt instructions are used by the simulator to call into the 1285// C-based V8 runtime. They are also used for debugging with simulator. 1286void Simulator::SoftwareInterrupt(Instruction* instr) { 1287 // There are several instructions that could get us here, 1288 // the break_ instruction, or several variants of traps. All 1289 // Are "SPECIAL" class opcode, and are distinuished by function. 1290 int32_t func = instr->FunctionFieldRaw(); 1291 int32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; 1292 1293 // We first check if we met a call_rt_redirected. 1294 if (instr->InstructionBits() == rtCallRedirInstr) { 1295 Redirection* redirection = Redirection::FromSwiInstruction(instr); 1296 int32_t arg0 = get_register(a0); 1297 int32_t arg1 = get_register(a1); 1298 int32_t arg2 = get_register(a2); 1299 int32_t arg3 = get_register(a3); 1300 int32_t arg4 = 0; 1301 int32_t arg5 = 0; 1302 1303 // Need to check if sp is valid before assigning arg4, arg5. 1304 // This is a fix for cctest test-api/CatchStackOverflow which causes 1305 // the stack to overflow. For some reason arm doesn't need this 1306 // stack check here. 1307 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); 1308 int32_t* stack = reinterpret_cast<int32_t*>(stack_); 1309 if (stack_pointer >= stack && stack_pointer < stack + stack_size_ - 5) { 1310 // Args 4 and 5 are on the stack after the reserved space for args 0..3. 1311 arg4 = stack_pointer[4]; 1312 arg5 = stack_pointer[5]; 1313 } 1314 1315 bool fp_call = 1316 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || 1317 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || 1318 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || 1319 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); 1320 1321 if (!IsMipsSoftFloatABI) { 1322 // With the hard floating point calling convention, double 1323 // arguments are passed in FPU registers. Fetch the arguments 1324 // from there and call the builtin using soft floating point 1325 // convention. 1326 switch (redirection->type()) { 1327 case ExternalReference::BUILTIN_FP_FP_CALL: 1328 case ExternalReference::BUILTIN_COMPARE_CALL: 1329 arg0 = get_fpu_register(f12); 1330 arg1 = get_fpu_register(f13); 1331 arg2 = get_fpu_register(f14); 1332 arg3 = get_fpu_register(f15); 1333 break; 1334 case ExternalReference::BUILTIN_FP_CALL: 1335 arg0 = get_fpu_register(f12); 1336 arg1 = get_fpu_register(f13); 1337 break; 1338 case ExternalReference::BUILTIN_FP_INT_CALL: 1339 arg0 = get_fpu_register(f12); 1340 arg1 = get_fpu_register(f13); 1341 arg2 = get_register(a2); 1342 break; 1343 default: 1344 break; 1345 } 1346 } 1347 1348 // This is dodgy but it works because the C entry stubs are never moved. 1349 // See comment in codegen-arm.cc and bug 1242173. 1350 int32_t saved_ra = get_register(ra); 1351 1352 intptr_t external = 1353 reinterpret_cast<intptr_t>(redirection->external_function()); 1354 1355 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware 1356 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this 1357 // simulator. Soft-float has additional abstraction of ExternalReference, 1358 // to support serialization. 1359 if (fp_call) { 1360 SimulatorRuntimeFPCall target = 1361 reinterpret_cast<SimulatorRuntimeFPCall>(external); 1362 if (::v8::internal::FLAG_trace_sim) { 1363 double dval0, dval1; 1364 int32_t ival; 1365 switch (redirection->type()) { 1366 case ExternalReference::BUILTIN_FP_FP_CALL: 1367 case ExternalReference::BUILTIN_COMPARE_CALL: 1368 GetFpArgs(&dval0, &dval1); 1369 PrintF("Call to host function at %p with args %f, %f", 1370 FUNCTION_ADDR(target), dval0, dval1); 1371 break; 1372 case ExternalReference::BUILTIN_FP_CALL: 1373 GetFpArgs(&dval0); 1374 PrintF("Call to host function at %p with arg %f", 1375 FUNCTION_ADDR(target), dval1); 1376 break; 1377 case ExternalReference::BUILTIN_FP_INT_CALL: 1378 GetFpArgs(&dval0, &ival); 1379 PrintF("Call to host function at %p with args %f, %d", 1380 FUNCTION_ADDR(target), dval0, ival); 1381 break; 1382 default: 1383 UNREACHABLE(); 1384 break; 1385 } 1386 } 1387 double result = target(arg0, arg1, arg2, arg3); 1388 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { 1389 SetFpResult(result); 1390 } else { 1391 int32_t gpreg_pair[2]; 1392 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); 1393 set_register(v0, gpreg_pair[0]); 1394 set_register(v1, gpreg_pair[1]); 1395 } 1396 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { 1397 // See DirectCEntryStub::GenerateCall for explanation of register usage. 1398 SimulatorRuntimeDirectApiCall target = 1399 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); 1400 if (::v8::internal::FLAG_trace_sim) { 1401 PrintF("Call to host function at %p args %08x\n", 1402 FUNCTION_ADDR(target), arg1); 1403 } 1404 v8::Handle<v8::Value> result = target(arg1); 1405 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result; 1406 set_register(v0, arg0); 1407 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { 1408 // See DirectCEntryStub::GenerateCall for explanation of register usage. 1409 SimulatorRuntimeDirectGetterCall target = 1410 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); 1411 if (::v8::internal::FLAG_trace_sim) { 1412 PrintF("Call to host function at %p args %08x %08x\n", 1413 FUNCTION_ADDR(target), arg1, arg2); 1414 } 1415 v8::Handle<v8::Value> result = target(arg1, arg2); 1416 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result; 1417 set_register(v0, arg0); 1418 } else { 1419 SimulatorRuntimeCall target = 1420 reinterpret_cast<SimulatorRuntimeCall>(external); 1421 if (::v8::internal::FLAG_trace_sim) { 1422 PrintF( 1423 "Call to host function at %p " 1424 "args %08x, %08x, %08x, %08x, %08x, %08x\n", 1425 FUNCTION_ADDR(target), 1426 arg0, 1427 arg1, 1428 arg2, 1429 arg3, 1430 arg4, 1431 arg5); 1432 } 1433 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); 1434 set_register(v0, static_cast<int32_t>(result)); 1435 set_register(v1, static_cast<int32_t>(result >> 32)); 1436 } 1437 if (::v8::internal::FLAG_trace_sim) { 1438 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0)); 1439 } 1440 set_register(ra, saved_ra); 1441 set_pc(get_register(ra)); 1442 1443 } else if (func == BREAK && code >= 0 && code < 32) { 1444 // First 32 break_ codes interpreted as debug-markers/watchpoints. 1445 MipsDebugger dbg(this); 1446 ++break_count_; 1447 PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------" 1448 "----------------------------------", 1449 code, break_count_, icount_); 1450 dbg.PrintAllRegs(); // Print registers and continue running. 1451 } else { 1452 // All remaining break_ codes, and all traps are handled here. 1453 MipsDebugger dbg(this); 1454 dbg.Debug(); 1455 } 1456} 1457 1458 1459void Simulator::SignalExceptions() { 1460 for (int i = 1; i < kNumExceptions; i++) { 1461 if (exceptions[i] != 0) { 1462 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i); 1463 } 1464 } 1465} 1466 1467 1468// Handle execution based on instruction types. 1469 1470void Simulator::ConfigureTypeRegister(Instruction* instr, 1471 int32_t& alu_out, 1472 int64_t& i64hilo, 1473 uint64_t& u64hilo, 1474 int32_t& next_pc, 1475 bool& do_interrupt) { 1476 // Every local variable declared here needs to be const. 1477 // This is to make sure that changed values are sent back to 1478 // DecodeTypeRegister correctly. 1479 1480 // Instruction fields. 1481 const Opcode op = instr->OpcodeFieldRaw(); 1482 const int32_t rs_reg = instr->RsValue(); 1483 const int32_t rs = get_register(rs_reg); 1484 const uint32_t rs_u = static_cast<uint32_t>(rs); 1485 const int32_t rt_reg = instr->RtValue(); 1486 const int32_t rt = get_register(rt_reg); 1487 const uint32_t rt_u = static_cast<uint32_t>(rt); 1488 const int32_t rd_reg = instr->RdValue(); 1489 const uint32_t sa = instr->SaValue(); 1490 1491 const int32_t fs_reg = instr->FsValue(); 1492 1493 1494 // ---------- Configuration. 1495 switch (op) { 1496 case COP1: // Coprocessor instructions. 1497 switch (instr->RsFieldRaw()) { 1498 case BC1: // Handled in DecodeTypeImmed, should never come here. 1499 UNREACHABLE(); 1500 break; 1501 case CFC1: 1502 // At the moment only FCSR is supported. 1503 ASSERT(fs_reg == kFCSRRegister); 1504 alu_out = FCSR_; 1505 break; 1506 case MFC1: 1507 alu_out = get_fpu_register(fs_reg); 1508 break; 1509 case MFHC1: 1510 UNIMPLEMENTED_MIPS(); 1511 break; 1512 case CTC1: 1513 case MTC1: 1514 case MTHC1: 1515 // Do the store in the execution step. 1516 break; 1517 case S: 1518 case D: 1519 case W: 1520 case L: 1521 case PS: 1522 // Do everything in the execution step. 1523 break; 1524 default: 1525 UNIMPLEMENTED_MIPS(); 1526 }; 1527 break; 1528 case SPECIAL: 1529 switch (instr->FunctionFieldRaw()) { 1530 case JR: 1531 case JALR: 1532 next_pc = get_register(instr->RsValue()); 1533 break; 1534 case SLL: 1535 alu_out = rt << sa; 1536 break; 1537 case SRL: 1538 if (rs_reg == 0) { 1539 // Regular logical right shift of a word by a fixed number of 1540 // bits instruction. RS field is always equal to 0. 1541 alu_out = rt_u >> sa; 1542 } else { 1543 // Logical right-rotate of a word by a fixed number of bits. This 1544 // is special case of SRL instruction, added in MIPS32 Release 2. 1545 // RS field is equal to 00001. 1546 alu_out = (rt_u >> sa) | (rt_u << (32 - sa)); 1547 } 1548 break; 1549 case SRA: 1550 alu_out = rt >> sa; 1551 break; 1552 case SLLV: 1553 alu_out = rt << rs; 1554 break; 1555 case SRLV: 1556 if (sa == 0) { 1557 // Regular logical right-shift of a word by a variable number of 1558 // bits instruction. SA field is always equal to 0. 1559 alu_out = rt_u >> rs; 1560 } else { 1561 // Logical right-rotate of a word by a variable number of bits. 1562 // This is special case od SRLV instruction, added in MIPS32 1563 // Release 2. SA field is equal to 00001. 1564 alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u)); 1565 } 1566 break; 1567 case SRAV: 1568 alu_out = rt >> rs; 1569 break; 1570 case MFHI: 1571 alu_out = get_register(HI); 1572 break; 1573 case MFLO: 1574 alu_out = get_register(LO); 1575 break; 1576 case MULT: 1577 i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt); 1578 break; 1579 case MULTU: 1580 u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u); 1581 break; 1582 case ADD: 1583 if (HaveSameSign(rs, rt)) { 1584 if (rs > 0) { 1585 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt); 1586 } else if (rs < 0) { 1587 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt); 1588 } 1589 } 1590 alu_out = rs + rt; 1591 break; 1592 case ADDU: 1593 alu_out = rs + rt; 1594 break; 1595 case SUB: 1596 if (!HaveSameSign(rs, rt)) { 1597 if (rs > 0) { 1598 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt); 1599 } else if (rs < 0) { 1600 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt); 1601 } 1602 } 1603 alu_out = rs - rt; 1604 break; 1605 case SUBU: 1606 alu_out = rs - rt; 1607 break; 1608 case AND: 1609 alu_out = rs & rt; 1610 break; 1611 case OR: 1612 alu_out = rs | rt; 1613 break; 1614 case XOR: 1615 alu_out = rs ^ rt; 1616 break; 1617 case NOR: 1618 alu_out = ~(rs | rt); 1619 break; 1620 case SLT: 1621 alu_out = rs < rt ? 1 : 0; 1622 break; 1623 case SLTU: 1624 alu_out = rs_u < rt_u ? 1 : 0; 1625 break; 1626 // Break and trap instructions. 1627 case BREAK: 1628 1629 do_interrupt = true; 1630 break; 1631 case TGE: 1632 do_interrupt = rs >= rt; 1633 break; 1634 case TGEU: 1635 do_interrupt = rs_u >= rt_u; 1636 break; 1637 case TLT: 1638 do_interrupt = rs < rt; 1639 break; 1640 case TLTU: 1641 do_interrupt = rs_u < rt_u; 1642 break; 1643 case TEQ: 1644 do_interrupt = rs == rt; 1645 break; 1646 case TNE: 1647 do_interrupt = rs != rt; 1648 break; 1649 case MOVN: 1650 case MOVZ: 1651 case MOVCI: 1652 // No action taken on decode. 1653 break; 1654 case DIV: 1655 case DIVU: 1656 // div and divu never raise exceptions. 1657 break; 1658 default: 1659 UNREACHABLE(); 1660 }; 1661 break; 1662 case SPECIAL2: 1663 switch (instr->FunctionFieldRaw()) { 1664 case MUL: 1665 alu_out = rs_u * rt_u; // Only the lower 32 bits are kept. 1666 break; 1667 case CLZ: 1668 alu_out = __builtin_clz(rs_u); 1669 break; 1670 default: 1671 UNREACHABLE(); 1672 }; 1673 break; 1674 case SPECIAL3: 1675 switch (instr->FunctionFieldRaw()) { 1676 case INS: { // Mips32r2 instruction. 1677 // Interpret rd field as 5-bit msb of insert. 1678 uint16_t msb = rd_reg; 1679 // Interpret sa field as 5-bit lsb of insert. 1680 uint16_t lsb = sa; 1681 uint16_t size = msb - lsb + 1; 1682 uint32_t mask = (1 << size) - 1; 1683 alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb); 1684 break; 1685 } 1686 case EXT: { // Mips32r2 instruction. 1687 // Interpret rd field as 5-bit msb of extract. 1688 uint16_t msb = rd_reg; 1689 // Interpret sa field as 5-bit lsb of extract. 1690 uint16_t lsb = sa; 1691 uint16_t size = msb + 1; 1692 uint32_t mask = (1 << size) - 1; 1693 alu_out = (rs_u & (mask << lsb)) >> lsb; 1694 break; 1695 } 1696 default: 1697 UNREACHABLE(); 1698 }; 1699 break; 1700 default: 1701 UNREACHABLE(); 1702 }; 1703} 1704 1705 1706void Simulator::DecodeTypeRegister(Instruction* instr) { 1707 // Instruction fields. 1708 const Opcode op = instr->OpcodeFieldRaw(); 1709 const int32_t rs_reg = instr->RsValue(); 1710 const int32_t rs = get_register(rs_reg); 1711 const uint32_t rs_u = static_cast<uint32_t>(rs); 1712 const int32_t rt_reg = instr->RtValue(); 1713 const int32_t rt = get_register(rt_reg); 1714 const uint32_t rt_u = static_cast<uint32_t>(rt); 1715 const int32_t rd_reg = instr->RdValue(); 1716 1717 const int32_t fs_reg = instr->FsValue(); 1718 const int32_t ft_reg = instr->FtValue(); 1719 const int32_t fd_reg = instr->FdValue(); 1720 int64_t i64hilo = 0; 1721 uint64_t u64hilo = 0; 1722 1723 // ALU output. 1724 // It should not be used as is. Instructions using it should always 1725 // initialize it first. 1726 int32_t alu_out = 0x12345678; 1727 1728 // For break and trap instructions. 1729 bool do_interrupt = false; 1730 1731 // For jr and jalr. 1732 // Get current pc. 1733 int32_t current_pc = get_pc(); 1734 // Next pc 1735 int32_t next_pc = 0; 1736 1737 // Setup the variables if needed before executing the instruction. 1738 ConfigureTypeRegister(instr, 1739 alu_out, 1740 i64hilo, 1741 u64hilo, 1742 next_pc, 1743 do_interrupt); 1744 1745 // ---------- Raise exceptions triggered. 1746 SignalExceptions(); 1747 1748 // ---------- Execution. 1749 switch (op) { 1750 case COP1: 1751 switch (instr->RsFieldRaw()) { 1752 case BC1: // Branch on coprocessor condition. 1753 UNREACHABLE(); 1754 break; 1755 case CFC1: 1756 set_register(rt_reg, alu_out); 1757 case MFC1: 1758 set_register(rt_reg, alu_out); 1759 break; 1760 case MFHC1: 1761 UNIMPLEMENTED_MIPS(); 1762 break; 1763 case CTC1: 1764 // At the moment only FCSR is supported. 1765 ASSERT(fs_reg == kFCSRRegister); 1766 FCSR_ = registers_[rt_reg]; 1767 break; 1768 case MTC1: 1769 FPUregisters_[fs_reg] = registers_[rt_reg]; 1770 break; 1771 case MTHC1: 1772 UNIMPLEMENTED_MIPS(); 1773 break; 1774 case S: 1775 float f; 1776 switch (instr->FunctionFieldRaw()) { 1777 case CVT_D_S: 1778 f = get_fpu_register_float(fs_reg); 1779 set_fpu_register_double(fd_reg, static_cast<double>(f)); 1780 break; 1781 case CVT_W_S: 1782 case CVT_L_S: 1783 case TRUNC_W_S: 1784 case TRUNC_L_S: 1785 case ROUND_W_S: 1786 case ROUND_L_S: 1787 case FLOOR_W_S: 1788 case FLOOR_L_S: 1789 case CEIL_W_S: 1790 case CEIL_L_S: 1791 case CVT_PS_S: 1792 UNIMPLEMENTED_MIPS(); 1793 break; 1794 default: 1795 UNREACHABLE(); 1796 } 1797 break; 1798 case D: 1799 double ft, fs; 1800 uint32_t cc, fcsr_cc; 1801 int64_t i64; 1802 fs = get_fpu_register_double(fs_reg); 1803 ft = get_fpu_register_double(ft_reg); 1804 cc = instr->FCccValue(); 1805 fcsr_cc = get_fcsr_condition_bit(cc); 1806 switch (instr->FunctionFieldRaw()) { 1807 case ADD_D: 1808 set_fpu_register_double(fd_reg, fs + ft); 1809 break; 1810 case SUB_D: 1811 set_fpu_register_double(fd_reg, fs - ft); 1812 break; 1813 case MUL_D: 1814 set_fpu_register_double(fd_reg, fs * ft); 1815 break; 1816 case DIV_D: 1817 set_fpu_register_double(fd_reg, fs / ft); 1818 break; 1819 case ABS_D: 1820 set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs); 1821 break; 1822 case MOV_D: 1823 set_fpu_register_double(fd_reg, fs); 1824 break; 1825 case NEG_D: 1826 set_fpu_register_double(fd_reg, -fs); 1827 break; 1828 case SQRT_D: 1829 set_fpu_register_double(fd_reg, sqrt(fs)); 1830 break; 1831 case C_UN_D: 1832 set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft)); 1833 break; 1834 case C_EQ_D: 1835 set_fcsr_bit(fcsr_cc, (fs == ft)); 1836 break; 1837 case C_UEQ_D: 1838 set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft))); 1839 break; 1840 case C_OLT_D: 1841 set_fcsr_bit(fcsr_cc, (fs < ft)); 1842 break; 1843 case C_ULT_D: 1844 set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft))); 1845 break; 1846 case C_OLE_D: 1847 set_fcsr_bit(fcsr_cc, (fs <= ft)); 1848 break; 1849 case C_ULE_D: 1850 set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft))); 1851 break; 1852 case CVT_W_D: // Convert double to word. 1853 // Rounding modes are not yet supported. 1854 ASSERT((FCSR_ & 3) == 0); 1855 // In rounding mode 0 it should behave like ROUND. 1856 case ROUND_W_D: // Round double to word. 1857 { 1858 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); 1859 int32_t result = static_cast<int32_t>(rounded); 1860 set_fpu_register(fd_reg, result); 1861 if (set_fcsr_round_error(fs, rounded)) { 1862 set_fpu_register(fd_reg, kFPUInvalidResult); 1863 } 1864 } 1865 break; 1866 case TRUNC_W_D: // Truncate double to word (round towards 0). 1867 { 1868 int32_t result = static_cast<int32_t>(fs); 1869 set_fpu_register(fd_reg, result); 1870 if (set_fcsr_round_error(fs, static_cast<double>(result))) { 1871 set_fpu_register(fd_reg, kFPUInvalidResult); 1872 } 1873 } 1874 break; 1875 case FLOOR_W_D: // Round double to word towards negative infinity. 1876 { 1877 double rounded = floor(fs); 1878 int32_t result = static_cast<int32_t>(rounded); 1879 set_fpu_register(fd_reg, result); 1880 if (set_fcsr_round_error(fs, rounded)) { 1881 set_fpu_register(fd_reg, kFPUInvalidResult); 1882 } 1883 } 1884 break; 1885 case CEIL_W_D: // Round double to word towards positive infinity. 1886 { 1887 double rounded = ceil(fs); 1888 int32_t result = static_cast<int32_t>(rounded); 1889 set_fpu_register(fd_reg, result); 1890 if (set_fcsr_round_error(fs, rounded)) { 1891 set_fpu_register(fd_reg, kFPUInvalidResult); 1892 } 1893 } 1894 break; 1895 case CVT_S_D: // Convert double to float (single). 1896 set_fpu_register_float(fd_reg, static_cast<float>(fs)); 1897 break; 1898 case CVT_L_D: // Mips32r2: Truncate double to 64-bit long-word. 1899 i64 = static_cast<int64_t>(fs); 1900 set_fpu_register(fd_reg, i64 & 0xffffffff); 1901 set_fpu_register(fd_reg + 1, i64 >> 32); 1902 break; 1903 case TRUNC_L_D: // Mips32r2 instruction. 1904 i64 = static_cast<int64_t>(fs); 1905 set_fpu_register(fd_reg, i64 & 0xffffffff); 1906 set_fpu_register(fd_reg + 1, i64 >> 32); 1907 break; 1908 case ROUND_L_D: { // Mips32r2 instruction. 1909 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); 1910 i64 = static_cast<int64_t>(rounded); 1911 set_fpu_register(fd_reg, i64 & 0xffffffff); 1912 set_fpu_register(fd_reg + 1, i64 >> 32); 1913 break; 1914 } 1915 case FLOOR_L_D: // Mips32r2 instruction. 1916 i64 = static_cast<int64_t>(floor(fs)); 1917 set_fpu_register(fd_reg, i64 & 0xffffffff); 1918 set_fpu_register(fd_reg + 1, i64 >> 32); 1919 break; 1920 case CEIL_L_D: // Mips32r2 instruction. 1921 i64 = static_cast<int64_t>(ceil(fs)); 1922 set_fpu_register(fd_reg, i64 & 0xffffffff); 1923 set_fpu_register(fd_reg + 1, i64 >> 32); 1924 break; 1925 case C_F_D: 1926 UNIMPLEMENTED_MIPS(); 1927 break; 1928 default: 1929 UNREACHABLE(); 1930 } 1931 break; 1932 case W: 1933 switch (instr->FunctionFieldRaw()) { 1934 case CVT_S_W: // Convert word to float (single). 1935 alu_out = get_fpu_register(fs_reg); 1936 set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); 1937 break; 1938 case CVT_D_W: // Convert word to double. 1939 alu_out = get_fpu_register(fs_reg); 1940 set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); 1941 break; 1942 default: 1943 UNREACHABLE(); 1944 }; 1945 break; 1946 case L: 1947 switch (instr->FunctionFieldRaw()) { 1948 case CVT_D_L: // Mips32r2 instruction. 1949 // Watch the signs here, we want 2 32-bit vals 1950 // to make a sign-64. 1951 i64 = (uint32_t) get_fpu_register(fs_reg); 1952 i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32); 1953 set_fpu_register_double(fd_reg, static_cast<double>(i64)); 1954 break; 1955 case CVT_S_L: 1956 UNIMPLEMENTED_MIPS(); 1957 break; 1958 default: 1959 UNREACHABLE(); 1960 } 1961 break; 1962 case PS: 1963 break; 1964 default: 1965 UNREACHABLE(); 1966 }; 1967 break; 1968 case SPECIAL: 1969 switch (instr->FunctionFieldRaw()) { 1970 case JR: { 1971 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( 1972 current_pc+Instruction::kInstrSize); 1973 BranchDelayInstructionDecode(branch_delay_instr); 1974 set_pc(next_pc); 1975 pc_modified_ = true; 1976 break; 1977 } 1978 case JALR: { 1979 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( 1980 current_pc+Instruction::kInstrSize); 1981 BranchDelayInstructionDecode(branch_delay_instr); 1982 set_register(31, current_pc + 2 * Instruction::kInstrSize); 1983 set_pc(next_pc); 1984 pc_modified_ = true; 1985 break; 1986 } 1987 // Instructions using HI and LO registers. 1988 case MULT: 1989 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); 1990 set_register(HI, static_cast<int32_t>(i64hilo >> 32)); 1991 break; 1992 case MULTU: 1993 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); 1994 set_register(HI, static_cast<int32_t>(u64hilo >> 32)); 1995 break; 1996 case DIV: 1997 // Divide by zero was not checked in the configuration step - div and 1998 // divu do not raise exceptions. On division by 0, the result will 1999 // be UNPREDICTABLE. 2000 if (rt != 0) { 2001 set_register(LO, rs / rt); 2002 set_register(HI, rs % rt); 2003 } 2004 break; 2005 case DIVU: 2006 if (rt_u != 0) { 2007 set_register(LO, rs_u / rt_u); 2008 set_register(HI, rs_u % rt_u); 2009 } 2010 break; 2011 // Break and trap instructions. 2012 case BREAK: 2013 case TGE: 2014 case TGEU: 2015 case TLT: 2016 case TLTU: 2017 case TEQ: 2018 case TNE: 2019 if (do_interrupt) { 2020 SoftwareInterrupt(instr); 2021 } 2022 break; 2023 // Conditional moves. 2024 case MOVN: 2025 if (rt) set_register(rd_reg, rs); 2026 break; 2027 case MOVCI: { 2028 uint32_t cc = instr->FBccValue(); 2029 uint32_t fcsr_cc = get_fcsr_condition_bit(cc); 2030 if (instr->Bit(16)) { // Read Tf bit. 2031 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); 2032 } else { 2033 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); 2034 } 2035 break; 2036 } 2037 case MOVZ: 2038 if (!rt) set_register(rd_reg, rs); 2039 break; 2040 default: // For other special opcodes we do the default operation. 2041 set_register(rd_reg, alu_out); 2042 }; 2043 break; 2044 case SPECIAL2: 2045 switch (instr->FunctionFieldRaw()) { 2046 case MUL: 2047 set_register(rd_reg, alu_out); 2048 // HI and LO are UNPREDICTABLE after the operation. 2049 set_register(LO, Unpredictable); 2050 set_register(HI, Unpredictable); 2051 break; 2052 default: // For other special2 opcodes we do the default operation. 2053 set_register(rd_reg, alu_out); 2054 } 2055 break; 2056 case SPECIAL3: 2057 switch (instr->FunctionFieldRaw()) { 2058 case INS: 2059 // Ins instr leaves result in Rt, rather than Rd. 2060 set_register(rt_reg, alu_out); 2061 break; 2062 case EXT: 2063 // Ext instr leaves result in Rt, rather than Rd. 2064 set_register(rt_reg, alu_out); 2065 break; 2066 default: 2067 UNREACHABLE(); 2068 }; 2069 break; 2070 // Unimplemented opcodes raised an error in the configuration step before, 2071 // so we can use the default here to set the destination register in common 2072 // cases. 2073 default: 2074 set_register(rd_reg, alu_out); 2075 }; 2076} 2077 2078 2079// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq). 2080void Simulator::DecodeTypeImmediate(Instruction* instr) { 2081 // Instruction fields. 2082 Opcode op = instr->OpcodeFieldRaw(); 2083 int32_t rs = get_register(instr->RsValue()); 2084 uint32_t rs_u = static_cast<uint32_t>(rs); 2085 int32_t rt_reg = instr->RtValue(); // Destination register. 2086 int32_t rt = get_register(rt_reg); 2087 int16_t imm16 = instr->Imm16Value(); 2088 2089 int32_t ft_reg = instr->FtValue(); // Destination register. 2090 2091 // Zero extended immediate. 2092 uint32_t oe_imm16 = 0xffff & imm16; 2093 // Sign extended immediate. 2094 int32_t se_imm16 = imm16; 2095 2096 // Get current pc. 2097 int32_t current_pc = get_pc(); 2098 // Next pc. 2099 int32_t next_pc = bad_ra; 2100 2101 // Used for conditional branch instructions. 2102 bool do_branch = false; 2103 bool execute_branch_delay_instruction = false; 2104 2105 // Used for arithmetic instructions. 2106 int32_t alu_out = 0; 2107 // Floating point. 2108 double fp_out = 0.0; 2109 uint32_t cc, cc_value, fcsr_cc; 2110 2111 // Used for memory instructions. 2112 int32_t addr = 0x0; 2113 // Value to be written in memory. 2114 uint32_t mem_value = 0x0; 2115 2116 // ---------- Configuration (and execution for REGIMM). 2117 switch (op) { 2118 // ------------- COP1. Coprocessor instructions. 2119 case COP1: 2120 switch (instr->RsFieldRaw()) { 2121 case BC1: // Branch on coprocessor condition. 2122 cc = instr->FBccValue(); 2123 fcsr_cc = get_fcsr_condition_bit(cc); 2124 cc_value = test_fcsr_bit(fcsr_cc); 2125 do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; 2126 execute_branch_delay_instruction = true; 2127 // Set next_pc. 2128 if (do_branch) { 2129 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; 2130 } else { 2131 next_pc = current_pc + kBranchReturnOffset; 2132 } 2133 break; 2134 default: 2135 UNREACHABLE(); 2136 }; 2137 break; 2138 // ------------- REGIMM class. 2139 case REGIMM: 2140 switch (instr->RtFieldRaw()) { 2141 case BLTZ: 2142 do_branch = (rs < 0); 2143 break; 2144 case BLTZAL: 2145 do_branch = rs < 0; 2146 break; 2147 case BGEZ: 2148 do_branch = rs >= 0; 2149 break; 2150 case BGEZAL: 2151 do_branch = rs >= 0; 2152 break; 2153 default: 2154 UNREACHABLE(); 2155 }; 2156 switch (instr->RtFieldRaw()) { 2157 case BLTZ: 2158 case BLTZAL: 2159 case BGEZ: 2160 case BGEZAL: 2161 // Branch instructions common part. 2162 execute_branch_delay_instruction = true; 2163 // Set next_pc. 2164 if (do_branch) { 2165 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; 2166 if (instr->IsLinkingInstruction()) { 2167 set_register(31, current_pc + kBranchReturnOffset); 2168 } 2169 } else { 2170 next_pc = current_pc + kBranchReturnOffset; 2171 } 2172 default: 2173 break; 2174 }; 2175 break; // case REGIMM. 2176 // ------------- Branch instructions. 2177 // When comparing to zero, the encoding of rt field is always 0, so we don't 2178 // need to replace rt with zero. 2179 case BEQ: 2180 do_branch = (rs == rt); 2181 break; 2182 case BNE: 2183 do_branch = rs != rt; 2184 break; 2185 case BLEZ: 2186 do_branch = rs <= 0; 2187 break; 2188 case BGTZ: 2189 do_branch = rs > 0; 2190 break; 2191 // ------------- Arithmetic instructions. 2192 case ADDI: 2193 if (HaveSameSign(rs, se_imm16)) { 2194 if (rs > 0) { 2195 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16); 2196 } else if (rs < 0) { 2197 exceptions[kIntegerUnderflow] = 2198 rs < (Registers::kMinValue - se_imm16); 2199 } 2200 } 2201 alu_out = rs + se_imm16; 2202 break; 2203 case ADDIU: 2204 alu_out = rs + se_imm16; 2205 break; 2206 case SLTI: 2207 alu_out = (rs < se_imm16) ? 1 : 0; 2208 break; 2209 case SLTIU: 2210 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0; 2211 break; 2212 case ANDI: 2213 alu_out = rs & oe_imm16; 2214 break; 2215 case ORI: 2216 alu_out = rs | oe_imm16; 2217 break; 2218 case XORI: 2219 alu_out = rs ^ oe_imm16; 2220 break; 2221 case LUI: 2222 alu_out = (oe_imm16 << 16); 2223 break; 2224 // ------------- Memory instructions. 2225 case LB: 2226 addr = rs + se_imm16; 2227 alu_out = ReadB(addr); 2228 break; 2229 case LH: 2230 addr = rs + se_imm16; 2231 alu_out = ReadH(addr, instr); 2232 break; 2233 case LWL: { 2234 // al_offset is offset of the effective address within an aligned word. 2235 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 2236 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 2237 uint32_t mask = (1 << byte_shift * 8) - 1; 2238 addr = rs + se_imm16 - al_offset; 2239 alu_out = ReadW(addr, instr); 2240 alu_out <<= byte_shift * 8; 2241 alu_out |= rt & mask; 2242 break; 2243 } 2244 case LW: 2245 addr = rs + se_imm16; 2246 alu_out = ReadW(addr, instr); 2247 break; 2248 case LBU: 2249 addr = rs + se_imm16; 2250 alu_out = ReadBU(addr); 2251 break; 2252 case LHU: 2253 addr = rs + se_imm16; 2254 alu_out = ReadHU(addr, instr); 2255 break; 2256 case LWR: { 2257 // al_offset is offset of the effective address within an aligned word. 2258 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 2259 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 2260 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; 2261 addr = rs + se_imm16 - al_offset; 2262 alu_out = ReadW(addr, instr); 2263 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8; 2264 alu_out |= rt & mask; 2265 break; 2266 } 2267 case SB: 2268 addr = rs + se_imm16; 2269 break; 2270 case SH: 2271 addr = rs + se_imm16; 2272 break; 2273 case SWL: { 2274 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 2275 uint8_t byte_shift = kPointerAlignmentMask - al_offset; 2276 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; 2277 addr = rs + se_imm16 - al_offset; 2278 mem_value = ReadW(addr, instr) & mask; 2279 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; 2280 break; 2281 } 2282 case SW: 2283 addr = rs + se_imm16; 2284 break; 2285 case SWR: { 2286 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; 2287 uint32_t mask = (1 << al_offset * 8) - 1; 2288 addr = rs + se_imm16 - al_offset; 2289 mem_value = ReadW(addr, instr); 2290 mem_value = (rt << al_offset * 8) | (mem_value & mask); 2291 break; 2292 } 2293 case LWC1: 2294 addr = rs + se_imm16; 2295 alu_out = ReadW(addr, instr); 2296 break; 2297 case LDC1: 2298 addr = rs + se_imm16; 2299 fp_out = ReadD(addr, instr); 2300 break; 2301 case SWC1: 2302 case SDC1: 2303 addr = rs + se_imm16; 2304 break; 2305 default: 2306 UNREACHABLE(); 2307 }; 2308 2309 // ---------- Raise exceptions triggered. 2310 SignalExceptions(); 2311 2312 // ---------- Execution. 2313 switch (op) { 2314 // ------------- Branch instructions. 2315 case BEQ: 2316 case BNE: 2317 case BLEZ: 2318 case BGTZ: 2319 // Branch instructions common part. 2320 execute_branch_delay_instruction = true; 2321 // Set next_pc. 2322 if (do_branch) { 2323 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; 2324 if (instr->IsLinkingInstruction()) { 2325 set_register(31, current_pc + 2* Instruction::kInstrSize); 2326 } 2327 } else { 2328 next_pc = current_pc + 2 * Instruction::kInstrSize; 2329 } 2330 break; 2331 // ------------- Arithmetic instructions. 2332 case ADDI: 2333 case ADDIU: 2334 case SLTI: 2335 case SLTIU: 2336 case ANDI: 2337 case ORI: 2338 case XORI: 2339 case LUI: 2340 set_register(rt_reg, alu_out); 2341 break; 2342 // ------------- Memory instructions. 2343 case LB: 2344 case LH: 2345 case LWL: 2346 case LW: 2347 case LBU: 2348 case LHU: 2349 case LWR: 2350 set_register(rt_reg, alu_out); 2351 break; 2352 case SB: 2353 WriteB(addr, static_cast<int8_t>(rt)); 2354 break; 2355 case SH: 2356 WriteH(addr, static_cast<uint16_t>(rt), instr); 2357 break; 2358 case SWL: 2359 WriteW(addr, mem_value, instr); 2360 break; 2361 case SW: 2362 WriteW(addr, rt, instr); 2363 break; 2364 case SWR: 2365 WriteW(addr, mem_value, instr); 2366 break; 2367 case LWC1: 2368 set_fpu_register(ft_reg, alu_out); 2369 break; 2370 case LDC1: 2371 set_fpu_register_double(ft_reg, fp_out); 2372 break; 2373 case SWC1: 2374 addr = rs + se_imm16; 2375 WriteW(addr, get_fpu_register(ft_reg), instr); 2376 break; 2377 case SDC1: 2378 addr = rs + se_imm16; 2379 WriteD(addr, get_fpu_register_double(ft_reg), instr); 2380 break; 2381 default: 2382 break; 2383 }; 2384 2385 2386 if (execute_branch_delay_instruction) { 2387 // Execute branch delay slot 2388 // We don't check for end_sim_pc. First it should not be met as the current 2389 // pc is valid. Secondly a jump should always execute its branch delay slot. 2390 Instruction* branch_delay_instr = 2391 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize); 2392 BranchDelayInstructionDecode(branch_delay_instr); 2393 } 2394 2395 // If needed update pc after the branch delay execution. 2396 if (next_pc != bad_ra) { 2397 set_pc(next_pc); 2398 } 2399} 2400 2401 2402// Type 3: instructions using a 26 bytes immediate. (eg: j, jal). 2403void Simulator::DecodeTypeJump(Instruction* instr) { 2404 // Get current pc. 2405 int32_t current_pc = get_pc(); 2406 // Get unchanged bits of pc. 2407 int32_t pc_high_bits = current_pc & 0xf0000000; 2408 // Next pc. 2409 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2); 2410 2411 // Execute branch delay slot. 2412 // We don't check for end_sim_pc. First it should not be met as the current pc 2413 // is valid. Secondly a jump should always execute its branch delay slot. 2414 Instruction* branch_delay_instr = 2415 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); 2416 BranchDelayInstructionDecode(branch_delay_instr); 2417 2418 // Update pc and ra if necessary. 2419 // Do this after the branch delay execution. 2420 if (instr->IsLinkingInstruction()) { 2421 set_register(31, current_pc + 2 * Instruction::kInstrSize); 2422 } 2423 set_pc(next_pc); 2424 pc_modified_ = true; 2425} 2426 2427 2428// Executes the current instruction. 2429void Simulator::InstructionDecode(Instruction* instr) { 2430 if (v8::internal::FLAG_check_icache) { 2431 CheckICache(isolate_->simulator_i_cache(), instr); 2432 } 2433 pc_modified_ = false; 2434 if (::v8::internal::FLAG_trace_sim) { 2435 disasm::NameConverter converter; 2436 disasm::Disassembler dasm(converter); 2437 // Use a reasonably large buffer. 2438 v8::internal::EmbeddedVector<char, 256> buffer; 2439 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); 2440 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), 2441 buffer.start()); 2442 } 2443 2444 switch (instr->InstructionType()) { 2445 case Instruction::kRegisterType: 2446 DecodeTypeRegister(instr); 2447 break; 2448 case Instruction::kImmediateType: 2449 DecodeTypeImmediate(instr); 2450 break; 2451 case Instruction::kJumpType: 2452 DecodeTypeJump(instr); 2453 break; 2454 default: 2455 UNSUPPORTED(); 2456 } 2457 if (!pc_modified_) { 2458 set_register(pc, reinterpret_cast<int32_t>(instr) + 2459 Instruction::kInstrSize); 2460 } 2461} 2462 2463 2464 2465void Simulator::Execute() { 2466 // Get the PC to simulate. Cannot use the accessor here as we need the 2467 // raw PC value and not the one used as input to arithmetic instructions. 2468 int program_counter = get_pc(); 2469 if (::v8::internal::FLAG_stop_sim_at == 0) { 2470 // Fast version of the dispatch loop without checking whether the simulator 2471 // should be stopping at a particular executed instruction. 2472 while (program_counter != end_sim_pc) { 2473 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); 2474 icount_++; 2475 InstructionDecode(instr); 2476 program_counter = get_pc(); 2477 } 2478 } else { 2479 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when 2480 // we reach the particular instuction count. 2481 while (program_counter != end_sim_pc) { 2482 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); 2483 icount_++; 2484 if (icount_ == ::v8::internal::FLAG_stop_sim_at) { 2485 MipsDebugger dbg(this); 2486 dbg.Debug(); 2487 } else { 2488 InstructionDecode(instr); 2489 } 2490 program_counter = get_pc(); 2491 } 2492 } 2493} 2494 2495 2496int32_t Simulator::Call(byte* entry, int argument_count, ...) { 2497 va_list parameters; 2498 va_start(parameters, argument_count); 2499 // Setup arguments. 2500 2501 // First four arguments passed in registers. 2502 ASSERT(argument_count >= 4); 2503 set_register(a0, va_arg(parameters, int32_t)); 2504 set_register(a1, va_arg(parameters, int32_t)); 2505 set_register(a2, va_arg(parameters, int32_t)); 2506 set_register(a3, va_arg(parameters, int32_t)); 2507 2508 // Remaining arguments passed on stack. 2509 int original_stack = get_register(sp); 2510 // Compute position of stack on entry to generated code. 2511 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) 2512 - kCArgsSlotsSize); 2513 if (OS::ActivationFrameAlignment() != 0) { 2514 entry_stack &= -OS::ActivationFrameAlignment(); 2515 } 2516 // Store remaining arguments on stack, from low to high memory. 2517 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); 2518 for (int i = 4; i < argument_count; i++) { 2519 stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t); 2520 } 2521 va_end(parameters); 2522 set_register(sp, entry_stack); 2523 2524 // Prepare to execute the code at entry. 2525 set_register(pc, reinterpret_cast<int32_t>(entry)); 2526 // Put down marker for end of simulation. The simulator will stop simulation 2527 // when the PC reaches this value. By saving the "end simulation" value into 2528 // the LR the simulation stops when returning to this call point. 2529 set_register(ra, end_sim_pc); 2530 2531 // Remember the values of callee-saved registers. 2532 // The code below assumes that r9 is not used as sb (static base) in 2533 // simulator code and therefore is regarded as a callee-saved register. 2534 int32_t s0_val = get_register(s0); 2535 int32_t s1_val = get_register(s1); 2536 int32_t s2_val = get_register(s2); 2537 int32_t s3_val = get_register(s3); 2538 int32_t s4_val = get_register(s4); 2539 int32_t s5_val = get_register(s5); 2540 int32_t s6_val = get_register(s6); 2541 int32_t s7_val = get_register(s7); 2542 int32_t gp_val = get_register(gp); 2543 int32_t sp_val = get_register(sp); 2544 int32_t fp_val = get_register(fp); 2545 2546 // Setup the callee-saved registers with a known value. To be able to check 2547 // that they are preserved properly across JS execution. 2548 int32_t callee_saved_value = icount_; 2549 set_register(s0, callee_saved_value); 2550 set_register(s1, callee_saved_value); 2551 set_register(s2, callee_saved_value); 2552 set_register(s3, callee_saved_value); 2553 set_register(s4, callee_saved_value); 2554 set_register(s5, callee_saved_value); 2555 set_register(s6, callee_saved_value); 2556 set_register(s7, callee_saved_value); 2557 set_register(gp, callee_saved_value); 2558 set_register(fp, callee_saved_value); 2559 2560 // Start the simulation. 2561 Execute(); 2562 2563 // Check that the callee-saved registers have been preserved. 2564 CHECK_EQ(callee_saved_value, get_register(s0)); 2565 CHECK_EQ(callee_saved_value, get_register(s1)); 2566 CHECK_EQ(callee_saved_value, get_register(s2)); 2567 CHECK_EQ(callee_saved_value, get_register(s3)); 2568 CHECK_EQ(callee_saved_value, get_register(s4)); 2569 CHECK_EQ(callee_saved_value, get_register(s5)); 2570 CHECK_EQ(callee_saved_value, get_register(s6)); 2571 CHECK_EQ(callee_saved_value, get_register(s7)); 2572 CHECK_EQ(callee_saved_value, get_register(gp)); 2573 CHECK_EQ(callee_saved_value, get_register(fp)); 2574 2575 // Restore callee-saved registers with the original value. 2576 set_register(s0, s0_val); 2577 set_register(s1, s1_val); 2578 set_register(s2, s2_val); 2579 set_register(s3, s3_val); 2580 set_register(s4, s4_val); 2581 set_register(s5, s5_val); 2582 set_register(s6, s6_val); 2583 set_register(s7, s7_val); 2584 set_register(gp, gp_val); 2585 set_register(sp, sp_val); 2586 set_register(fp, fp_val); 2587 2588 // Pop stack passed arguments. 2589 CHECK_EQ(entry_stack, get_register(sp)); 2590 set_register(sp, original_stack); 2591 2592 int32_t result = get_register(v0); 2593 return result; 2594} 2595 2596 2597uintptr_t Simulator::PushAddress(uintptr_t address) { 2598 int new_sp = get_register(sp) - sizeof(uintptr_t); 2599 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); 2600 *stack_slot = address; 2601 set_register(sp, new_sp); 2602 return new_sp; 2603} 2604 2605 2606uintptr_t Simulator::PopAddress() { 2607 int current_sp = get_register(sp); 2608 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); 2609 uintptr_t address = *stack_slot; 2610 set_register(sp, current_sp + sizeof(uintptr_t)); 2611 return address; 2612} 2613 2614 2615#undef UNSUPPORTED 2616 2617} } // namespace v8::internal 2618 2619#endif // USE_SIMULATOR 2620 2621#endif // V8_TARGET_ARCH_MIPS 2622