OLD | NEW |
(Empty) | |
| 1 // Copyright 2008 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 |
| 30 #include "v8.h" |
| 31 |
| 32 #include "disasm.h" |
| 33 #include "arm/constants-arm.h" |
| 34 #include "arm/simulator-arm.h" |
| 35 |
| 36 #if !defined(__arm__) |
| 37 |
| 38 // Only build the simulator if not compiling for real ARM hardware. |
| 39 namespace assembler { namespace arm { |
| 40 |
| 41 using ::v8::internal::Object; |
| 42 using ::v8::internal::PrintF; |
| 43 using ::v8::internal::OS; |
| 44 using ::v8::internal::ReadLine; |
| 45 using ::v8::internal::DeleteArray; |
| 46 |
| 47 // This macro provides a platform independent use of sscanf. The reason for |
| 48 // SScanF not being implemented in a platform independent was through |
| 49 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time |
| 50 // Library does not provide vsscanf. |
| 51 #define SScanF sscanf // NOLINT |
| 52 |
| 53 // The Debugger class is used by the simulator while debugging simulated ARM |
| 54 // code. |
| 55 class Debugger { |
| 56 public: |
| 57 explicit Debugger(Simulator* sim); |
| 58 ~Debugger(); |
| 59 |
| 60 void Stop(Instr* instr); |
| 61 void Debug(); |
| 62 |
| 63 private: |
| 64 static const instr_t kBreakpointInstr = |
| 65 ((AL << 28) | (7 << 25) | (1 << 24) | break_point); |
| 66 static const instr_t kNopInstr = |
| 67 ((AL << 28) | (13 << 21)); |
| 68 |
| 69 Simulator* sim_; |
| 70 |
| 71 bool GetValue(char* desc, int32_t* value); |
| 72 |
| 73 // Set or delete a breakpoint. Returns true if successful. |
| 74 bool SetBreakpoint(Instr* breakpc); |
| 75 bool DeleteBreakpoint(Instr* breakpc); |
| 76 |
| 77 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 78 // execution to skip past breakpoints when run from the debugger. |
| 79 void UndoBreakpoints(); |
| 80 void RedoBreakpoints(); |
| 81 }; |
| 82 |
| 83 |
| 84 Debugger::Debugger(Simulator* sim) { |
| 85 sim_ = sim; |
| 86 } |
| 87 |
| 88 |
| 89 Debugger::~Debugger() { |
| 90 } |
| 91 |
| 92 |
| 93 |
| 94 #ifdef GENERATED_CODE_COVERAGE |
| 95 static FILE* coverage_log = NULL; |
| 96 |
| 97 |
| 98 static void InitializeCoverage() { |
| 99 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); |
| 100 if (file_name != NULL) { |
| 101 coverage_log = fopen(file_name, "aw+"); |
| 102 } |
| 103 } |
| 104 |
| 105 |
| 106 void Debugger::Stop(Instr* instr) { |
| 107 char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff); |
| 108 if (strlen(str) > 0) { |
| 109 if (coverage_log != NULL) { |
| 110 fprintf(coverage_log, "%s\n", str); |
| 111 fflush(coverage_log); |
| 112 } |
| 113 instr->SetInstructionBits(0xe1a00000); // Overwrite with nop. |
| 114 } |
| 115 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); |
| 116 } |
| 117 |
| 118 #else // ndef GENERATED_CODE_COVERAGE |
| 119 |
| 120 static void InitializeCoverage() { |
| 121 } |
| 122 |
| 123 |
| 124 void Debugger::Stop(Instr* instr) { |
| 125 const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); |
| 126 PrintF("Simulator hit %s\n", str); |
| 127 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); |
| 128 Debug(); |
| 129 } |
| 130 #endif |
| 131 |
| 132 |
| 133 static const char* reg_names[] = { "r0", "r1", "r2", "r3", |
| 134 "r4", "r5", "r6", "r7", |
| 135 "r8", "r9", "r10", "r11", |
| 136 "r12", "r13", "r14", "r15", |
| 137 "pc", "lr", "sp", "ip", |
| 138 "fp", "sl", ""}; |
| 139 |
| 140 static int reg_nums[] = { 0, 1, 2, 3, |
| 141 4, 5, 6, 7, |
| 142 8, 9, 10, 11, |
| 143 12, 13, 14, 15, |
| 144 15, 14, 13, 12, |
| 145 11, 10}; |
| 146 |
| 147 |
| 148 static int RegNameToRegNum(char* name) { |
| 149 int reg = 0; |
| 150 while (*reg_names[reg] != 0) { |
| 151 if (strcmp(reg_names[reg], name) == 0) { |
| 152 return reg_nums[reg]; |
| 153 } |
| 154 reg++; |
| 155 } |
| 156 return -1; |
| 157 } |
| 158 |
| 159 |
| 160 bool Debugger::GetValue(char* desc, int32_t* value) { |
| 161 int regnum = RegNameToRegNum(desc); |
| 162 if (regnum >= 0) { |
| 163 if (regnum == 15) { |
| 164 *value = sim_->get_pc(); |
| 165 } else { |
| 166 *value = sim_->get_register(regnum); |
| 167 } |
| 168 return true; |
| 169 } else { |
| 170 return SScanF(desc, "%i", value) == 1; |
| 171 } |
| 172 return false; |
| 173 } |
| 174 |
| 175 |
| 176 bool Debugger::SetBreakpoint(Instr* breakpc) { |
| 177 // Check if a breakpoint can be set. If not return without any side-effects. |
| 178 if (sim_->break_pc_ != NULL) { |
| 179 return false; |
| 180 } |
| 181 |
| 182 // Set the breakpoint. |
| 183 sim_->break_pc_ = breakpc; |
| 184 sim_->break_instr_ = breakpc->InstructionBits(); |
| 185 // Not setting the breakpoint instruction in the code itself. It will be set |
| 186 // when the debugger shell continues. |
| 187 return true; |
| 188 } |
| 189 |
| 190 |
| 191 bool Debugger::DeleteBreakpoint(Instr* breakpc) { |
| 192 if (sim_->break_pc_ != NULL) { |
| 193 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 194 } |
| 195 |
| 196 sim_->break_pc_ = NULL; |
| 197 sim_->break_instr_ = 0; |
| 198 return true; |
| 199 } |
| 200 |
| 201 |
| 202 void Debugger::UndoBreakpoints() { |
| 203 if (sim_->break_pc_ != NULL) { |
| 204 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 205 } |
| 206 } |
| 207 |
| 208 |
| 209 void Debugger::RedoBreakpoints() { |
| 210 if (sim_->break_pc_ != NULL) { |
| 211 sim_->break_pc_->SetInstructionBits(kBreakpointInstr); |
| 212 } |
| 213 } |
| 214 |
| 215 |
| 216 void Debugger::Debug() { |
| 217 intptr_t last_pc = -1; |
| 218 bool done = false; |
| 219 |
| 220 #define COMMAND_SIZE 63 |
| 221 #define ARG_SIZE 255 |
| 222 |
| 223 #define STR(a) #a |
| 224 #define XSTR(a) STR(a) |
| 225 |
| 226 char cmd[COMMAND_SIZE + 1]; |
| 227 char arg1[ARG_SIZE + 1]; |
| 228 char arg2[ARG_SIZE + 1]; |
| 229 |
| 230 // make sure to have a proper terminating character if reaching the limit |
| 231 cmd[COMMAND_SIZE] = 0; |
| 232 arg1[ARG_SIZE] = 0; |
| 233 arg2[ARG_SIZE] = 0; |
| 234 |
| 235 // Undo all set breakpoints while running in the debugger shell. This will |
| 236 // make them invisible to all commands. |
| 237 UndoBreakpoints(); |
| 238 |
| 239 while (!done) { |
| 240 if (last_pc != sim_->get_pc()) { |
| 241 disasm::NameConverter converter; |
| 242 disasm::Disassembler dasm(converter); |
| 243 // use a reasonably large buffer |
| 244 v8::internal::EmbeddedVector<char, 256> buffer; |
| 245 dasm.InstructionDecode(buffer, |
| 246 reinterpret_cast<byte*>(sim_->get_pc())); |
| 247 PrintF(" 0x%x %s\n", sim_->get_pc(), buffer.start()); |
| 248 last_pc = sim_->get_pc(); |
| 249 } |
| 250 char* line = ReadLine("sim> "); |
| 251 if (line == NULL) { |
| 252 break; |
| 253 } else { |
| 254 // Use sscanf to parse the individual parts of the command line. At the |
| 255 // moment no command expects more than two parameters. |
| 256 int args = SScanF(line, |
| 257 "%" XSTR(COMMAND_SIZE) "s " |
| 258 "%" XSTR(ARG_SIZE) "s " |
| 259 "%" XSTR(ARG_SIZE) "s", |
| 260 cmd, arg1, arg2); |
| 261 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 262 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 263 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 264 // Execute the one instruction we broke at with breakpoints disabled. |
| 265 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 266 // Leave the debugger shell. |
| 267 done = true; |
| 268 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 269 if (args == 2) { |
| 270 int32_t value; |
| 271 if (GetValue(arg1, &value)) { |
| 272 PrintF("%s: %d 0x%x\n", arg1, value, value); |
| 273 } else { |
| 274 PrintF("%s unrecognized\n", arg1); |
| 275 } |
| 276 } else { |
| 277 PrintF("print value\n"); |
| 278 } |
| 279 } else if ((strcmp(cmd, "po") == 0) |
| 280 || (strcmp(cmd, "printobject") == 0)) { |
| 281 if (args == 2) { |
| 282 int32_t value; |
| 283 if (GetValue(arg1, &value)) { |
| 284 Object* obj = reinterpret_cast<Object*>(value); |
| 285 USE(obj); |
| 286 PrintF("%s: \n", arg1); |
| 287 #if defined(DEBUG) |
| 288 obj->PrintLn(); |
| 289 #endif // defined(DEBUG) |
| 290 } else { |
| 291 PrintF("%s unrecognized\n", arg1); |
| 292 } |
| 293 } else { |
| 294 PrintF("printobject value\n"); |
| 295 } |
| 296 } else if (strcmp(cmd, "disasm") == 0) { |
| 297 disasm::NameConverter converter; |
| 298 disasm::Disassembler dasm(converter); |
| 299 // use a reasonably large buffer |
| 300 v8::internal::EmbeddedVector<char, 256> buffer; |
| 301 |
| 302 byte* cur = NULL; |
| 303 byte* end = NULL; |
| 304 |
| 305 if (args == 1) { |
| 306 cur = reinterpret_cast<byte*>(sim_->get_pc()); |
| 307 end = cur + (10 * Instr::kInstrSize); |
| 308 } else if (args == 2) { |
| 309 int32_t value; |
| 310 if (GetValue(arg1, &value)) { |
| 311 cur = reinterpret_cast<byte*>(value); |
| 312 // no length parameter passed, assume 10 instructions |
| 313 end = cur + (10 * Instr::kInstrSize); |
| 314 } |
| 315 } else { |
| 316 int32_t value1; |
| 317 int32_t value2; |
| 318 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { |
| 319 cur = reinterpret_cast<byte*>(value1); |
| 320 end = cur + (value2 * Instr::kInstrSize); |
| 321 } |
| 322 } |
| 323 |
| 324 while (cur < end) { |
| 325 dasm.InstructionDecode(buffer, cur); |
| 326 PrintF(" 0x%x %s\n", cur, buffer.start()); |
| 327 cur += Instr::kInstrSize; |
| 328 } |
| 329 } else if (strcmp(cmd, "gdb") == 0) { |
| 330 PrintF("relinquishing control to gdb\n"); |
| 331 v8::internal::OS::DebugBreak(); |
| 332 PrintF("regaining control from gdb\n"); |
| 333 } else if (strcmp(cmd, "break") == 0) { |
| 334 if (args == 2) { |
| 335 int32_t value; |
| 336 if (GetValue(arg1, &value)) { |
| 337 if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) { |
| 338 PrintF("setting breakpoint failed\n"); |
| 339 } |
| 340 } else { |
| 341 PrintF("%s unrecognized\n", arg1); |
| 342 } |
| 343 } else { |
| 344 PrintF("break addr\n"); |
| 345 } |
| 346 } else if (strcmp(cmd, "del") == 0) { |
| 347 if (!DeleteBreakpoint(NULL)) { |
| 348 PrintF("deleting breakpoint failed\n"); |
| 349 } |
| 350 } else if (strcmp(cmd, "flags") == 0) { |
| 351 PrintF("N flag: %d; ", sim_->n_flag_); |
| 352 PrintF("Z flag: %d; ", sim_->z_flag_); |
| 353 PrintF("C flag: %d; ", sim_->c_flag_); |
| 354 PrintF("V flag: %d\n", sim_->v_flag_); |
| 355 } else if (strcmp(cmd, "unstop") == 0) { |
| 356 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
| 357 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
| 358 if (stop_instr->ConditionField() == special_condition) { |
| 359 stop_instr->SetInstructionBits(kNopInstr); |
| 360 } else { |
| 361 PrintF("Not at debugger stop."); |
| 362 } |
| 363 } else { |
| 364 PrintF("Unknown command: %s\n", cmd); |
| 365 } |
| 366 } |
| 367 DeleteArray(line); |
| 368 } |
| 369 |
| 370 // Add all the breakpoints back to stop execution and enter the debugger |
| 371 // shell when hit. |
| 372 RedoBreakpoints(); |
| 373 |
| 374 #undef COMMAND_SIZE |
| 375 #undef ARG_SIZE |
| 376 |
| 377 #undef STR |
| 378 #undef XSTR |
| 379 } |
| 380 |
| 381 |
| 382 Simulator::Simulator() { |
| 383 // Setup simulator support first. Some of this information is needed to |
| 384 // setup the architecture state. |
| 385 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
| 386 stack_ = reinterpret_cast<char*>(malloc(stack_size)); |
| 387 pc_modified_ = false; |
| 388 icount_ = 0; |
| 389 break_pc_ = NULL; |
| 390 break_instr_ = 0; |
| 391 |
| 392 // Setup architecture state. |
| 393 // All registers are initialized to zero to start with. |
| 394 for (int i = 0; i < num_registers; i++) { |
| 395 registers_[i] = 0; |
| 396 } |
| 397 n_flag_ = false; |
| 398 z_flag_ = false; |
| 399 c_flag_ = false; |
| 400 v_flag_ = false; |
| 401 |
| 402 // The sp is initialized to point to the bottom (high address) of the |
| 403 // allocated stack area. To be safe in potential stack underflows we leave |
| 404 // some buffer below. |
| 405 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; |
| 406 // The lr and pc are initialized to a known bad value that will cause an |
| 407 // access violation if the simulator ever tries to execute it. |
| 408 registers_[pc] = bad_lr; |
| 409 registers_[lr] = bad_lr; |
| 410 InitializeCoverage(); |
| 411 } |
| 412 |
| 413 |
| 414 // Create one simulator per thread and keep it in thread local storage. |
| 415 static v8::internal::Thread::LocalStorageKey simulator_key = |
| 416 v8::internal::Thread::CreateThreadLocalKey(); |
| 417 |
| 418 // Get the active Simulator for the current thread. |
| 419 Simulator* Simulator::current() { |
| 420 Simulator* sim = reinterpret_cast<Simulator*>( |
| 421 v8::internal::Thread::GetThreadLocal(simulator_key)); |
| 422 if (sim == NULL) { |
| 423 // TODO(146): delete the simulator object when a thread goes away. |
| 424 sim = new Simulator(); |
| 425 v8::internal::Thread::SetThreadLocal(simulator_key, sim); |
| 426 } |
| 427 return sim; |
| 428 } |
| 429 |
| 430 |
| 431 // Sets the register in the architecture state. It will also deal with updating |
| 432 // Simulator internal state for special registers such as PC. |
| 433 void Simulator::set_register(int reg, int32_t value) { |
| 434 ASSERT((reg >= 0) && (reg < num_registers)); |
| 435 if (reg == pc) { |
| 436 pc_modified_ = true; |
| 437 } |
| 438 registers_[reg] = value; |
| 439 } |
| 440 |
| 441 |
| 442 // Get the register from the architecture state. This function does handle |
| 443 // the special case of accessing the PC register. |
| 444 int32_t Simulator::get_register(int reg) const { |
| 445 ASSERT((reg >= 0) && (reg < num_registers)); |
| 446 return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0); |
| 447 } |
| 448 |
| 449 |
| 450 // Raw access to the PC register. |
| 451 void Simulator::set_pc(int32_t value) { |
| 452 pc_modified_ = true; |
| 453 registers_[pc] = value; |
| 454 } |
| 455 |
| 456 |
| 457 // Raw access to the PC register without the special adjustment when reading. |
| 458 int32_t Simulator::get_pc() const { |
| 459 return registers_[pc]; |
| 460 } |
| 461 |
| 462 |
| 463 // For use in calls that take two double values, constructed from r0, r1, r2 |
| 464 // and r3. |
| 465 void Simulator::GetFpArgs(double* x, double* y) { |
| 466 // We use a char buffer to get around the strict-aliasing rules which |
| 467 // otherwise allow the compiler to optimize away the copy. |
| 468 char buffer[2 * sizeof(registers_[0])]; |
| 469 // Registers 0 and 1 -> x. |
| 470 memcpy(buffer, registers_, sizeof(buffer)); |
| 471 memcpy(x, buffer, sizeof(buffer)); |
| 472 // Registers 2 and 3 -> y. |
| 473 memcpy(buffer, registers_ + 2, sizeof(buffer)); |
| 474 memcpy(y, buffer, sizeof(buffer)); |
| 475 } |
| 476 |
| 477 |
| 478 void Simulator::SetFpResult(const double& result) { |
| 479 char buffer[2 * sizeof(registers_[0])]; |
| 480 memcpy(buffer, &result, sizeof(buffer)); |
| 481 // result -> registers 0 and 1. |
| 482 memcpy(registers_, buffer, sizeof(buffer)); |
| 483 } |
| 484 |
| 485 |
| 486 void Simulator::TrashCallerSaveRegisters() { |
| 487 // We don't trash the registers with the return value. |
| 488 registers_[2] = 0x50Bad4U; |
| 489 registers_[3] = 0x50Bad4U; |
| 490 registers_[12] = 0x50Bad4U; |
| 491 } |
| 492 |
| 493 |
| 494 // The ARM cannot do unaligned reads and writes. On some ARM platforms an |
| 495 // interrupt is caused. On others it does a funky rotation thing. For now we |
| 496 // simply disallow unaligned reads, but at some point we may want to move to |
| 497 // emulating the rotate behaviour. Note that simulator runs have the runtime |
| 498 // system running directly on the host system and only generated code is |
| 499 // executed in the simulator. Since the host is typically IA32 we will not |
| 500 // get the correct ARM-like behaviour on unaligned accesses. |
| 501 |
| 502 int Simulator::ReadW(int32_t addr, Instr* instr) { |
| 503 if ((addr & 3) == 0) { |
| 504 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 505 return *ptr; |
| 506 } |
| 507 PrintF("Unaligned read at %x\n", addr); |
| 508 UNIMPLEMENTED(); |
| 509 return 0; |
| 510 } |
| 511 |
| 512 |
| 513 void Simulator::WriteW(int32_t addr, int value, Instr* instr) { |
| 514 if ((addr & 3) == 0) { |
| 515 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 516 *ptr = value; |
| 517 return; |
| 518 } |
| 519 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); |
| 520 UNIMPLEMENTED(); |
| 521 } |
| 522 |
| 523 |
| 524 uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) { |
| 525 if ((addr & 1) == 0) { |
| 526 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 527 return *ptr; |
| 528 } |
| 529 PrintF("Unaligned read at %x, pc=%p\n", addr, instr); |
| 530 UNIMPLEMENTED(); |
| 531 return 0; |
| 532 } |
| 533 |
| 534 |
| 535 int16_t Simulator::ReadH(int32_t addr, Instr* instr) { |
| 536 if ((addr & 1) == 0) { |
| 537 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 538 return *ptr; |
| 539 } |
| 540 PrintF("Unaligned read at %x\n", addr); |
| 541 UNIMPLEMENTED(); |
| 542 return 0; |
| 543 } |
| 544 |
| 545 |
| 546 void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) { |
| 547 if ((addr & 1) == 0) { |
| 548 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 549 *ptr = value; |
| 550 return; |
| 551 } |
| 552 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); |
| 553 UNIMPLEMENTED(); |
| 554 } |
| 555 |
| 556 |
| 557 void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) { |
| 558 if ((addr & 1) == 0) { |
| 559 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 560 *ptr = value; |
| 561 return; |
| 562 } |
| 563 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); |
| 564 UNIMPLEMENTED(); |
| 565 } |
| 566 |
| 567 |
| 568 uint8_t Simulator::ReadBU(int32_t addr) { |
| 569 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 570 return *ptr; |
| 571 } |
| 572 |
| 573 |
| 574 int8_t Simulator::ReadB(int32_t addr) { |
| 575 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 576 return *ptr; |
| 577 } |
| 578 |
| 579 |
| 580 void Simulator::WriteB(int32_t addr, uint8_t value) { |
| 581 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 582 *ptr = value; |
| 583 } |
| 584 |
| 585 |
| 586 void Simulator::WriteB(int32_t addr, int8_t value) { |
| 587 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 588 *ptr = value; |
| 589 } |
| 590 |
| 591 |
| 592 // Returns the limit of the stack area to enable checking for stack overflows. |
| 593 uintptr_t Simulator::StackLimit() const { |
| 594 // Leave a safety margin of 256 bytes to prevent overrunning the stack when |
| 595 // pushing values. |
| 596 return reinterpret_cast<uintptr_t>(stack_) + 256; |
| 597 } |
| 598 |
| 599 |
| 600 // Unsupported instructions use Format to print an error and stop execution. |
| 601 void Simulator::Format(Instr* instr, const char* format) { |
| 602 PrintF("Simulator found unsupported instruction:\n 0x%x: %s\n", |
| 603 instr, format); |
| 604 UNIMPLEMENTED(); |
| 605 } |
| 606 |
| 607 |
| 608 // Checks if the current instruction should be executed based on its |
| 609 // condition bits. |
| 610 bool Simulator::ConditionallyExecute(Instr* instr) { |
| 611 switch (instr->ConditionField()) { |
| 612 case EQ: return z_flag_; |
| 613 case NE: return !z_flag_; |
| 614 case CS: return c_flag_; |
| 615 case CC: return !c_flag_; |
| 616 case MI: return n_flag_; |
| 617 case PL: return !n_flag_; |
| 618 case VS: return v_flag_; |
| 619 case VC: return !v_flag_; |
| 620 case HI: return c_flag_ && !z_flag_; |
| 621 case LS: return !c_flag_ || z_flag_; |
| 622 case GE: return n_flag_ == v_flag_; |
| 623 case LT: return n_flag_ != v_flag_; |
| 624 case GT: return !z_flag_ && (n_flag_ == v_flag_); |
| 625 case LE: return z_flag_ || (n_flag_ != v_flag_); |
| 626 case AL: return true; |
| 627 default: UNREACHABLE(); |
| 628 } |
| 629 return false; |
| 630 } |
| 631 |
| 632 |
| 633 // Calculate and set the Negative and Zero flags. |
| 634 void Simulator::SetNZFlags(int32_t val) { |
| 635 n_flag_ = (val < 0); |
| 636 z_flag_ = (val == 0); |
| 637 } |
| 638 |
| 639 |
| 640 // Set the Carry flag. |
| 641 void Simulator::SetCFlag(bool val) { |
| 642 c_flag_ = val; |
| 643 } |
| 644 |
| 645 |
| 646 // Set the oVerflow flag. |
| 647 void Simulator::SetVFlag(bool val) { |
| 648 v_flag_ = val; |
| 649 } |
| 650 |
| 651 |
| 652 // Calculate C flag value for additions. |
| 653 bool Simulator::CarryFrom(int32_t left, int32_t right) { |
| 654 uint32_t uleft = static_cast<uint32_t>(left); |
| 655 uint32_t uright = static_cast<uint32_t>(right); |
| 656 uint32_t urest = 0xffffffffU - uleft; |
| 657 |
| 658 return (uright > urest); |
| 659 } |
| 660 |
| 661 |
| 662 // Calculate C flag value for subtractions. |
| 663 bool Simulator::BorrowFrom(int32_t left, int32_t right) { |
| 664 uint32_t uleft = static_cast<uint32_t>(left); |
| 665 uint32_t uright = static_cast<uint32_t>(right); |
| 666 |
| 667 return (uright > uleft); |
| 668 } |
| 669 |
| 670 |
| 671 // Calculate V flag value for additions and subtractions. |
| 672 bool Simulator::OverflowFrom(int32_t alu_out, |
| 673 int32_t left, int32_t right, bool addition) { |
| 674 bool overflow; |
| 675 if (addition) { |
| 676 // operands have the same sign |
| 677 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) |
| 678 // and operands and result have different sign |
| 679 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 680 } else { |
| 681 // operands have different signs |
| 682 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) |
| 683 // and first operand and result have different signs |
| 684 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 685 } |
| 686 return overflow; |
| 687 } |
| 688 |
| 689 |
| 690 // Addressing Mode 1 - Data-processing operands: |
| 691 // Get the value based on the shifter_operand with register. |
| 692 int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { |
| 693 Shift shift = instr->ShiftField(); |
| 694 int shift_amount = instr->ShiftAmountField(); |
| 695 int32_t result = get_register(instr->RmField()); |
| 696 if (instr->Bit(4) == 0) { |
| 697 // by immediate |
| 698 if ((shift == ROR) && (shift_amount == 0)) { |
| 699 UNIMPLEMENTED(); |
| 700 return result; |
| 701 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { |
| 702 shift_amount = 32; |
| 703 } |
| 704 switch (shift) { |
| 705 case ASR: { |
| 706 if (shift_amount == 0) { |
| 707 if (result < 0) { |
| 708 result = 0xffffffff; |
| 709 *carry_out = true; |
| 710 } else { |
| 711 result = 0; |
| 712 *carry_out = false; |
| 713 } |
| 714 } else { |
| 715 result >>= (shift_amount - 1); |
| 716 *carry_out = (result & 1) == 1; |
| 717 result >>= 1; |
| 718 } |
| 719 break; |
| 720 } |
| 721 |
| 722 case LSL: { |
| 723 if (shift_amount == 0) { |
| 724 *carry_out = c_flag_; |
| 725 } else { |
| 726 result <<= (shift_amount - 1); |
| 727 *carry_out = (result < 0); |
| 728 result <<= 1; |
| 729 } |
| 730 break; |
| 731 } |
| 732 |
| 733 case LSR: { |
| 734 if (shift_amount == 0) { |
| 735 result = 0; |
| 736 *carry_out = c_flag_; |
| 737 } else { |
| 738 uint32_t uresult = static_cast<uint32_t>(result); |
| 739 uresult >>= (shift_amount - 1); |
| 740 *carry_out = (uresult & 1) == 1; |
| 741 uresult >>= 1; |
| 742 result = static_cast<int32_t>(uresult); |
| 743 } |
| 744 break; |
| 745 } |
| 746 |
| 747 case ROR: { |
| 748 UNIMPLEMENTED(); |
| 749 break; |
| 750 } |
| 751 |
| 752 default: { |
| 753 UNREACHABLE(); |
| 754 break; |
| 755 } |
| 756 } |
| 757 } else { |
| 758 // by register |
| 759 int rs = instr->RsField(); |
| 760 shift_amount = get_register(rs) &0xff; |
| 761 switch (shift) { |
| 762 case ASR: { |
| 763 if (shift_amount == 0) { |
| 764 *carry_out = c_flag_; |
| 765 } else if (shift_amount < 32) { |
| 766 result >>= (shift_amount - 1); |
| 767 *carry_out = (result & 1) == 1; |
| 768 result >>= 1; |
| 769 } else { |
| 770 ASSERT(shift_amount >= 32); |
| 771 if (result < 0) { |
| 772 *carry_out = true; |
| 773 result = 0xffffffff; |
| 774 } else { |
| 775 *carry_out = false; |
| 776 result = 0; |
| 777 } |
| 778 } |
| 779 break; |
| 780 } |
| 781 |
| 782 case LSL: { |
| 783 if (shift_amount == 0) { |
| 784 *carry_out = c_flag_; |
| 785 } else if (shift_amount < 32) { |
| 786 result <<= (shift_amount - 1); |
| 787 *carry_out = (result < 0); |
| 788 result <<= 1; |
| 789 } else if (shift_amount == 32) { |
| 790 *carry_out = (result & 1) == 1; |
| 791 result = 0; |
| 792 } else { |
| 793 ASSERT(shift_amount > 32); |
| 794 *carry_out = false; |
| 795 result = 0; |
| 796 } |
| 797 break; |
| 798 } |
| 799 |
| 800 case LSR: { |
| 801 if (shift_amount == 0) { |
| 802 *carry_out = c_flag_; |
| 803 } else if (shift_amount < 32) { |
| 804 uint32_t uresult = static_cast<uint32_t>(result); |
| 805 uresult >>= (shift_amount - 1); |
| 806 *carry_out = (uresult & 1) == 1; |
| 807 uresult >>= 1; |
| 808 result = static_cast<int32_t>(uresult); |
| 809 } else if (shift_amount == 32) { |
| 810 *carry_out = (result < 0); |
| 811 result = 0; |
| 812 } else { |
| 813 *carry_out = false; |
| 814 result = 0; |
| 815 } |
| 816 break; |
| 817 } |
| 818 |
| 819 case ROR: { |
| 820 UNIMPLEMENTED(); |
| 821 break; |
| 822 } |
| 823 |
| 824 default: { |
| 825 UNREACHABLE(); |
| 826 break; |
| 827 } |
| 828 } |
| 829 } |
| 830 return result; |
| 831 } |
| 832 |
| 833 |
| 834 // Addressing Mode 1 - Data-processing operands: |
| 835 // Get the value based on the shifter_operand with immediate. |
| 836 int32_t Simulator::GetImm(Instr* instr, bool* carry_out) { |
| 837 int rotate = instr->RotateField() * 2; |
| 838 int immed8 = instr->Immed8Field(); |
| 839 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); |
| 840 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0); |
| 841 return imm; |
| 842 } |
| 843 |
| 844 |
| 845 static int count_bits(int bit_vector) { |
| 846 int count = 0; |
| 847 while (bit_vector != 0) { |
| 848 if ((bit_vector & 1) != 0) { |
| 849 count++; |
| 850 } |
| 851 bit_vector >>= 1; |
| 852 } |
| 853 return count; |
| 854 } |
| 855 |
| 856 |
| 857 // Addressing Mode 4 - Load and Store Multiple |
| 858 void Simulator::HandleRList(Instr* instr, bool load) { |
| 859 int rn = instr->RnField(); |
| 860 int32_t rn_val = get_register(rn); |
| 861 int rlist = instr->RlistField(); |
| 862 int num_regs = count_bits(rlist); |
| 863 |
| 864 intptr_t start_address = 0; |
| 865 intptr_t end_address = 0; |
| 866 switch (instr->PUField()) { |
| 867 case 0: { |
| 868 // Print("da"); |
| 869 UNIMPLEMENTED(); |
| 870 break; |
| 871 } |
| 872 case 1: { |
| 873 // Print("ia"); |
| 874 start_address = rn_val; |
| 875 end_address = rn_val + (num_regs * 4) - 4; |
| 876 rn_val = rn_val + (num_regs * 4); |
| 877 break; |
| 878 } |
| 879 case 2: { |
| 880 // Print("db"); |
| 881 start_address = rn_val - (num_regs * 4); |
| 882 end_address = rn_val - 4; |
| 883 rn_val = start_address; |
| 884 break; |
| 885 } |
| 886 case 3: { |
| 887 // Print("ib"); |
| 888 UNIMPLEMENTED(); |
| 889 break; |
| 890 } |
| 891 default: { |
| 892 UNREACHABLE(); |
| 893 break; |
| 894 } |
| 895 } |
| 896 if (instr->HasW()) { |
| 897 set_register(rn, rn_val); |
| 898 } |
| 899 intptr_t* address = reinterpret_cast<intptr_t*>(start_address); |
| 900 int reg = 0; |
| 901 while (rlist != 0) { |
| 902 if ((rlist & 1) != 0) { |
| 903 if (load) { |
| 904 set_register(reg, *address); |
| 905 } else { |
| 906 *address = get_register(reg); |
| 907 } |
| 908 address += 1; |
| 909 } |
| 910 reg++; |
| 911 rlist >>= 1; |
| 912 } |
| 913 ASSERT(end_address == ((intptr_t)address) - 4); |
| 914 } |
| 915 |
| 916 |
| 917 // Calls into the V8 runtime are based on this very simple interface. |
| 918 // Note: To be able to return two values from some calls the code in runtime.cc |
| 919 // uses the ObjectPair which is essentially two 32-bit values stuffed into a |
| 920 // 64-bit value. With the code below we assume that all runtime calls return |
| 921 // 64 bits of result. If they don't, the r1 result register contains a bogus |
| 922 // value, which is fine because it is caller-saved. |
| 923 typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); |
| 924 |
| 925 |
| 926 // Software interrupt instructions are used by the simulator to call into the |
| 927 // C-based V8 runtime. |
| 928 void Simulator::SoftwareInterrupt(Instr* instr) { |
| 929 int swi = instr->SwiField(); |
| 930 switch (swi) { |
| 931 case call_rt_r5: { |
| 932 SimulatorRuntimeCall target = |
| 933 reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); |
| 934 intptr_t arg0 = get_register(r0); |
| 935 intptr_t arg1 = get_register(r1); |
| 936 int64_t result = target(arg0, arg1); |
| 937 int32_t lo_res = static_cast<int32_t>(result); |
| 938 int32_t hi_res = static_cast<int32_t>(result >> 32); |
| 939 set_register(r0, lo_res); |
| 940 set_register(r1, hi_res); |
| 941 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 942 break; |
| 943 } |
| 944 case call_rt_r2: { |
| 945 SimulatorRuntimeCall target = |
| 946 reinterpret_cast<SimulatorRuntimeCall>(get_register(r2)); |
| 947 intptr_t arg0 = get_register(r0); |
| 948 intptr_t arg1 = get_register(r1); |
| 949 int64_t result = target(arg0, arg1); |
| 950 int32_t lo_res = static_cast<int32_t>(result); |
| 951 int32_t hi_res = static_cast<int32_t>(result >> 32); |
| 952 set_register(r0, lo_res); |
| 953 set_register(r1, hi_res); |
| 954 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 955 break; |
| 956 } |
| 957 case break_point: { |
| 958 Debugger dbg(this); |
| 959 dbg.Debug(); |
| 960 break; |
| 961 } |
| 962 { |
| 963 double x, y, z; |
| 964 case simulator_fp_add: |
| 965 GetFpArgs(&x, &y); |
| 966 z = x + y; |
| 967 SetFpResult(z); |
| 968 TrashCallerSaveRegisters(); |
| 969 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 970 break; |
| 971 case simulator_fp_sub: |
| 972 GetFpArgs(&x, &y); |
| 973 z = x - y; |
| 974 SetFpResult(z); |
| 975 TrashCallerSaveRegisters(); |
| 976 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 977 break; |
| 978 case simulator_fp_mul: |
| 979 GetFpArgs(&x, &y); |
| 980 z = x * y; |
| 981 SetFpResult(z); |
| 982 TrashCallerSaveRegisters(); |
| 983 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 984 break; |
| 985 } |
| 986 default: { |
| 987 UNREACHABLE(); |
| 988 break; |
| 989 } |
| 990 } |
| 991 } |
| 992 |
| 993 |
| 994 // Handle execution based on instruction types. |
| 995 |
| 996 // Instruction types 0 and 1 are both rolled into one function because they |
| 997 // only differ in the handling of the shifter_operand. |
| 998 void Simulator::DecodeType01(Instr* instr) { |
| 999 int type = instr->TypeField(); |
| 1000 if ((type == 0) && instr->IsSpecialType0()) { |
| 1001 // multiply instruction or extra loads and stores |
| 1002 if (instr->Bits(7, 4) == 9) { |
| 1003 if (instr->Bit(24) == 0) { |
| 1004 // multiply instructions |
| 1005 int rd = instr->RdField(); |
| 1006 int rm = instr->RmField(); |
| 1007 int rs = instr->RsField(); |
| 1008 int32_t rs_val = get_register(rs); |
| 1009 int32_t rm_val = get_register(rm); |
| 1010 if (instr->Bit(23) == 0) { |
| 1011 if (instr->Bit(21) == 0) { |
| 1012 // Format(instr, "mul'cond's 'rd, 'rm, 'rs"); |
| 1013 int32_t alu_out = rm_val * rs_val; |
| 1014 set_register(rd, alu_out); |
| 1015 if (instr->HasS()) { |
| 1016 SetNZFlags(alu_out); |
| 1017 } |
| 1018 } else { |
| 1019 Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn"); |
| 1020 } |
| 1021 } else { |
| 1022 // Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm"); |
| 1023 int rn = instr->RnField(); |
| 1024 int32_t hi_res = 0; |
| 1025 int32_t lo_res = 0; |
| 1026 if (instr->Bit(22) == 0) { |
| 1027 // signed multiply |
| 1028 UNIMPLEMENTED(); |
| 1029 } else { |
| 1030 // unsigned multiply |
| 1031 uint64_t left_op = rm_val; |
| 1032 uint64_t right_op = rs_val; |
| 1033 uint64_t result = left_op * right_op; |
| 1034 hi_res = static_cast<int32_t>(result >> 32); |
| 1035 lo_res = static_cast<int32_t>(result & 0xffffffff); |
| 1036 } |
| 1037 set_register(rn, hi_res); |
| 1038 set_register(rd, lo_res); |
| 1039 if (instr->HasS()) { |
| 1040 UNIMPLEMENTED(); |
| 1041 } |
| 1042 } |
| 1043 } else { |
| 1044 UNIMPLEMENTED(); // not used by V8 |
| 1045 } |
| 1046 } else { |
| 1047 // extra load/store instructions |
| 1048 int rd = instr->RdField(); |
| 1049 int rn = instr->RnField(); |
| 1050 int32_t rn_val = get_register(rn); |
| 1051 int32_t addr = 0; |
| 1052 if (instr->Bit(22) == 0) { |
| 1053 int rm = instr->RmField(); |
| 1054 int32_t rm_val = get_register(rm); |
| 1055 switch (instr->PUField()) { |
| 1056 case 0: { |
| 1057 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); |
| 1058 ASSERT(!instr->HasW()); |
| 1059 addr = rn_val; |
| 1060 rn_val -= rm_val; |
| 1061 set_register(rn, rn_val); |
| 1062 break; |
| 1063 } |
| 1064 case 1: { |
| 1065 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); |
| 1066 ASSERT(!instr->HasW()); |
| 1067 addr = rn_val; |
| 1068 rn_val += rm_val; |
| 1069 set_register(rn, rn_val); |
| 1070 break; |
| 1071 } |
| 1072 case 2: { |
| 1073 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); |
| 1074 rn_val -= rm_val; |
| 1075 addr = rn_val; |
| 1076 if (instr->HasW()) { |
| 1077 set_register(rn, rn_val); |
| 1078 } |
| 1079 break; |
| 1080 } |
| 1081 case 3: { |
| 1082 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); |
| 1083 rn_val += rm_val; |
| 1084 addr = rn_val; |
| 1085 if (instr->HasW()) { |
| 1086 set_register(rn, rn_val); |
| 1087 } |
| 1088 break; |
| 1089 } |
| 1090 default: { |
| 1091 // The PU field is a 2-bit field. |
| 1092 UNREACHABLE(); |
| 1093 break; |
| 1094 } |
| 1095 } |
| 1096 } else { |
| 1097 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
| 1098 switch (instr->PUField()) { |
| 1099 case 0: { |
| 1100 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8"); |
| 1101 ASSERT(!instr->HasW()); |
| 1102 addr = rn_val; |
| 1103 rn_val -= imm_val; |
| 1104 set_register(rn, rn_val); |
| 1105 break; |
| 1106 } |
| 1107 case 1: { |
| 1108 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8"); |
| 1109 ASSERT(!instr->HasW()); |
| 1110 addr = rn_val; |
| 1111 rn_val += imm_val; |
| 1112 set_register(rn, rn_val); |
| 1113 break; |
| 1114 } |
| 1115 case 2: { |
| 1116 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w"); |
| 1117 rn_val -= imm_val; |
| 1118 addr = rn_val; |
| 1119 if (instr->HasW()) { |
| 1120 set_register(rn, rn_val); |
| 1121 } |
| 1122 break; |
| 1123 } |
| 1124 case 3: { |
| 1125 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w"); |
| 1126 rn_val += imm_val; |
| 1127 addr = rn_val; |
| 1128 if (instr->HasW()) { |
| 1129 set_register(rn, rn_val); |
| 1130 } |
| 1131 break; |
| 1132 } |
| 1133 default: { |
| 1134 // The PU field is a 2-bit field. |
| 1135 UNREACHABLE(); |
| 1136 break; |
| 1137 } |
| 1138 } |
| 1139 } |
| 1140 if (instr->HasH()) { |
| 1141 if (instr->HasSign()) { |
| 1142 if (instr->HasL()) { |
| 1143 int16_t val = ReadH(addr, instr); |
| 1144 set_register(rd, val); |
| 1145 } else { |
| 1146 int16_t val = get_register(rd); |
| 1147 WriteH(addr, val, instr); |
| 1148 } |
| 1149 } else { |
| 1150 if (instr->HasL()) { |
| 1151 uint16_t val = ReadHU(addr, instr); |
| 1152 set_register(rd, val); |
| 1153 } else { |
| 1154 uint16_t val = get_register(rd); |
| 1155 WriteH(addr, val, instr); |
| 1156 } |
| 1157 } |
| 1158 } else { |
| 1159 // signed byte loads |
| 1160 ASSERT(instr->HasSign()); |
| 1161 ASSERT(instr->HasL()); |
| 1162 int8_t val = ReadB(addr); |
| 1163 set_register(rd, val); |
| 1164 } |
| 1165 return; |
| 1166 } |
| 1167 } else { |
| 1168 int rd = instr->RdField(); |
| 1169 int rn = instr->RnField(); |
| 1170 int32_t rn_val = get_register(rn); |
| 1171 int32_t shifter_operand = 0; |
| 1172 bool shifter_carry_out = 0; |
| 1173 if (type == 0) { |
| 1174 shifter_operand = GetShiftRm(instr, &shifter_carry_out); |
| 1175 } else { |
| 1176 ASSERT(instr->TypeField() == 1); |
| 1177 shifter_operand = GetImm(instr, &shifter_carry_out); |
| 1178 } |
| 1179 int32_t alu_out; |
| 1180 |
| 1181 switch (instr->OpcodeField()) { |
| 1182 case AND: { |
| 1183 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm"); |
| 1184 // Format(instr, "and'cond's 'rd, 'rn, 'imm"); |
| 1185 alu_out = rn_val & shifter_operand; |
| 1186 set_register(rd, alu_out); |
| 1187 if (instr->HasS()) { |
| 1188 SetNZFlags(alu_out); |
| 1189 SetCFlag(shifter_carry_out); |
| 1190 } |
| 1191 break; |
| 1192 } |
| 1193 |
| 1194 case EOR: { |
| 1195 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm"); |
| 1196 // Format(instr, "eor'cond's 'rd, 'rn, 'imm"); |
| 1197 alu_out = rn_val ^ shifter_operand; |
| 1198 set_register(rd, alu_out); |
| 1199 if (instr->HasS()) { |
| 1200 SetNZFlags(alu_out); |
| 1201 SetCFlag(shifter_carry_out); |
| 1202 } |
| 1203 break; |
| 1204 } |
| 1205 |
| 1206 case SUB: { |
| 1207 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm"); |
| 1208 // Format(instr, "sub'cond's 'rd, 'rn, 'imm"); |
| 1209 alu_out = rn_val - shifter_operand; |
| 1210 set_register(rd, alu_out); |
| 1211 if (instr->HasS()) { |
| 1212 SetNZFlags(alu_out); |
| 1213 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); |
| 1214 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); |
| 1215 } |
| 1216 break; |
| 1217 } |
| 1218 |
| 1219 case RSB: { |
| 1220 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm"); |
| 1221 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm"); |
| 1222 alu_out = shifter_operand - rn_val; |
| 1223 set_register(rd, alu_out); |
| 1224 if (instr->HasS()) { |
| 1225 SetNZFlags(alu_out); |
| 1226 SetCFlag(!BorrowFrom(shifter_operand, rn_val)); |
| 1227 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false)); |
| 1228 } |
| 1229 break; |
| 1230 } |
| 1231 |
| 1232 case ADD: { |
| 1233 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm"); |
| 1234 // Format(instr, "add'cond's 'rd, 'rn, 'imm"); |
| 1235 alu_out = rn_val + shifter_operand; |
| 1236 set_register(rd, alu_out); |
| 1237 if (instr->HasS()) { |
| 1238 SetNZFlags(alu_out); |
| 1239 SetCFlag(CarryFrom(rn_val, shifter_operand)); |
| 1240 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true)); |
| 1241 } |
| 1242 break; |
| 1243 } |
| 1244 |
| 1245 case ADC: { |
| 1246 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm"); |
| 1247 Format(instr, "adc'cond's 'rd, 'rn, 'imm"); |
| 1248 break; |
| 1249 } |
| 1250 |
| 1251 case SBC: { |
| 1252 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm"); |
| 1253 Format(instr, "sbc'cond's 'rd, 'rn, 'imm"); |
| 1254 break; |
| 1255 } |
| 1256 |
| 1257 case RSC: { |
| 1258 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm"); |
| 1259 Format(instr, "rsc'cond's 'rd, 'rn, 'imm"); |
| 1260 break; |
| 1261 } |
| 1262 |
| 1263 case TST: { |
| 1264 if (instr->HasS()) { |
| 1265 // Format(instr, "tst'cond 'rn, 'shift_rm"); |
| 1266 // Format(instr, "tst'cond 'rn, 'imm"); |
| 1267 alu_out = rn_val & shifter_operand; |
| 1268 SetNZFlags(alu_out); |
| 1269 SetCFlag(shifter_carry_out); |
| 1270 } else { |
| 1271 UNIMPLEMENTED(); |
| 1272 } |
| 1273 break; |
| 1274 } |
| 1275 |
| 1276 case TEQ: { |
| 1277 if (instr->HasS()) { |
| 1278 // Format(instr, "teq'cond 'rn, 'shift_rm"); |
| 1279 // Format(instr, "teq'cond 'rn, 'imm"); |
| 1280 alu_out = rn_val ^ shifter_operand; |
| 1281 SetNZFlags(alu_out); |
| 1282 SetCFlag(shifter_carry_out); |
| 1283 } else { |
| 1284 UNIMPLEMENTED(); |
| 1285 } |
| 1286 break; |
| 1287 } |
| 1288 |
| 1289 case CMP: { |
| 1290 if (instr->HasS()) { |
| 1291 // Format(instr, "cmp'cond 'rn, 'shift_rm"); |
| 1292 // Format(instr, "cmp'cond 'rn, 'imm"); |
| 1293 alu_out = rn_val - shifter_operand; |
| 1294 SetNZFlags(alu_out); |
| 1295 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); |
| 1296 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); |
| 1297 } else { |
| 1298 UNIMPLEMENTED(); |
| 1299 } |
| 1300 break; |
| 1301 } |
| 1302 |
| 1303 case CMN: { |
| 1304 if (instr->HasS()) { |
| 1305 Format(instr, "cmn'cond 'rn, 'shift_rm"); |
| 1306 Format(instr, "cmn'cond 'rn, 'imm"); |
| 1307 } else { |
| 1308 UNIMPLEMENTED(); |
| 1309 } |
| 1310 break; |
| 1311 } |
| 1312 |
| 1313 case ORR: { |
| 1314 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm"); |
| 1315 // Format(instr, "orr'cond's 'rd, 'rn, 'imm"); |
| 1316 alu_out = rn_val | shifter_operand; |
| 1317 set_register(rd, alu_out); |
| 1318 if (instr->HasS()) { |
| 1319 SetNZFlags(alu_out); |
| 1320 SetCFlag(shifter_carry_out); |
| 1321 } |
| 1322 break; |
| 1323 } |
| 1324 |
| 1325 case MOV: { |
| 1326 // Format(instr, "mov'cond's 'rd, 'shift_rm"); |
| 1327 // Format(instr, "mov'cond's 'rd, 'imm"); |
| 1328 alu_out = shifter_operand; |
| 1329 set_register(rd, alu_out); |
| 1330 if (instr->HasS()) { |
| 1331 SetNZFlags(alu_out); |
| 1332 SetCFlag(shifter_carry_out); |
| 1333 } |
| 1334 break; |
| 1335 } |
| 1336 |
| 1337 case BIC: { |
| 1338 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm"); |
| 1339 // Format(instr, "bic'cond's 'rd, 'rn, 'imm"); |
| 1340 alu_out = rn_val & ~shifter_operand; |
| 1341 set_register(rd, alu_out); |
| 1342 if (instr->HasS()) { |
| 1343 SetNZFlags(alu_out); |
| 1344 SetCFlag(shifter_carry_out); |
| 1345 } |
| 1346 break; |
| 1347 } |
| 1348 |
| 1349 case MVN: { |
| 1350 // Format(instr, "mvn'cond's 'rd, 'shift_rm"); |
| 1351 // Format(instr, "mvn'cond's 'rd, 'imm"); |
| 1352 alu_out = ~shifter_operand; |
| 1353 set_register(rd, alu_out); |
| 1354 if (instr->HasS()) { |
| 1355 SetNZFlags(alu_out); |
| 1356 SetCFlag(shifter_carry_out); |
| 1357 } |
| 1358 break; |
| 1359 } |
| 1360 |
| 1361 default: { |
| 1362 UNREACHABLE(); |
| 1363 break; |
| 1364 } |
| 1365 } |
| 1366 } |
| 1367 } |
| 1368 |
| 1369 |
| 1370 void Simulator::DecodeType2(Instr* instr) { |
| 1371 int rd = instr->RdField(); |
| 1372 int rn = instr->RnField(); |
| 1373 int32_t rn_val = get_register(rn); |
| 1374 int32_t im_val = instr->Offset12Field(); |
| 1375 int32_t addr = 0; |
| 1376 switch (instr->PUField()) { |
| 1377 case 0: { |
| 1378 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); |
| 1379 ASSERT(!instr->HasW()); |
| 1380 addr = rn_val; |
| 1381 rn_val -= im_val; |
| 1382 set_register(rn, rn_val); |
| 1383 break; |
| 1384 } |
| 1385 case 1: { |
| 1386 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); |
| 1387 ASSERT(!instr->HasW()); |
| 1388 addr = rn_val; |
| 1389 rn_val += im_val; |
| 1390 set_register(rn, rn_val); |
| 1391 break; |
| 1392 } |
| 1393 case 2: { |
| 1394 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); |
| 1395 rn_val -= im_val; |
| 1396 addr = rn_val; |
| 1397 if (instr->HasW()) { |
| 1398 set_register(rn, rn_val); |
| 1399 } |
| 1400 break; |
| 1401 } |
| 1402 case 3: { |
| 1403 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); |
| 1404 rn_val += im_val; |
| 1405 addr = rn_val; |
| 1406 if (instr->HasW()) { |
| 1407 set_register(rn, rn_val); |
| 1408 } |
| 1409 break; |
| 1410 } |
| 1411 default: { |
| 1412 UNREACHABLE(); |
| 1413 break; |
| 1414 } |
| 1415 } |
| 1416 if (instr->HasB()) { |
| 1417 if (instr->HasL()) { |
| 1418 byte val = ReadBU(addr); |
| 1419 set_register(rd, val); |
| 1420 } else { |
| 1421 byte val = get_register(rd); |
| 1422 WriteB(addr, val); |
| 1423 } |
| 1424 } else { |
| 1425 if (instr->HasL()) { |
| 1426 set_register(rd, ReadW(addr, instr)); |
| 1427 } else { |
| 1428 WriteW(addr, get_register(rd), instr); |
| 1429 } |
| 1430 } |
| 1431 } |
| 1432 |
| 1433 |
| 1434 void Simulator::DecodeType3(Instr* instr) { |
| 1435 int rd = instr->RdField(); |
| 1436 int rn = instr->RnField(); |
| 1437 int32_t rn_val = get_register(rn); |
| 1438 bool shifter_carry_out = 0; |
| 1439 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out); |
| 1440 int32_t addr = 0; |
| 1441 switch (instr->PUField()) { |
| 1442 case 0: { |
| 1443 ASSERT(!instr->HasW()); |
| 1444 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); |
| 1445 break; |
| 1446 } |
| 1447 case 1: { |
| 1448 ASSERT(!instr->HasW()); |
| 1449 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); |
| 1450 break; |
| 1451 } |
| 1452 case 2: { |
| 1453 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); |
| 1454 addr = rn_val - shifter_operand; |
| 1455 if (instr->HasW()) { |
| 1456 set_register(rn, addr); |
| 1457 } |
| 1458 break; |
| 1459 } |
| 1460 case 3: { |
| 1461 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); |
| 1462 addr = rn_val + shifter_operand; |
| 1463 if (instr->HasW()) { |
| 1464 set_register(rn, addr); |
| 1465 } |
| 1466 break; |
| 1467 } |
| 1468 default: { |
| 1469 UNREACHABLE(); |
| 1470 break; |
| 1471 } |
| 1472 } |
| 1473 if (instr->HasB()) { |
| 1474 UNIMPLEMENTED(); |
| 1475 } else { |
| 1476 if (instr->HasL()) { |
| 1477 set_register(rd, ReadW(addr, instr)); |
| 1478 } else { |
| 1479 WriteW(addr, get_register(rd), instr); |
| 1480 } |
| 1481 } |
| 1482 } |
| 1483 |
| 1484 |
| 1485 void Simulator::DecodeType4(Instr* instr) { |
| 1486 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode |
| 1487 if (instr->HasL()) { |
| 1488 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); |
| 1489 HandleRList(instr, true); |
| 1490 } else { |
| 1491 // Format(instr, "stm'cond'pu 'rn'w, 'rlist"); |
| 1492 HandleRList(instr, false); |
| 1493 } |
| 1494 } |
| 1495 |
| 1496 |
| 1497 void Simulator::DecodeType5(Instr* instr) { |
| 1498 // Format(instr, "b'l'cond 'target"); |
| 1499 int off = (instr->SImmed24Field() << 2) + 8; |
| 1500 intptr_t pc = get_pc(); |
| 1501 if (instr->HasLink()) { |
| 1502 set_register(lr, pc + Instr::kInstrSize); |
| 1503 } |
| 1504 set_pc(pc+off); |
| 1505 } |
| 1506 |
| 1507 |
| 1508 void Simulator::DecodeType6(Instr* instr) { |
| 1509 UNIMPLEMENTED(); |
| 1510 } |
| 1511 |
| 1512 |
| 1513 void Simulator::DecodeType7(Instr* instr) { |
| 1514 if (instr->Bit(24) == 1) { |
| 1515 // Format(instr, "swi 'swi"); |
| 1516 SoftwareInterrupt(instr); |
| 1517 } else { |
| 1518 UNIMPLEMENTED(); |
| 1519 } |
| 1520 } |
| 1521 |
| 1522 |
| 1523 // Executes the current instruction. |
| 1524 void Simulator::InstructionDecode(Instr* instr) { |
| 1525 pc_modified_ = false; |
| 1526 if (instr->ConditionField() == special_condition) { |
| 1527 Debugger dbg(this); |
| 1528 dbg.Stop(instr); |
| 1529 return; |
| 1530 } |
| 1531 if (::v8::internal::FLAG_trace_sim) { |
| 1532 disasm::NameConverter converter; |
| 1533 disasm::Disassembler dasm(converter); |
| 1534 // use a reasonably large buffer |
| 1535 v8::internal::EmbeddedVector<char, 256> buffer; |
| 1536 dasm.InstructionDecode(buffer, |
| 1537 reinterpret_cast<byte*>(instr)); |
| 1538 PrintF(" 0x%x %s\n", instr, buffer.start()); |
| 1539 } |
| 1540 if (ConditionallyExecute(instr)) { |
| 1541 switch (instr->TypeField()) { |
| 1542 case 0: |
| 1543 case 1: { |
| 1544 DecodeType01(instr); |
| 1545 break; |
| 1546 } |
| 1547 case 2: { |
| 1548 DecodeType2(instr); |
| 1549 break; |
| 1550 } |
| 1551 case 3: { |
| 1552 DecodeType3(instr); |
| 1553 break; |
| 1554 } |
| 1555 case 4: { |
| 1556 DecodeType4(instr); |
| 1557 break; |
| 1558 } |
| 1559 case 5: { |
| 1560 DecodeType5(instr); |
| 1561 break; |
| 1562 } |
| 1563 case 6: { |
| 1564 DecodeType6(instr); |
| 1565 break; |
| 1566 } |
| 1567 case 7: { |
| 1568 DecodeType7(instr); |
| 1569 break; |
| 1570 } |
| 1571 default: { |
| 1572 UNIMPLEMENTED(); |
| 1573 break; |
| 1574 } |
| 1575 } |
| 1576 } |
| 1577 if (!pc_modified_) { |
| 1578 set_register(pc, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
| 1579 } |
| 1580 } |
| 1581 |
| 1582 |
| 1583 // |
| 1584 void Simulator::Execute() { |
| 1585 // Get the PC to simulate. Cannot use the accessor here as we need the |
| 1586 // raw PC value and not the one used as input to arithmetic instructions. |
| 1587 int program_counter = get_pc(); |
| 1588 |
| 1589 if (::v8::internal::FLAG_stop_sim_at == 0) { |
| 1590 // Fast version of the dispatch loop without checking whether the simulator |
| 1591 // should be stopping at a particular executed instruction. |
| 1592 while (program_counter != end_sim_pc) { |
| 1593 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 1594 icount_++; |
| 1595 InstructionDecode(instr); |
| 1596 program_counter = get_pc(); |
| 1597 } |
| 1598 } else { |
| 1599 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
| 1600 // we reach the particular instuction count. |
| 1601 while (program_counter != end_sim_pc) { |
| 1602 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 1603 icount_++; |
| 1604 if (icount_ == ::v8::internal::FLAG_stop_sim_at) { |
| 1605 Debugger dbg(this); |
| 1606 dbg.Debug(); |
| 1607 } else { |
| 1608 InstructionDecode(instr); |
| 1609 } |
| 1610 program_counter = get_pc(); |
| 1611 } |
| 1612 } |
| 1613 } |
| 1614 |
| 1615 |
| 1616 Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2, |
| 1617 int32_t p3, int32_t p4) { |
| 1618 // Setup parameters |
| 1619 set_register(r0, p0); |
| 1620 set_register(r1, p1); |
| 1621 set_register(r2, p2); |
| 1622 set_register(r3, p3); |
| 1623 intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp)); |
| 1624 *(--stack_pointer) = p4; |
| 1625 set_register(sp, reinterpret_cast<int32_t>(stack_pointer)); |
| 1626 |
| 1627 // Prepare to execute the code at entry |
| 1628 set_register(pc, entry); |
| 1629 // Put down marker for end of simulation. The simulator will stop simulation |
| 1630 // when the PC reaches this value. By saving the "end simulation" value into |
| 1631 // the LR the simulation stops when returning to this call point. |
| 1632 set_register(lr, end_sim_pc); |
| 1633 |
| 1634 // Remember the values of callee-saved registers. |
| 1635 // The code below assumes that r9 is not used as sb (static base) in |
| 1636 // simulator code and therefore is regarded as a callee-saved register. |
| 1637 int32_t r4_val = get_register(r4); |
| 1638 int32_t r5_val = get_register(r5); |
| 1639 int32_t r6_val = get_register(r6); |
| 1640 int32_t r7_val = get_register(r7); |
| 1641 int32_t r8_val = get_register(r8); |
| 1642 int32_t r9_val = get_register(r9); |
| 1643 int32_t r10_val = get_register(r10); |
| 1644 int32_t r11_val = get_register(r11); |
| 1645 |
| 1646 // Setup the callee-saved registers with a known value. To be able to check |
| 1647 // that they are preserved properly across JS execution. |
| 1648 int32_t callee_saved_value = icount_; |
| 1649 set_register(r4, callee_saved_value); |
| 1650 set_register(r5, callee_saved_value); |
| 1651 set_register(r6, callee_saved_value); |
| 1652 set_register(r7, callee_saved_value); |
| 1653 set_register(r8, callee_saved_value); |
| 1654 set_register(r9, callee_saved_value); |
| 1655 set_register(r10, callee_saved_value); |
| 1656 set_register(r11, callee_saved_value); |
| 1657 |
| 1658 // Start the simulation |
| 1659 Execute(); |
| 1660 |
| 1661 // Check that the callee-saved registers have been preserved. |
| 1662 CHECK_EQ(get_register(r4), callee_saved_value); |
| 1663 CHECK_EQ(get_register(r5), callee_saved_value); |
| 1664 CHECK_EQ(get_register(r6), callee_saved_value); |
| 1665 CHECK_EQ(get_register(r7), callee_saved_value); |
| 1666 CHECK_EQ(get_register(r8), callee_saved_value); |
| 1667 CHECK_EQ(get_register(r9), callee_saved_value); |
| 1668 CHECK_EQ(get_register(r10), callee_saved_value); |
| 1669 CHECK_EQ(get_register(r11), callee_saved_value); |
| 1670 |
| 1671 // Restore callee-saved registers with the original value. |
| 1672 set_register(r4, r4_val); |
| 1673 set_register(r5, r5_val); |
| 1674 set_register(r6, r6_val); |
| 1675 set_register(r7, r7_val); |
| 1676 set_register(r8, r8_val); |
| 1677 set_register(r9, r9_val); |
| 1678 set_register(r10, r10_val); |
| 1679 set_register(r11, r11_val); |
| 1680 |
| 1681 int result = get_register(r0); |
| 1682 return reinterpret_cast<Object*>(result); |
| 1683 } |
| 1684 |
| 1685 } } // namespace assembler::arm |
| 1686 |
| 1687 #endif // !defined(__arm__) |
OLD | NEW |