| OLD | NEW |
| (Empty) | |
| 1 #include <stdlib.h> |
| 2 #include <cstdarg> |
| 3 #include "v8.h" |
| 4 |
| 5 #include "disasm.h" |
| 6 #include "assembler.h" |
| 7 #include "mips/constants-mips.h" |
| 8 #include "mips/simulator-mips.h" |
| 9 |
| 10 #if !defined(__mips) |
| 11 |
| 12 // Only build the simulator if not compiling for real MIPS hardware. |
| 13 namespace assembler { |
| 14 namespace mips { |
| 15 |
| 16 using ::v8::internal::Object; |
| 17 using ::v8::internal::PrintF; |
| 18 using ::v8::internal::OS; |
| 19 using ::v8::internal::ReadLine; |
| 20 using ::v8::internal::DeleteArray; |
| 21 |
| 22 // Utils functions |
| 23 bool haveSameSign(int32_t a, int32_t b) { |
| 24 return ((a & signMask) == (b & signMask)); |
| 25 } |
| 26 |
| 27 |
| 28 // This macro provides a platform independent use of sscanf. The reason for |
| 29 // SScanF not being implemented in a platform independent was through |
| 30 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time |
| 31 // Library does not provide vsscanf. |
| 32 #define SScanF sscanf // NOLINT |
| 33 |
| 34 // The Debugger class is used by the simulator while debugging simulated MIPS |
| 35 // code. |
| 36 class Debugger { |
| 37 public: |
| 38 explicit Debugger(Simulator* sim); |
| 39 ~Debugger(); |
| 40 |
| 41 void Stop(Instruction* instr); |
| 42 void Debug(); |
| 43 |
| 44 private: |
| 45 // We set the breakpoint code to 0xfffff to easily recognize it. |
| 46 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6; |
| 47 static const Instr kNopInstr = 0x0; |
| 48 |
| 49 Simulator* sim_; |
| 50 |
| 51 int32_t GetRegisterValue(int regnum); |
| 52 bool GetValue(const char* desc, int32_t* value); |
| 53 |
| 54 // Set or delete a breakpoint. Returns true if successful. |
| 55 bool SetBreakpoint(Instruction* breakpc); |
| 56 bool DeleteBreakpoint(Instruction* breakpc); |
| 57 |
| 58 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 59 // execution to skip past breakpoints when run from the debugger. |
| 60 void UndoBreakpoints(); |
| 61 void RedoBreakpoints(); |
| 62 }; |
| 63 |
| 64 Debugger::Debugger(Simulator* sim) { |
| 65 sim_ = sim; |
| 66 } |
| 67 |
| 68 Debugger::~Debugger() { |
| 69 } |
| 70 |
| 71 #ifdef GENERATED_CODE_COVERAGE |
| 72 static FILE* coverage_log = NULL; |
| 73 |
| 74 |
| 75 static void InitializeCoverage() { |
| 76 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); |
| 77 if (file_name != NULL) { |
| 78 coverage_log = fopen(file_name, "aw+"); |
| 79 } |
| 80 } |
| 81 |
| 82 |
| 83 void Debugger::Stop(Instruction* instr) { |
| 84 UNIMPLEMENTED_(); |
| 85 char* str = reinterpret_cast<char*>(instr->InstructionBits()); |
| 86 if (strlen(str) > 0) { |
| 87 if (coverage_log != NULL) { |
| 88 fprintf(coverage_log, "%s\n", str); |
| 89 fflush(coverage_log); |
| 90 } |
| 91 instr->SetInstructionBits(0x0); // Overwrite with nop. |
| 92 } |
| 93 sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize); |
| 94 } |
| 95 |
| 96 #else // ndef GENERATED_CODE_COVERAGE |
| 97 |
| 98 static void InitializeCoverage() {} |
| 99 |
| 100 |
| 101 void Debugger::Stop(Instruction* instr) { |
| 102 const char* str = (const char*)(instr->InstructionBits()); |
| 103 PrintF("Simulator hit %s\n", str); |
| 104 sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize); |
| 105 Debug(); |
| 106 } |
| 107 #endif // def GENERATED_CODE_COVERAGE |
| 108 |
| 109 |
| 110 int32_t Debugger::GetRegisterValue(int regnum) { |
| 111 if (regnum == kPCRegister) { |
| 112 return sim_->get_pc(); |
| 113 } else { |
| 114 return sim_->get_register(regnum); |
| 115 } |
| 116 } |
| 117 |
| 118 |
| 119 bool Debugger::GetValue(const char* desc, int32_t* value) { |
| 120 int regnum = Registers::Number(desc); |
| 121 if (regnum != kInvalidRegister) { |
| 122 *value = GetRegisterValue(regnum); |
| 123 return true; |
| 124 } else { |
| 125 return SScanF(desc, "%i", value) == 1; |
| 126 } |
| 127 return false; |
| 128 } |
| 129 |
| 130 |
| 131 bool Debugger::SetBreakpoint(Instruction* breakpc) { |
| 132 // Check if a breakpoint can be set. If not return without any side-effects. |
| 133 if (sim_->break_pc_ != NULL) { |
| 134 return false; |
| 135 } |
| 136 |
| 137 // Set the breakpoint. |
| 138 sim_->break_pc_ = breakpc; |
| 139 sim_->break_instr_ = breakpc->InstructionBits(); |
| 140 // Not setting the breakpoint instruction in the code itself. It will be set |
| 141 // when the debugger shell continues. |
| 142 return true; |
| 143 } |
| 144 |
| 145 |
| 146 bool Debugger::DeleteBreakpoint(Instruction* breakpc) { |
| 147 if (sim_->break_pc_ != NULL) { |
| 148 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 149 } |
| 150 |
| 151 sim_->break_pc_ = NULL; |
| 152 sim_->break_instr_ = 0; |
| 153 return true; |
| 154 } |
| 155 |
| 156 |
| 157 void Debugger::UndoBreakpoints() { |
| 158 if (sim_->break_pc_ != NULL) { |
| 159 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 160 } |
| 161 } |
| 162 |
| 163 |
| 164 void Debugger::RedoBreakpoints() { |
| 165 if (sim_->break_pc_ != NULL) { |
| 166 sim_->break_pc_->SetInstructionBits(kBreakpointInstr); |
| 167 } |
| 168 } |
| 169 |
| 170 |
| 171 void Debugger::Debug() { |
| 172 UNIMPLEMENTED_(); |
| 173 // intptr_t last_pc = -1; |
| 174 // bool done = false; |
| 175 // |
| 176 //#define COMMAND_SIZE 63 |
| 177 //#define ARG_SIZE 255 |
| 178 // |
| 179 //#define STR(a) #a |
| 180 //#define XSTR(a) STR(a) |
| 181 // |
| 182 // char cmd[COMMAND_SIZE + 1]; |
| 183 // char arg1[ARG_SIZE + 1]; |
| 184 // char arg2[ARG_SIZE + 1]; |
| 185 // |
| 186 // // make sure to have a proper terminating character if reaching the limit |
| 187 // cmd[COMMAND_SIZE] = 0; |
| 188 // arg1[ARG_SIZE] = 0; |
| 189 // arg2[ARG_SIZE] = 0; |
| 190 // |
| 191 // // Undo all set breakpoints while running in the debugger shell. This will |
| 192 // // make them invisible to all commands. |
| 193 // UndoBreakpoints(); |
| 194 // |
| 195 // while (!done) { |
| 196 // if (last_pc != sim_->get_pc()) { |
| 197 // disasm::NameConverter converter; |
| 198 // disasm::Disassembler dasm(converter); |
| 199 // // use a reasonably large buffer |
| 200 // v8::internal::EmbeddedVector<char, 256> buffer; |
| 201 // dasm.InstructionDecode(buffer, |
| 202 // reinterpret_cast<byte*>(sim_->get_pc())); |
| 203 // PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start()); |
| 204 // last_pc = sim_->get_pc(); |
| 205 // } |
| 206 // char* line = ReadLine("sim> "); |
| 207 // if (line == NULL) { |
| 208 // break; |
| 209 // } else { |
| 210 // // Use sscanf to parse the individual parts of the command line. At the |
| 211 // // moment no command expects more than two parameters. |
| 212 // int args = SScanF(line, |
| 213 // "%" XSTR(COMMAND_SIZE) "s " |
| 214 // "%" XSTR(ARG_SIZE) "s " |
| 215 // "%" XSTR(ARG_SIZE) "s", |
| 216 // cmd, arg1, arg2); |
| 217 // if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 218 // sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc())
); |
| 219 // } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 220 // // Execute the one instruction we broke at with breakpoints disabled. |
| 221 // sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc())
); |
| 222 // // Leave the debugger shell. |
| 223 // done = true; |
| 224 // } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 225 // if (args == 2) { |
| 226 // int32_t value; |
| 227 // if (strcmp(arg1, "all") == 0) { |
| 228 // for (int i = 0; i < kNumRegisters; i++) { |
| 229 // value = GetRegisterValue(i); |
| 230 // PrintF("%3s: 0x%08x %10d\n", Registers::Name(i), value, value); |
| 231 // } |
| 232 // } else { |
| 233 // if (GetValue(arg1, &value)) { |
| 234 // PrintF("%s: 0x%08x %d \n", arg1, value, value); |
| 235 // } else { |
| 236 // PrintF("%s unrecognized\n", arg1); |
| 237 // } |
| 238 // } |
| 239 // } else { |
| 240 // PrintF("print <register>\n"); |
| 241 // } |
| 242 // } else if ((strcmp(cmd, "po") == 0) |
| 243 // || (strcmp(cmd, "printobject") == 0)) { |
| 244 // if (args == 2) { |
| 245 // int32_t value; |
| 246 // if (GetValue(arg1, &value)) { |
| 247 // Object* obj = reinterpret_cast<Object*>(value); |
| 248 // PrintF("%s: \n", arg1); |
| 249 //#ifdef DEBUG |
| 250 // obj->PrintLn(); |
| 251 //#else |
| 252 // obj->ShortPrint(); |
| 253 // PrintF("\n"); |
| 254 //#endif |
| 255 // } else { |
| 256 // PrintF("%s unrecognized\n", arg1); |
| 257 // } |
| 258 // } else { |
| 259 // PrintF("printobject <value>\n"); |
| 260 // } |
| 261 // } else if (strcmp(cmd, "disasm") == 0) { |
| 262 // disasm::NameConverter converter; |
| 263 // disasm::Disassembler dasm(converter); |
| 264 // // use a reasonably large buffer |
| 265 // v8::internal::EmbeddedVector<char, 256> buffer; |
| 266 // |
| 267 // byte* cur = NULL; |
| 268 // byte* end = NULL; |
| 269 // |
| 270 // if (args == 1) { |
| 271 // cur = reinterpret_cast<byte*>(sim_->get_pc()); |
| 272 // end = cur + (10 * Instruction::kInstructionSize); |
| 273 // } else if (args == 2) { |
| 274 // int32_t value; |
| 275 // if (GetValue(arg1, &value)) { |
| 276 // cur = reinterpret_cast<byte*>(value); |
| 277 // // no length parameter passed, assume 10 instructions |
| 278 // end = cur + (10 * Instruction::kInstructionSize); |
| 279 // } |
| 280 // } else { |
| 281 // int32_t value1; |
| 282 // int32_t value2; |
| 283 // if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { |
| 284 // cur = reinterpret_cast<byte*>(value1); |
| 285 // end = cur + (value2 * Instruction::kInstructionSize); |
| 286 // } |
| 287 // } |
| 288 // |
| 289 // while (cur < end) { |
| 290 // dasm.InstructionDecode(buffer, cur); |
| 291 // PrintF(" 0x%08x %s\n", cur, buffer.start()); |
| 292 // cur += Instruction::kInstructionSize; |
| 293 // } |
| 294 // } else if (strcmp(cmd, "gdb") == 0) { |
| 295 // PrintF("relinquishing control to gdb\n"); |
| 296 // v8::internal::OS::DebugBreak(); |
| 297 // PrintF("regaining control from gdb\n"); |
| 298 // } else if (strcmp(cmd, "break") == 0) { |
| 299 // if (args == 2) { |
| 300 // int32_t value; |
| 301 // if (GetValue(arg1, &value)) { |
| 302 // if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) { |
| 303 // PrintF("setting breakpoint failed\n"); |
| 304 // } |
| 305 // } else { |
| 306 // PrintF("%s unrecognized\n", arg1); |
| 307 // } |
| 308 // } else { |
| 309 // PrintF("break <address>\n"); |
| 310 // } |
| 311 // } else if (strcmp(cmd, "del") == 0) { |
| 312 // if (!DeleteBreakpoint(NULL)) { |
| 313 // PrintF("deleting breakpoint failed\n"); |
| 314 // } |
| 315 // } else if (strcmp(cmd, "flags") == 0) { |
| 316 // PrintF("N flag: %d; ", sim_->n_flag_); |
| 317 // PrintF("Z flag: %d; ", sim_->z_flag_); |
| 318 // PrintF("C flag: %d; ", sim_->c_flag_); |
| 319 // PrintF("V flag: %d\n", sim_->v_flag_); |
| 320 // } else if (strcmp(cmd, "unstop") == 0) { |
| 321 // intptr_t stop_pc = sim_->get_pc() - Instruction::kInstructionSize; |
| 322 // Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc); |
| 323 // if (stop_instr->ConditionField() == special_condition) { |
| 324 // stop_instr->SetInstructionBits(kNopInstr); |
| 325 // } else { |
| 326 // PrintF("Not at debugger stop."); |
| 327 // } |
| 328 // } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
| 329 // PrintF("cont\n"); |
| 330 // PrintF(" continue execution (alias 'c')\n"); |
| 331 // PrintF("stepi\n"); |
| 332 // PrintF(" step one instruction (alias 'si')\n"); |
| 333 // PrintF("print <register>\n"); |
| 334 // PrintF(" print register content (alias 'p')\n"); |
| 335 // PrintF(" use register name 'all' to print all registers\n"); |
| 336 // PrintF("printobject <register>\n"); |
| 337 // PrintF(" print an object from a register (alias 'po')\n"); |
| 338 // PrintF("flags\n"); |
| 339 // PrintF(" print flags\n"); |
| 340 // PrintF("disasm [<instructions>]\n"); |
| 341 // PrintF("disasm [[<address>] <instructions>]\n"); |
| 342 // PrintF(" disassemble code, default is 10 instructions from pc\n"); |
| 343 // PrintF("gdb\n"); |
| 344 // PrintF(" enter gdb\n"); |
| 345 // PrintF("break <address>\n"); |
| 346 // PrintF(" set a break point on the address\n"); |
| 347 // PrintF("del\n"); |
| 348 // PrintF(" delete the breakpoint\n"); |
| 349 // PrintF("unstop\n"); |
| 350 // PrintF(" ignore the stop instruction at the current location"); |
| 351 // PrintF(" from now on\n"); |
| 352 // } else { |
| 353 // PrintF("Unknown command: %s\n", cmd); |
| 354 // } |
| 355 // } |
| 356 // DeleteArray(line); |
| 357 // } |
| 358 // |
| 359 // // Add all the breakpoints back to stop execution and enter the debugger |
| 360 // // shell when hit. |
| 361 // RedoBreakpoints(); |
| 362 // |
| 363 //#undef COMMAND_SIZE |
| 364 //#undef ARG_SIZE |
| 365 // |
| 366 //#undef STR |
| 367 //#undef XSTR |
| 368 } |
| 369 |
| 370 |
| 371 // Create one simulator per thread and keep it in thread local storage. |
| 372 static v8::internal::Thread::LocalStorageKey simulator_key; |
| 373 |
| 374 |
| 375 bool Simulator::initialized_ = false; |
| 376 |
| 377 |
| 378 void Simulator::Initialize() { |
| 379 if (initialized_) return; |
| 380 simulator_key = v8::internal::Thread::CreateThreadLocalKey(); |
| 381 initialized_ = true; |
| 382 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); |
| 383 } |
| 384 |
| 385 |
| 386 Simulator::Simulator() { |
| 387 Initialize(); |
| 388 // Setup simulator support first. Some of this information is needed to |
| 389 // setup the architecture state. |
| 390 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
| 391 stack_ = reinterpret_cast<char*>(malloc(stack_size)); |
| 392 pc_modified_ = false; |
| 393 icount_ = 0; |
| 394 break_pc_ = NULL; |
| 395 break_instr_ = 0; |
| 396 |
| 397 // Setup architecture state. |
| 398 // All registers are initialized to zero to start with. |
| 399 for (int i = 0; i < num_registers; i++) { |
| 400 registers_[i] = 0; |
| 401 } |
| 402 |
| 403 // The sp is initialized to point to the bottom (high address) of the |
| 404 // allocated stack area. To be safe in potential stack underflows we leave |
| 405 // some buffer below. |
| 406 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; |
| 407 // The ra and pc are initialized to a known bad value that will cause an |
| 408 // access violation if the simulator ever tries to execute it. |
| 409 registers_[pc] = bad_ra; |
| 410 registers_[ra] = bad_ra; |
| 411 InitializeCoverage(); |
| 412 } |
| 413 |
| 414 |
| 415 // When the generated code calls an external reference we need to catch that in |
| 416 // the simulator. The external reference will be a function compiled for the |
| 417 // host architecture. We need to call that function instead of trying to |
| 418 // execute it with the simulator. We do that by redirecting the external |
| 419 // reference to a swi (software-interrupt) instruction that is handled by |
| 420 // the simulator. We write the original destination of the jump just at a known |
| 421 // offset from the swi instruction so the simulator knows what to call. |
| 422 class Redirection { |
| 423 // public: |
| 424 // Redirection(void* external_function, bool fp_return) |
| 425 // : external_function_(external_function), |
| 426 // swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), |
| 427 // fp_return_(fp_return), |
| 428 // next_(list_) { |
| 429 // list_ = this; |
| 430 // } |
| 431 // |
| 432 // void* address_of_swi_instruction() { |
| 433 // return reinterpret_cast<void*>(&swi_instruction_); |
| 434 // } |
| 435 // |
| 436 // void* external_function() { return external_function_; } |
| 437 // bool fp_return() { return fp_return_; } |
| 438 // |
| 439 // static Redirection* Get(void* external_function, bool fp_return) { |
| 440 // Redirection* current; |
| 441 // for (current = list_; current != NULL; current = current->next_) { |
| 442 // if (current->external_function_ == external_function) return current; |
| 443 // } |
| 444 // return new Redirection(external_function, fp_return); |
| 445 // } |
| 446 // |
| 447 // static Redirection* FromSwiInstruction(Instruction* swi_instruction) { |
| 448 // char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); |
| 449 // char* addr_of_redirection = |
| 450 // addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); |
| 451 // return reinterpret_cast<Redirection*>(addr_of_redirection); |
| 452 // } |
| 453 |
| 454 private: |
| 455 void* external_function_; |
| 456 uint32_t swi_instruction_; |
| 457 bool fp_return_; |
| 458 Redirection* next_; |
| 459 static Redirection* list_; |
| 460 }; |
| 461 |
| 462 |
| 463 Redirection* Redirection::list_ = NULL; |
| 464 |
| 465 |
| 466 void* Simulator::RedirectExternalReference(void* external_function, |
| 467 bool fp_return) { |
| 468 // Redirection* redirection = Redirection::Get(external_function, fp_return); |
| 469 // return redirection->address_of_swi_instruction(); |
| 470 return NULL; |
| 471 } |
| 472 |
| 473 |
| 474 // Get the active Simulator for the current thread. |
| 475 Simulator* Simulator::current() { |
| 476 Initialize(); |
| 477 Simulator* sim = reinterpret_cast<Simulator*>( |
| 478 v8::internal::Thread::GetThreadLocal(simulator_key)); |
| 479 if (sim == NULL) { |
| 480 // TODO(146): delete the simulator object when a thread goes away. |
| 481 sim = new Simulator(); |
| 482 v8::internal::Thread::SetThreadLocal(simulator_key, sim); |
| 483 } |
| 484 return sim; |
| 485 } |
| 486 |
| 487 |
| 488 // Sets the register in the architecture state. It will also deal with updating |
| 489 // Simulator internal state for special registers such as PC. |
| 490 void Simulator::set_register(int reg, int32_t value) { |
| 491 ASSERT((reg >= 0) && (reg < num_registers)); |
| 492 if (reg == pc) { |
| 493 pc_modified_ = true; |
| 494 } |
| 495 |
| 496 // zero register always hold 0. |
| 497 registers_[reg] = (reg==0) ? 0 : value; |
| 498 } |
| 499 |
| 500 // Set the CRegister. No special case. |
| 501 void Simulator::set_Cregister(int creg, double value) { |
| 502 ASSERT((creg >= 0) && (creg < num_Cregisters) && (creg%2==0)); |
| 503 Cregisters_[creg] = value; |
| 504 } |
| 505 |
| 506 |
| 507 // Get the register from the architecture state. This function does handle |
| 508 // the special case of accessing the PC register. |
| 509 int32_t Simulator::get_register(int reg) const { |
| 510 ASSERT((reg >= 0) && (reg < num_registers)); |
| 511 if(reg==0) |
| 512 return 0; |
| 513 else |
| 514 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); |
| 515 } |
| 516 |
| 517 // Get the CRegister. No special case |
| 518 double Simulator::get_Cregister(int creg) const { |
| 519 ASSERT((creg >= 0) && (creg < num_Cregisters) && (creg%2==0)); |
| 520 return registers_[creg]; |
| 521 } |
| 522 |
| 523 int32_t Simulator::get_CregisterHI(int creg) const { |
| 524 ASSERT((creg >= 0) && (creg < num_Cregisters) && (creg%2==0)); |
| 525 return *(((int32_t*)&Cregisters_[creg])+1); |
| 526 } |
| 527 |
| 528 int32_t Simulator::get_CregisterLO(int creg) const { |
| 529 ASSERT((creg >= 0) && (creg < num_Cregisters) && (creg%2==0)); |
| 530 return (int32_t)Cregisters_[creg]; |
| 531 } |
| 532 |
| 533 // Raw access to the PC register. |
| 534 void Simulator::set_pc(int32_t value) { |
| 535 pc_modified_ = true; |
| 536 registers_[pc] = value; |
| 537 } |
| 538 |
| 539 |
| 540 // Raw access to the PC register without the special adjustment when reading. |
| 541 int32_t Simulator::get_pc() const { |
| 542 return registers_[pc]; |
| 543 } |
| 544 |
| 545 |
| 546 // For use in calls that take two double values, constructed from r0, r1, r2 |
| 547 // and r3. |
| 548 //void Simulator::GetFpArgs(double* x, double* y) { |
| 549 // // We use a char buffer to get around the strict-aliasing rules which |
| 550 // // otherwise allow the compiler to optimize away the copy. |
| 551 // char buffer[2 * sizeof(registers_[0])]; |
| 552 // // Registers 0 and 1 -> x. |
| 553 // memcpy(buffer, registers_, sizeof(buffer)); |
| 554 // memcpy(x, buffer, sizeof(buffer)); |
| 555 // // Registers 2 and 3 -> y. |
| 556 // memcpy(buffer, registers_ + 2, sizeof(buffer)); |
| 557 // memcpy(y, buffer, sizeof(buffer)); |
| 558 //} |
| 559 |
| 560 |
| 561 //void Simulator::SetFpResult(const double& result) { |
| 562 // char buffer[2 * sizeof(registers_[0])]; |
| 563 // memcpy(buffer, &result, sizeof(buffer)); |
| 564 // // result -> registers 0 and 1. |
| 565 // memcpy(registers_, buffer, sizeof(buffer)); |
| 566 //} |
| 567 |
| 568 |
| 569 //void Simulator::TrashCallerSaveRegisters() { |
| 570 // // We don't trash the registers with the return value. |
| 571 // registers_[2] = 0x50Bad4U; |
| 572 // registers_[3] = 0x50Bad4U; |
| 573 // registers_[12] = 0x50Bad4U; |
| 574 //} |
| 575 |
| 576 |
| 577 // The ARM cannot do unaligned reads and writes. On some ARM platforms an |
| 578 // interrupt is caused. On others it does a funky rotation thing. For now we |
| 579 // simply disallow unaligned reads, but at some point we may want to move to |
| 580 // emulating the rotate behaviour. Note that simulator runs have the runtime |
| 581 // system running directly on the host system and only generated code is |
| 582 // executed in the simulator. Since the host is typically IA32 we will not |
| 583 // get the correct ARM-like behaviour on unaligned accesses. |
| 584 |
| 585 int Simulator::ReadW(int32_t addr, Instruction* instr) { |
| 586 if ((addr & 3) == 0) { |
| 587 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 588 return *ptr; |
| 589 } |
| 590 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr); |
| 591 UNIMPLEMENTED_(); |
| 592 return 0; |
| 593 } |
| 594 |
| 595 |
| 596 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { |
| 597 if ((addr & 3) == 0) { |
| 598 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 599 *ptr = value; |
| 600 return; |
| 601 } |
| 602 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr); |
| 603 UNIMPLEMENTED_(); |
| 604 } |
| 605 |
| 606 |
| 607 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { |
| 608 if ((addr & 1) == 0) { |
| 609 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 610 return *ptr; |
| 611 } |
| 612 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr); |
| 613 UNIMPLEMENTED_(); |
| 614 return 0; |
| 615 } |
| 616 |
| 617 |
| 618 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { |
| 619 if ((addr & 1) == 0) { |
| 620 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 621 return *ptr; |
| 622 } |
| 623 PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr, instr); |
| 624 UNIMPLEMENTED_(); |
| 625 return 0; |
| 626 } |
| 627 |
| 628 |
| 629 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { |
| 630 if ((addr & 1) == 0) { |
| 631 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 632 *ptr = value; |
| 633 return; |
| 634 } |
| 635 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr); |
| 636 UNIMPLEMENTED_(); |
| 637 } |
| 638 |
| 639 |
| 640 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { |
| 641 if ((addr & 1) == 0) { |
| 642 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 643 *ptr = value; |
| 644 return; |
| 645 } |
| 646 PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr); |
| 647 UNIMPLEMENTED_(); |
| 648 } |
| 649 |
| 650 |
| 651 uint32_t Simulator::ReadBU(int32_t addr) { |
| 652 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 653 return *ptr & 0xff; |
| 654 } |
| 655 |
| 656 |
| 657 int32_t Simulator::ReadB(int32_t addr) { |
| 658 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 659 return ((*ptr<<24)>>24) & 0xff; |
| 660 } |
| 661 |
| 662 |
| 663 void Simulator::WriteB(int32_t addr, uint8_t value) { |
| 664 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 665 *ptr = value; |
| 666 } |
| 667 |
| 668 |
| 669 void Simulator::WriteB(int32_t addr, int8_t value) { |
| 670 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 671 *ptr = value; |
| 672 } |
| 673 |
| 674 |
| 675 // Returns the limit of the stack area to enable checking for stack overflows. |
| 676 uintptr_t Simulator::StackLimit() const { |
| 677 // Leave a safety margin of 256 bytes to prevent overrunning the stack when |
| 678 // pushing values. |
| 679 return reinterpret_cast<uintptr_t>(stack_) + 256; |
| 680 } |
| 681 |
| 682 |
| 683 // Unsupported instructions use Format to print an error and stop execution. |
| 684 void Simulator::Format(Instruction* instr, const char* format) { |
| 685 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", |
| 686 instr, format); |
| 687 UNIMPLEMENTED_(); |
| 688 } |
| 689 |
| 690 |
| 691 // Calls into the V8 runtime are based on this very simple interface. |
| 692 // Note: To be able to return two values from some calls the code in runtime.cc |
| 693 // uses the ObjectPair which is essentially two 32-bit values stuffed into a |
| 694 // 64-bit value. With the code below we assume that all runtime calls return |
| 695 // 64 bits of result. If they don't, the r1 result register contains a bogus |
| 696 // value, which is fine because it is caller-saved. |
| 697 //typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, |
| 698 // int32_t arg1, |
| 699 // int32_t arg2, |
| 700 // int32_t arg3); |
| 701 //typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, |
| 702 // int32_t arg1, |
| 703 // int32_t arg2, |
| 704 // int32_t arg3); |
| 705 |
| 706 |
| 707 // Software interrupt instructions are used by the simulator to call into the |
| 708 // C-based V8 runtime. |
| 709 //void Simulator::SoftwareInterrupt(Instruction* instr) { |
| 710 // int swi = instr->SwiField(); |
| 711 // switch (swi) { |
| 712 // case call_rt_redirected: { |
| 713 // Redirection* redirection = Redirection::FromSwiInstruction(instr); |
| 714 // int32_t arg0 = get_register(r0); |
| 715 // int32_t arg1 = get_register(r1); |
| 716 // int32_t arg2 = get_register(r2); |
| 717 // int32_t arg3 = get_register(r3); |
| 718 // // This is dodgy but it works because the C entry stubs are never moved. |
| 719 // // See comment in codegen-arm.cc and bug 1242173. |
| 720 // int32_t saved_lr = get_register(lr); |
| 721 // if (redirection->fp_return()) { |
| 722 // intptr_t external = |
| 723 // reinterpret_cast<intptr_t>(redirection->external_function()); |
| 724 // SimulatorRuntimeFPCall target = |
| 725 // reinterpret_cast<SimulatorRuntimeFPCall>(external); |
| 726 // if (::v8::internal::FLAG_trace_sim) { |
| 727 // double x, y; |
| 728 // GetFpArgs(&x, &y); |
| 729 // PrintF("Call to host function at %p with args %f, %f\n", |
| 730 // FUNCTION_ADDR(target), x, y); |
| 731 // } |
| 732 // double result = target(arg0, arg1, arg2, arg3); |
| 733 // SetFpResult(result); |
| 734 // } else { |
| 735 // intptr_t external = |
| 736 // reinterpret_cast<int32_t>(redirection->external_function()); |
| 737 // SimulatorRuntimeCall target = |
| 738 // reinterpret_cast<SimulatorRuntimeCall>(external); |
| 739 // if (::v8::internal::FLAG_trace_sim) { |
| 740 // PrintF( |
| 741 // "Call to host function at %p with args %08x, %08x, %08x, %08x\n"
, |
| 742 // FUNCTION_ADDR(target), |
| 743 // arg0, |
| 744 // arg1, |
| 745 // arg2, |
| 746 // arg3); |
| 747 // } |
| 748 // int64_t result = target(arg0, arg1, arg2, arg3); |
| 749 // int32_t lo_res = static_cast<int32_t>(result); |
| 750 // int32_t hi_res = static_cast<int32_t>(result >> 32); |
| 751 // if (::v8::internal::FLAG_trace_sim) { |
| 752 // PrintF("Returned %08x\n", lo_res); |
| 753 // } |
| 754 // set_register(r0, lo_res); |
| 755 // set_register(r1, hi_res); |
| 756 // } |
| 757 // set_register(lr, saved_lr); |
| 758 // set_pc(get_register(lr)); |
| 759 // break; |
| 760 // } |
| 761 // case break_point: { |
| 762 // Debugger dbg(this); |
| 763 // dbg.Debug(); |
| 764 // break; |
| 765 // } |
| 766 // default: { |
| 767 // UNREACHABLE(); |
| 768 // break; |
| 769 // } |
| 770 // } |
| 771 //} |
| 772 |
| 773 void Simulator::SignalExceptions() { |
| 774 for(int i=1; i < num_exceptions; i++) { |
| 775 if(exceptions[i] != 0) { |
| 776 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i); |
| 777 } |
| 778 } |
| 779 } |
| 780 |
| 781 // Handle execution based on instruction types. |
| 782 void Simulator::DecodeType1(Instruction* instr) { |
| 783 // Instruction fields |
| 784 Opcode op = instr->OpcodeFieldRaw(); |
| 785 int32_t rs = get_register(instr->rsField()); |
| 786 int32_t rs_reg= instr->rsField(); |
| 787 int32_t rt = get_register(instr->rtField()); |
| 788 int32_t rt_reg= instr->rtField(); |
| 789 int32_t rd_reg= instr->rdField(); |
| 790 uint32_t sa = instr->saField(); |
| 791 |
| 792 // ALU output |
| 793 int32_t alu_out; |
| 794 |
| 795 // ---------- Configuration |
| 796 switch(op) { |
| 797 case COP1: // Coprocessor instructions |
| 798 switch(instr->rsFieldRaw()) { |
| 799 case BC1: // branch on coprocessor condition |
| 800 UNREACHABLE(); |
| 801 break; |
| 802 case MFC1: |
| 803 alu_out = get_CregisterLO(rs_reg); |
| 804 break; |
| 805 case MFHC1: |
| 806 alu_out = get_CregisterHI(rs_reg); |
| 807 break; |
| 808 case MTC1: |
| 809 case MTHC1: |
| 810 // Do the store in the execution step. |
| 811 break; |
| 812 case S: |
| 813 case D: |
| 814 case W: |
| 815 case L: |
| 816 case PS: |
| 817 // Do everything in the execution step. |
| 818 break; |
| 819 default: |
| 820 UNIMPLEMENTED_(); |
| 821 break; |
| 822 }; |
| 823 break; |
| 824 case SPECIAL: |
| 825 switch(instr->functionFieldRaw()) { |
| 826 case SLL: |
| 827 alu_out = rt << sa; |
| 828 break; |
| 829 case SRL: |
| 830 alu_out = (uint32_t)rt >> sa; |
| 831 break; |
| 832 case SRA: |
| 833 alu_out = (int32_t)rt >> sa; |
| 834 break; |
| 835 case SLLV: |
| 836 alu_out = rt << rs; |
| 837 break; |
| 838 case SRLV: |
| 839 alu_out = (uint32_t)rt >> rs; |
| 840 break; |
| 841 case SRAV: |
| 842 alu_out = (int32_t)rt >> rs; |
| 843 break; |
| 844 case MFHI: |
| 845 alu_out = get_register(HI); |
| 846 break; |
| 847 case MFLO: |
| 848 alu_out = get_register(LO); |
| 849 break; |
| 850 case MULT: |
| 851 UNIMPLEMENTED_(); |
| 852 break; |
| 853 case MULTU: |
| 854 UNIMPLEMENTED_(); |
| 855 break; |
| 856 case DIV: |
| 857 UNIMPLEMENTED_(); |
| 858 break; |
| 859 case DIVU: |
| 860 UNIMPLEMENTED_(); |
| 861 break; |
| 862 case ADD: |
| 863 if(haveSameSign(rs, rt)) { |
| 864 if(rs>0) { |
| 865 exceptions[integer_overflow] = rs > (Registers::max_val() - rt); |
| 866 } else { |
| 867 exceptions[integer_underflow] = rs < (Registers::min_val() - rt); |
| 868 } |
| 869 } |
| 870 alu_out = rs + rt; |
| 871 break; |
| 872 case ADDU: |
| 873 alu_out = rs + rt; |
| 874 break; |
| 875 case SUB: |
| 876 if(!haveSameSign(rs, rt)) { |
| 877 if(rs>0) { |
| 878 exceptions[integer_overflow] = rs > (Registers::max_val() + rt); |
| 879 } else { |
| 880 exceptions[integer_underflow] = rs < (Registers::min_val() + rt); |
| 881 } |
| 882 } |
| 883 alu_out = rs - rt; |
| 884 break; |
| 885 case SUBU: |
| 886 alu_out = rs - rt; |
| 887 break; |
| 888 case AND: |
| 889 alu_out = rs & rt; |
| 890 break; |
| 891 case OR: |
| 892 alu_out = rs | rt; |
| 893 break; |
| 894 case XOR: |
| 895 alu_out = rs ^ rt; |
| 896 break; |
| 897 case NOR: |
| 898 alu_out = ~(rs | rt); |
| 899 break; |
| 900 case SLT: |
| 901 alu_out = (int32_t) rs < (int32_t) rt ? 1 : 0; |
| 902 break; |
| 903 case SLTU: |
| 904 alu_out = (uint32_t) rs < (uint32_t) rt ? 1 : 0; |
| 905 break; |
| 906 case TGE: |
| 907 UNIMPLEMENTED_(); |
| 908 break; |
| 909 case TGEU: |
| 910 UNIMPLEMENTED_(); |
| 911 break; |
| 912 case TLT: |
| 913 UNIMPLEMENTED_(); |
| 914 break; |
| 915 case TLTU: |
| 916 UNIMPLEMENTED_(); |
| 917 break; |
| 918 case TEQ: |
| 919 UNIMPLEMENTED_(); |
| 920 break; |
| 921 case TNE: |
| 922 UNIMPLEMENTED_(); |
| 923 break; |
| 924 default: |
| 925 UNREACHABLE(); |
| 926 break; |
| 927 }; |
| 928 break; |
| 929 case SPECIAL2: |
| 930 switch(instr->functionFieldRaw()) { |
| 931 case MUL: |
| 932 alu_out = rs * rt; // Only the lower 32 bits are kept. |
| 933 break; |
| 934 default: |
| 935 UNREACHABLE(); |
| 936 break; |
| 937 } |
| 938 break; |
| 939 default: |
| 940 UNREACHABLE(); |
| 941 break; |
| 942 }; |
| 943 |
| 944 // ---------- Raise exceptions triggered. |
| 945 SignalExceptions(); |
| 946 |
| 947 // ---------- Execution |
| 948 switch(op) { |
| 949 case COP1: |
| 950 switch(instr->rsFieldRaw()) { |
| 951 case BC1: // branch on coprocessor condition |
| 952 UNREACHABLE(); |
| 953 break; |
| 954 case MFC1: |
| 955 case MFHC1: |
| 956 set_register(rd_reg, alu_out); |
| 957 break; |
| 958 case MTC1: |
| 959 // We don't need to set the higher bits to 0, because MIPS ISA says |
| 960 // they are in an unpredictable state after executing MTC1. |
| 961 Cregisters_[rs_reg] = *((double*)®isters_[rt_reg]); |
| 962 break; |
| 963 case MTHC1: |
| 964 // Here we need to keep the lower bits unchanged. |
| 965 *(((int32_t*)&Cregisters_[rs_reg])+1) = registers_[rt_reg]; |
| 966 break; |
| 967 case S: |
| 968 switch(instr->functionFieldRaw()) { |
| 969 case CVT_D_S: |
| 970 case CVT_W_S: |
| 971 case CVT_L_S: |
| 972 case CVT_PS_S: |
| 973 UNIMPLEMENTED_(); |
| 974 break; |
| 975 default: |
| 976 UNREACHABLE(); |
| 977 } |
| 978 break; |
| 979 case D: |
| 980 switch(instr->functionFieldRaw()) { |
| 981 case CVT_S_D: |
| 982 case CVT_W_D: |
| 983 case CVT_L_D: |
| 984 UNIMPLEMENTED_(); |
| 985 break; |
| 986 default: |
| 987 UNREACHABLE(); |
| 988 } |
| 989 break; |
| 990 case W: |
| 991 switch(instr->functionFieldRaw()) { |
| 992 case CVT_S_W: |
| 993 UNIMPLEMENTED_(); |
| 994 break; |
| 995 case CVT_D_W: // Convert word to double. |
| 996 set_Cregister(rd_reg, static_cast<double>(rs)); |
| 997 break; |
| 998 default: |
| 999 UNREACHABLE(); |
| 1000 }; |
| 1001 break; |
| 1002 case L: |
| 1003 switch(instr->functionFieldRaw()) { |
| 1004 case CVT_S_L: |
| 1005 case CVT_D_L: |
| 1006 UNIMPLEMENTED_(); |
| 1007 break; |
| 1008 default: |
| 1009 UNREACHABLE(); |
| 1010 } |
| 1011 break; |
| 1012 case PS: |
| 1013 break; |
| 1014 default: |
| 1015 UNREACHABLE(); |
| 1016 break; |
| 1017 }; |
| 1018 break; |
| 1019 // Unimplemented opcodes raised an error in the configuration step before, |
| 1020 // so we can use the default here to set the destination register in common |
| 1021 // cases. |
| 1022 default: |
| 1023 set_register(rd_reg, alu_out); |
| 1024 }; |
| 1025 |
| 1026 |
| 1027 } |
| 1028 |
| 1029 // Type 2: instructions using a 16 bytes immediate. (eg: addi, beq) |
| 1030 void Simulator::DecodeType2(Instruction* instr) { |
| 1031 |
| 1032 // Instruction fields |
| 1033 Opcode op = instr->OpcodeFieldRaw(); |
| 1034 int32_t rt_reg= instr->rtField(); // destination register |
| 1035 int32_t rs = get_register(instr->rsField()); |
| 1036 int32_t rt = get_register(instr->rtField()); |
| 1037 int16_t imm16 = instr->Imm16Field(); |
| 1038 |
| 1039 // zero extended immediate |
| 1040 uint32_t oe_imm16 = 0xffff & imm16; |
| 1041 // sign extended immediate |
| 1042 int32_t se_imm16 = imm16; |
| 1043 |
| 1044 // Get current pc. |
| 1045 int32_t current_pc = get_pc(); |
| 1046 // Next pc. |
| 1047 int32_t next_pc = bad_ra; |
| 1048 |
| 1049 // Used for conditional branch instructions |
| 1050 bool do_branch = false; |
| 1051 bool execute_branch_delay_instruction = false; |
| 1052 |
| 1053 // Used for arithmetic instructions |
| 1054 int32_t alu_out; |
| 1055 |
| 1056 // Used for memory instructions |
| 1057 int32_t addr; |
| 1058 |
| 1059 // ---------- Configuration (and execution for REGIMM) |
| 1060 switch(op) { |
| 1061 //////////////// COP1. Coprocessor instructions |
| 1062 case COP1: |
| 1063 switch(instr->rsFieldRaw()) { |
| 1064 case BC1: // branch on coprocessor condition |
| 1065 UNIMPLEMENTED_(); |
| 1066 break; |
| 1067 default: |
| 1068 UNREACHABLE(); |
| 1069 break; |
| 1070 }; |
| 1071 break; |
| 1072 //////////////// REGIMM class |
| 1073 case REGIMM: |
| 1074 switch(instr->rtFieldRaw()) { |
| 1075 case BLTZ: |
| 1076 do_branch = (rs < rt); |
| 1077 break; |
| 1078 case BLTZAL: |
| 1079 do_branch = rs < rt; |
| 1080 break; |
| 1081 case BGEZ: |
| 1082 do_branch = rs >= rt; |
| 1083 break; |
| 1084 case BGEZAL: |
| 1085 do_branch = rs >= rt; |
| 1086 break; |
| 1087 // case TGEI: |
| 1088 // case TGEIU: |
| 1089 default: |
| 1090 UNREACHABLE(); |
| 1091 }; |
| 1092 switch(instr->rtFieldRaw()) { |
| 1093 case BLTZ: |
| 1094 case BLTZAL: |
| 1095 case BGEZ: |
| 1096 case BGEZAL: |
| 1097 // Branch instructions common part. |
| 1098 execute_branch_delay_instruction = true; |
| 1099 // Set next_pc |
| 1100 if(do_branch) { |
| 1101 next_pc = current_pc + (imm16<<2) + Instruction::kInstructionSize; |
| 1102 if (instr->isLinkingInstruction()) { |
| 1103 set_register(31, current_pc + 2* Instruction::kInstructionSize); |
| 1104 } |
| 1105 } else { |
| 1106 next_pc = current_pc + 2 * Instruction::kInstructionSize; |
| 1107 } |
| 1108 // case TGEI: |
| 1109 // case TGEIU: |
| 1110 default: |
| 1111 break; |
| 1112 }; |
| 1113 break; // case REGIMM |
| 1114 //////////////// Branch instructions |
| 1115 // When comparing to zero, the encoding of rt field is always 0, so we don't |
| 1116 // need to replace rt with zero. |
| 1117 case BEQ: |
| 1118 do_branch = (rs == rt); |
| 1119 break; |
| 1120 case BNE: |
| 1121 do_branch = rs != rt; |
| 1122 break; |
| 1123 case BLEZ: |
| 1124 do_branch = rs <= rt; |
| 1125 break; |
| 1126 case BGTZ: |
| 1127 do_branch = rs > rt; |
| 1128 break; |
| 1129 //////////////// Arithmetic instructions |
| 1130 case ADDI: |
| 1131 if(haveSameSign(rs, se_imm16)) { |
| 1132 if(rs>0) { |
| 1133 exceptions[integer_overflow] = rs > (Registers::max_val() - se_imm16); |
| 1134 } else { |
| 1135 exceptions[integer_underflow] = rs < (Registers::min_val() - se_imm16)
; |
| 1136 } |
| 1137 } |
| 1138 alu_out = rs + se_imm16; |
| 1139 break; |
| 1140 case ADDIU: |
| 1141 alu_out = rs + se_imm16; |
| 1142 break; |
| 1143 case SLTI: |
| 1144 alu_out = (rs < se_imm16) ? 1 : 0; |
| 1145 break; |
| 1146 case SLTIU: |
| 1147 alu_out = ((uint32_t)rs < (uint32_t)se_imm16) ? 1 : 0; |
| 1148 break; |
| 1149 case ANDI: |
| 1150 alu_out = rs & oe_imm16; |
| 1151 break; |
| 1152 case ORI: |
| 1153 alu_out = rs | oe_imm16; |
| 1154 break; |
| 1155 case XORI: |
| 1156 alu_out = rs ^ oe_imm16; |
| 1157 break; |
| 1158 case LUI: |
| 1159 alu_out = (oe_imm16<<16); |
| 1160 break; |
| 1161 //////////////// Memory instructions |
| 1162 case LB: |
| 1163 addr = rs + se_imm16; |
| 1164 // alu_out = (((*(byte*)addr))<<24)>>24; |
| 1165 alu_out = ReadB(addr); |
| 1166 break; |
| 1167 case LW: |
| 1168 addr = rs + se_imm16; |
| 1169 // alu_out = (*(int32_t*)addr); |
| 1170 alu_out = ReadW(addr, instr); |
| 1171 break; |
| 1172 case LBU: |
| 1173 addr = rs + se_imm16; |
| 1174 // alu_out = (*(byte*)addr); |
| 1175 alu_out = ReadBU(addr); |
| 1176 break; |
| 1177 case SB: |
| 1178 addr = rs + se_imm16; |
| 1179 break; |
| 1180 case SW: |
| 1181 addr = rs + se_imm16; |
| 1182 break; |
| 1183 default: |
| 1184 UNREACHABLE(); |
| 1185 }; |
| 1186 |
| 1187 // ---------- Raise exceptions triggered. |
| 1188 SignalExceptions(); |
| 1189 |
| 1190 // ---------- Execution |
| 1191 switch(op) { |
| 1192 //////////////// Branch instructions |
| 1193 case BEQ: |
| 1194 case BNE: |
| 1195 case BLEZ: |
| 1196 case BGTZ: |
| 1197 // Branch instructions common part. |
| 1198 execute_branch_delay_instruction = true; |
| 1199 // Set next_pc |
| 1200 if(do_branch) { |
| 1201 next_pc = current_pc + (imm16<<2) + Instruction::kInstructionSize; |
| 1202 if (instr->isLinkingInstruction()) { |
| 1203 set_register(31, current_pc + 2* Instruction::kInstructionSize); |
| 1204 } |
| 1205 } else { |
| 1206 next_pc = current_pc + 2 * Instruction::kInstructionSize; |
| 1207 } |
| 1208 break; |
| 1209 //////////////// Arithmetic instructions |
| 1210 case ADDI: |
| 1211 case ADDIU: |
| 1212 case SLTI: |
| 1213 case SLTIU: |
| 1214 case ANDI: |
| 1215 case ORI: |
| 1216 case XORI: |
| 1217 case LUI: |
| 1218 set_register(rt_reg, alu_out); |
| 1219 break; |
| 1220 //////////////// Memory instructions |
| 1221 case LB: |
| 1222 case LW: |
| 1223 case LBU: |
| 1224 set_register(rt_reg, alu_out); |
| 1225 break; |
| 1226 case SB: |
| 1227 WriteB(addr, (int8_t)rt); |
| 1228 break; |
| 1229 case SW: |
| 1230 WriteW(addr, rt, instr); |
| 1231 break; |
| 1232 default: |
| 1233 break; |
| 1234 }; |
| 1235 |
| 1236 |
| 1237 if(execute_branch_delay_instruction) { |
| 1238 // Execute branch delay slot |
| 1239 // We don't check for end_sim_pc. First it should not be met as the current
pc |
| 1240 // is valid. Secondly a jump should always execute its branch delay slot. |
| 1241 Instruction* branch_delay_instr = |
| 1242 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstruct
ionSize); |
| 1243 BranchDelayInstructionDecode(branch_delay_instr); |
| 1244 } |
| 1245 |
| 1246 // If needed update pc after the branch delay execution. |
| 1247 if(next_pc != bad_ra) { |
| 1248 set_pc(next_pc); |
| 1249 pc_modified_ = true; |
| 1250 } |
| 1251 } |
| 1252 |
| 1253 // Type 3: instructions using a 26 bytes immediate. (eg: j, jal) |
| 1254 void Simulator::DecodeType3(Instruction* instr) { |
| 1255 |
| 1256 // Get current pc. |
| 1257 int32_t current_pc = get_pc(); |
| 1258 // Get unchanged bits of pc. |
| 1259 int32_t pc_high_bits = current_pc & 0xf0000000 ; |
| 1260 // Next pc |
| 1261 int32_t next_pc; |
| 1262 |
| 1263 // Compute new pc. |
| 1264 switch (instr->OpcodeFieldRaw()) { |
| 1265 case SPECIAL: |
| 1266 // Jump instructions from the SPECIAL class are JR and JALR. |
| 1267 next_pc = get_register(instr->rsField()); |
| 1268 break; |
| 1269 default: |
| 1270 next_pc = pc_high_bits | (instr->Imm26Field()<<2); |
| 1271 break; |
| 1272 }; |
| 1273 |
| 1274 |
| 1275 // Execute branch delay slot |
| 1276 // We don't check for end_sim_pc. First it should not be met as the current pc |
| 1277 // is valid. Secondly a jump should always execute its branch delay slot. |
| 1278 Instruction* branch_delay_instr = |
| 1279 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstruct
ionSize); |
| 1280 BranchDelayInstructionDecode(branch_delay_instr); |
| 1281 |
| 1282 // Update pc and ra if necessary. |
| 1283 // Do this after the branch delay execution. |
| 1284 if (instr->isLinkingInstruction()) { |
| 1285 set_register(31, current_pc + 2* Instruction::kInstructionSize); |
| 1286 } |
| 1287 set_pc(next_pc); |
| 1288 pc_modified_ = true; |
| 1289 } |
| 1290 |
| 1291 // Executes the current instruction. |
| 1292 void Simulator::InstructionDecode(Instruction* instr) { |
| 1293 pc_modified_ = false; |
| 1294 if (::v8::internal::FLAG_trace_sim) { |
| 1295 disasm::NameConverter converter; |
| 1296 disasm::Disassembler dasm(converter); |
| 1297 // use a reasonably large buffer |
| 1298 v8::internal::EmbeddedVector<char, 256> buffer; |
| 1299 dasm.InstructionDecode(buffer, |
| 1300 reinterpret_cast<byte*>(instr)); |
| 1301 PrintF(" 0x%08x %s\n", instr, buffer.start()); |
| 1302 } |
| 1303 |
| 1304 switch (instr->instrType()) { |
| 1305 case 1: |
| 1306 DecodeType1(instr); |
| 1307 break; |
| 1308 case 2: |
| 1309 DecodeType2(instr); |
| 1310 break; |
| 1311 case 3: |
| 1312 DecodeType3(instr); |
| 1313 break; |
| 1314 default: |
| 1315 UNREACHABLE(); |
| 1316 } |
| 1317 if (!pc_modified_) { |
| 1318 set_register(pc, reinterpret_cast<int32_t>(instr) + Instruction::kInstructio
nSize); |
| 1319 } |
| 1320 } |
| 1321 |
| 1322 |
| 1323 |
| 1324 void Simulator::Execute() { |
| 1325 // Get the PC to simulate. Cannot use the accessor here as we need the |
| 1326 // raw PC value and not the one used as input to arithmetic instructions. |
| 1327 int program_counter = get_pc(); |
| 1328 // |
| 1329 if (::v8::internal::FLAG_stop_sim_at == 0) { |
| 1330 // Fast version of the dispatch loop without checking whether the simulator |
| 1331 // should be stopping at a particular executed instruction. |
| 1332 while (program_counter != end_sim_pc) { |
| 1333 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); |
| 1334 icount_++; |
| 1335 InstructionDecode(instr); |
| 1336 program_counter = get_pc(); |
| 1337 } |
| 1338 } else { |
| 1339 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
| 1340 // we reach the particular instuction count. |
| 1341 while (program_counter != end_sim_pc) { |
| 1342 Instruction* instr = reinterpret_cast<Instruction*>(program_counter); |
| 1343 icount_++; |
| 1344 if (icount_ == ::v8::internal::FLAG_stop_sim_at) { |
| 1345 Debugger dbg(this); |
| 1346 dbg.Debug(); |
| 1347 } else { |
| 1348 InstructionDecode(instr); |
| 1349 } |
| 1350 program_counter = get_pc(); |
| 1351 } |
| 1352 } |
| 1353 } |
| 1354 |
| 1355 |
| 1356 int32_t Simulator::Call(byte* entry, int argument_count, ...) { |
| 1357 va_list parameters; |
| 1358 va_start(parameters, argument_count); |
| 1359 // Setup arguments |
| 1360 |
| 1361 // First four arguments passed in registers. |
| 1362 ASSERT(argument_count >= 4); |
| 1363 set_register(a0, va_arg(parameters, int32_t)); |
| 1364 set_register(a1, va_arg(parameters, int32_t)); |
| 1365 set_register(a2, va_arg(parameters, int32_t)); |
| 1366 set_register(a3, va_arg(parameters, int32_t)); |
| 1367 |
| 1368 // Remaining arguments passed on stack. |
| 1369 int original_stack = get_register(sp); |
| 1370 // Compute position of stack on entry to generated code. |
| 1371 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) |
| 1372 - argsSlotsSize ); |
| 1373 if (OS::ActivationFrameAlignment() != 0) { |
| 1374 entry_stack &= -OS::ActivationFrameAlignment(); |
| 1375 } |
| 1376 // Store remaining arguments on stack, from low to high memory. |
| 1377 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); |
| 1378 for (int i = 4; i < argument_count; i++) { |
| 1379 stack_argument[i - 4 + argsSlotsNum] = va_arg(parameters, int32_t); |
| 1380 } |
| 1381 va_end(parameters); |
| 1382 set_register(sp, entry_stack); |
| 1383 |
| 1384 // Prepare to execute the code at entry |
| 1385 set_register(pc, reinterpret_cast<int32_t>(entry)); |
| 1386 // Put down marker for end of simulation. The simulator will stop simulation |
| 1387 // when the PC reaches this value. By saving the "end simulation" value into |
| 1388 // the LR the simulation stops when returning to this call point. |
| 1389 set_register(ra, end_sim_pc); |
| 1390 |
| 1391 // Remember the values of callee-saved registers. |
| 1392 // The code below assumes that r9 is not used as sb (static base) in |
| 1393 // simulator code and therefore is regarded as a callee-saved register. |
| 1394 int32_t s0_val = get_register(s0); |
| 1395 int32_t s1_val = get_register(s1); |
| 1396 int32_t s2_val = get_register(s2); |
| 1397 int32_t s3_val = get_register(s3); |
| 1398 int32_t s4_val = get_register(s4); |
| 1399 int32_t s5_val = get_register(s5); |
| 1400 int32_t s6_val = get_register(s6); |
| 1401 int32_t s7_val = get_register(s7); |
| 1402 int32_t gp_val = get_register(gp); |
| 1403 int32_t sp_val = get_register(sp); |
| 1404 int32_t fp_val = get_register(fp); |
| 1405 |
| 1406 // Setup the callee-saved registers with a known value. To be able to check |
| 1407 // that they are preserved properly across JS execution. |
| 1408 int32_t callee_saved_value = icount_; |
| 1409 set_register(s0, callee_saved_value); |
| 1410 set_register(s1, callee_saved_value); |
| 1411 set_register(s2, callee_saved_value); |
| 1412 set_register(s3, callee_saved_value); |
| 1413 set_register(s4, callee_saved_value); |
| 1414 set_register(s5, callee_saved_value); |
| 1415 set_register(s6, callee_saved_value); |
| 1416 set_register(s7, callee_saved_value); |
| 1417 set_register(gp, callee_saved_value); |
| 1418 set_register(fp, callee_saved_value); |
| 1419 |
| 1420 // Start the simulation |
| 1421 Execute(); |
| 1422 |
| 1423 // // Check that the callee-saved registers have been preserved. |
| 1424 CHECK_EQ(callee_saved_value, get_register(s0)); |
| 1425 CHECK_EQ(callee_saved_value, get_register(s1)); |
| 1426 CHECK_EQ(callee_saved_value, get_register(s2)); |
| 1427 CHECK_EQ(callee_saved_value, get_register(s3)); |
| 1428 CHECK_EQ(callee_saved_value, get_register(s4)); |
| 1429 CHECK_EQ(callee_saved_value, get_register(s5)); |
| 1430 CHECK_EQ(callee_saved_value, get_register(s6)); |
| 1431 CHECK_EQ(callee_saved_value, get_register(s7)); |
| 1432 CHECK_EQ(callee_saved_value, get_register(gp)); |
| 1433 CHECK_EQ(callee_saved_value, get_register(fp)); |
| 1434 |
| 1435 // Restore callee-saved registers with the original value. |
| 1436 set_register(s0, s0_val); |
| 1437 set_register(s1, s1_val); |
| 1438 set_register(s2, s2_val); |
| 1439 set_register(s3, s3_val); |
| 1440 set_register(s4, s4_val); |
| 1441 set_register(s5, s5_val); |
| 1442 set_register(s6, s6_val); |
| 1443 set_register(s7, s7_val); |
| 1444 set_register(gp, gp_val); |
| 1445 set_register(sp, sp_val); |
| 1446 set_register(fp, fp_val); |
| 1447 |
| 1448 // Pop stack passed arguments. |
| 1449 CHECK_EQ(entry_stack, get_register(sp)); |
| 1450 set_register(sp, original_stack); |
| 1451 |
| 1452 int32_t result = get_register(v0); |
| 1453 return result; |
| 1454 } |
| 1455 |
| 1456 } } // namespace assembler::mips |
| 1457 |
| 1458 #endif // !defined(__mips) |
| OLD | NEW |