| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 // Only build the simulator if not compiling for real MIPS hardware. | 8 // Only build the simulator if not compiling for real MIPS hardware. |
| 9 #if !defined(HOST_ARCH_MIPS) | 9 #if !defined(HOST_ARCH_MIPS) |
| 10 | 10 |
| 11 #include "vm/simulator.h" | 11 #include "vm/simulator.h" |
| 12 | 12 |
| 13 #include "vm/assembler.h" | 13 #include "vm/assembler.h" |
| 14 #include "vm/constants_mips.h" | 14 #include "vm/constants_mips.h" |
| 15 #include "vm/disassembler.h" | 15 #include "vm/disassembler.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); | 19 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); |
| 20 | 20 |
| 21 |
| 22 // This macro provides a platform independent use of sscanf. The reason for |
| 23 // SScanF not being implemented in a platform independent way through |
| 24 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 25 // Library does not provide vsscanf. |
| 26 #define SScanF sscanf // NOLINT |
| 27 |
| 28 |
| 29 // The SimulatorDebugger class is used by the simulator while debugging |
| 30 // simulated MIPS code. |
| 31 class SimulatorDebugger { |
| 32 public: |
| 33 explicit SimulatorDebugger(Simulator* sim); |
| 34 ~SimulatorDebugger(); |
| 35 |
| 36 void Stop(Instr* instr, const char* message); |
| 37 void Debug(); |
| 38 char* ReadLine(const char* prompt); |
| 39 |
| 40 private: |
| 41 Simulator* sim_; |
| 42 |
| 43 bool GetValue(char* desc, uint32_t* value); |
| 44 bool GetFValue(char* desc, double* value); |
| 45 |
| 46 // Set or delete a breakpoint. Returns true if successful. |
| 47 bool SetBreakpoint(Instr* breakpc); |
| 48 bool DeleteBreakpoint(Instr* breakpc); |
| 49 |
| 50 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 51 // execution to skip past breakpoints when run from the debugger. |
| 52 void UndoBreakpoints(); |
| 53 void RedoBreakpoints(); |
| 54 }; |
| 55 |
| 56 |
| 57 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { |
| 58 sim_ = sim; |
| 59 } |
| 60 |
| 61 |
| 62 SimulatorDebugger::~SimulatorDebugger() { |
| 63 } |
| 64 |
| 65 |
| 66 void SimulatorDebugger::Stop(Instr* instr, const char* message) { |
| 67 OS::Print("Simulator hit %s\n", message); |
| 68 Debug(); |
| 69 } |
| 70 |
| 71 |
| 72 static Register LookupCpuRegisterByName(const char* name) { |
| 73 static const char* kNames[] = { |
| 74 "r0", "r1", "r2", "r3", |
| 75 "r4", "r5", "r6", "r7", |
| 76 "r8", "r9", "r10", "r11", |
| 77 "r12", "r13", "r14", "r15", |
| 78 "r16", "r17", "r18", "r19", |
| 79 "r20", "r21", "r22", "r23", |
| 80 "r24", "r25", "r26", "r27", |
| 81 "r28", "r29", "r30", "r31", |
| 82 |
| 83 "zr", "at", "v0", "v1", |
| 84 "a0", "a1", "a2", "a3", |
| 85 "t0", "t1", "t2", "t3", |
| 86 "t4", "t5", "t6", "t7", |
| 87 "s0", "s1", "s2", "s3", |
| 88 "s4", "s5", "s6", "s7", |
| 89 "t8", "t9", "k0", "k1", |
| 90 "gp", "sp", "fp", "ra" |
| 91 }; |
| 92 static const Register kRegisters[] = { |
| 93 R0, R1, R2, R3, |
| 94 R4, R5, R6, R7, |
| 95 R8, R9, R10, R11, |
| 96 R12, R13, R14, R15, |
| 97 R16, R17, R18, R19, |
| 98 R20, R21, R22, R23, |
| 99 R24, R25, R26, R27, |
| 100 R28, R29, R30, R31, |
| 101 |
| 102 ZR, AT, V0, V1, |
| 103 A0, A1, A2, A3, |
| 104 T0, T1, T2, T3, |
| 105 T4, T5, T6, T7, |
| 106 S0, S1, S2, S3, |
| 107 S4, S5, S6, S7, |
| 108 T8, T9, K0, K1, |
| 109 GP, SP, FP, RA |
| 110 }; |
| 111 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); |
| 112 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { |
| 113 if (strcmp(kNames[i], name) == 0) { |
| 114 return kRegisters[i]; |
| 115 } |
| 116 } |
| 117 return kNoRegister; |
| 118 } |
| 119 |
| 120 |
| 121 static FRegister LookupFRegisterByName(const char* name) { |
| 122 int reg_nr = -1; |
| 123 bool ok = SScanF(name, "f%d", ®_nr); |
| 124 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfFRegisters)) { |
| 125 return static_cast<FRegister>(reg_nr); |
| 126 } |
| 127 return kNoFRegister; |
| 128 } |
| 129 |
| 130 |
| 131 bool SimulatorDebugger::GetValue(char* desc, uint32_t* value) { |
| 132 Register reg = LookupCpuRegisterByName(desc); |
| 133 if (reg != kNoRegister) { |
| 134 *value = sim_->get_register(reg); |
| 135 return true; |
| 136 } |
| 137 if ((desc[0] == '*')) { |
| 138 uint32_t addr; |
| 139 if (GetValue(desc + 1, &addr)) { |
| 140 if (Simulator::IsIllegalAddress(addr)) { |
| 141 return false; |
| 142 } |
| 143 *value = *(reinterpret_cast<uint32_t*>(addr)); |
| 144 return true; |
| 145 } |
| 146 } |
| 147 if (strcmp("pc", desc) == 0) { |
| 148 *value = sim_->get_pc(); |
| 149 return true; |
| 150 } |
| 151 bool retval = SScanF(desc, "0x%x", value) == 1; |
| 152 if (!retval) { |
| 153 retval = SScanF(desc, "%x", value) == 1; |
| 154 } |
| 155 return retval; |
| 156 } |
| 157 |
| 158 |
| 159 bool SimulatorDebugger::GetFValue(char* desc, double* value) { |
| 160 FRegister freg = LookupFRegisterByName(desc); |
| 161 if (freg != kNoFRegister) { |
| 162 *value = sim_->get_fregister(freg); |
| 163 return true; |
| 164 } |
| 165 if ((desc[0] == '*')) { |
| 166 uint32_t addr; |
| 167 if (GetValue(desc + 1, &addr)) { |
| 168 if (Simulator::IsIllegalAddress(addr)) { |
| 169 return false; |
| 170 } |
| 171 *value = *(reinterpret_cast<float*>(addr)); |
| 172 return true; |
| 173 } |
| 174 } |
| 175 return false; |
| 176 } |
| 177 |
| 178 |
| 179 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { |
| 180 // Check if a breakpoint can be set. If not return without any side-effects. |
| 181 if (sim_->break_pc_ != NULL) { |
| 182 return false; |
| 183 } |
| 184 |
| 185 // Set the breakpoint. |
| 186 sim_->break_pc_ = breakpc; |
| 187 sim_->break_instr_ = breakpc->InstructionBits(); |
| 188 // Not setting the breakpoint instruction in the code itself. It will be set |
| 189 // when the debugger shell continues. |
| 190 return true; |
| 191 } |
| 192 |
| 193 |
| 194 bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) { |
| 195 if (sim_->break_pc_ != NULL) { |
| 196 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 197 } |
| 198 |
| 199 sim_->break_pc_ = NULL; |
| 200 sim_->break_instr_ = 0; |
| 201 return true; |
| 202 } |
| 203 |
| 204 |
| 205 void SimulatorDebugger::UndoBreakpoints() { |
| 206 if (sim_->break_pc_ != NULL) { |
| 207 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); |
| 208 } |
| 209 } |
| 210 |
| 211 |
| 212 void SimulatorDebugger::RedoBreakpoints() { |
| 213 if (sim_->break_pc_ != NULL) { |
| 214 sim_->break_pc_->SetInstructionBits(Instr::kBreakPointInstruction); |
| 215 } |
| 216 } |
| 217 |
| 218 |
| 219 void SimulatorDebugger::Debug() { |
| 220 intptr_t last_pc = -1; |
| 221 bool done = false; |
| 222 bool decoded = true; |
| 223 |
| 224 #define COMMAND_SIZE 63 |
| 225 #define ARG_SIZE 255 |
| 226 |
| 227 #define STR(a) #a |
| 228 #define XSTR(a) STR(a) |
| 229 |
| 230 char cmd[COMMAND_SIZE + 1]; |
| 231 char arg1[ARG_SIZE + 1]; |
| 232 char arg2[ARG_SIZE + 1]; |
| 233 |
| 234 // make sure to have a proper terminating character if reaching the limit |
| 235 cmd[COMMAND_SIZE] = 0; |
| 236 arg1[ARG_SIZE] = 0; |
| 237 arg2[ARG_SIZE] = 0; |
| 238 |
| 239 // Undo all set breakpoints while running in the debugger shell. This will |
| 240 // make them invisible to all commands. |
| 241 UndoBreakpoints(); |
| 242 |
| 243 while (!done) { |
| 244 if (last_pc != sim_->get_pc()) { |
| 245 last_pc = sim_->get_pc(); |
| 246 decoded = Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize); |
| 247 } |
| 248 char* line = ReadLine("sim> "); |
| 249 if (line == NULL) { |
| 250 break; |
| 251 } else { |
| 252 // Use sscanf to parse the individual parts of the command line. At the |
| 253 // moment no command expects more than two parameters. |
| 254 int args = SScanF(line, |
| 255 "%" XSTR(COMMAND_SIZE) "s " |
| 256 "%" XSTR(ARG_SIZE) "s " |
| 257 "%" XSTR(ARG_SIZE) "s", |
| 258 cmd, arg1, arg2); |
| 259 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
| 260 OS::Print("c/cont -- continue execution\n" |
| 261 "disasm -- disassemble instrs at current pc location\n" |
| 262 " other variants are:\n" |
| 263 " disasm <address>\n" |
| 264 " disasm <address> <number_of_instructions>\n" |
| 265 " by default 10 instrs are disassembled\n" |
| 266 "del -- delete breakpoints\n" |
| 267 "gdb -- transfer control to gdb\n" |
| 268 "h/help -- print this help string\n" |
| 269 "break <address> -- set break point at specified address\n" |
| 270 "p/print <reg or value or *addr> -- print integer value\n" |
| 271 "pf/printfloat <freg or *addr> -- print float value\n" |
| 272 "po/printobject <*reg or *addr> -- print object\n" |
| 273 "si/stepi -- single step an instruction\n" |
| 274 "unstop -- if current pc is a stop instr make it a nop\n" |
| 275 "q/quit -- Quit the debugger and exit program\n"); |
| 276 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { |
| 277 OS::Print("Quitting\n"); |
| 278 OS::Exit(0); |
| 279 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 280 if (decoded) { |
| 281 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 282 } else { |
| 283 OS::Print("Instruction could not be decoded. Stepping disabled.\n"); |
| 284 } |
| 285 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 286 if (decoded) { |
| 287 // Execute the one instruction we broke at with breakpoints disabled. |
| 288 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 289 // Leave the debugger shell. |
| 290 done = true; |
| 291 } else { |
| 292 OS::Print("Instruction could not be decoded. Cannot continue.\n"); |
| 293 } |
| 294 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 295 if (args == 2) { |
| 296 uint32_t value; |
| 297 if (GetValue(arg1, &value)) { |
| 298 OS::Print("%s: %u 0x%x\n", arg1, value, value); |
| 299 } else { |
| 300 OS::Print("%s unrecognized\n", arg1); |
| 301 } |
| 302 } else { |
| 303 OS::Print("print <reg or value or *addr>\n"); |
| 304 } |
| 305 } else if ((strcmp(cmd, "pf") == 0) || |
| 306 (strcmp(cmd, "printfloat") == 0)) { |
| 307 if (args == 2) { |
| 308 double dvalue; |
| 309 if (GetFValue(arg1, &dvalue)) { |
| 310 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); |
| 311 OS::Print("%s: %llu 0x%llx %.8g\n", |
| 312 arg1, long_value, long_value, dvalue); |
| 313 } else { |
| 314 OS::Print("%s unrecognized\n", arg1); |
| 315 } |
| 316 } else { |
| 317 OS::Print("printfloat <dreg or *addr>\n"); |
| 318 } |
| 319 } else if ((strcmp(cmd, "po") == 0) || |
| 320 (strcmp(cmd, "printobject") == 0)) { |
| 321 if (args == 2) { |
| 322 uint32_t value; |
| 323 // Make the dereferencing '*' optional. |
| 324 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || |
| 325 GetValue(arg1, &value)) { |
| 326 if (Isolate::Current()->heap()->Contains(value)) { |
| 327 OS::Print("%s: \n", arg1); |
| 328 #if defined(DEBUG) |
| 329 const Object& obj = Object::Handle( |
| 330 reinterpret_cast<RawObject*>(value)); |
| 331 obj.Print(); |
| 332 #endif // defined(DEBUG) |
| 333 } else { |
| 334 OS::Print("0x%x is not an object reference\n", value); |
| 335 } |
| 336 } else { |
| 337 OS::Print("%s unrecognized\n", arg1); |
| 338 } |
| 339 } else { |
| 340 OS::Print("printobject <*reg or *addr>\n"); |
| 341 } |
| 342 } else if (strcmp(cmd, "disasm") == 0) { |
| 343 uint32_t start = 0; |
| 344 uint32_t end = 0; |
| 345 if (args == 1) { |
| 346 start = sim_->get_pc(); |
| 347 end = start + (10 * Instr::kInstrSize); |
| 348 } else if (args == 2) { |
| 349 if (GetValue(arg1, &start)) { |
| 350 // no length parameter passed, assume 10 instructions |
| 351 if (Simulator::IsIllegalAddress(start)) { |
| 352 // If start isn't a valid address, warn and use PC instead |
| 353 OS::Print("First argument yields invalid address: 0x%x\n", start); |
| 354 OS::Print("Using PC instead"); |
| 355 start = sim_->get_pc(); |
| 356 } |
| 357 end = start + (10 * Instr::kInstrSize); |
| 358 } |
| 359 } else { |
| 360 uint32_t length; |
| 361 if (GetValue(arg1, &start) && GetValue(arg2, &length)) { |
| 362 if (Simulator::IsIllegalAddress(start)) { |
| 363 // If start isn't a valid address, warn and use PC instead |
| 364 OS::Print("First argument yields invalid address: 0x%x\n", start); |
| 365 OS::Print("Using PC instead\n"); |
| 366 start = sim_->get_pc(); |
| 367 } |
| 368 end = start + (length * Instr::kInstrSize); |
| 369 } |
| 370 } |
| 371 |
| 372 Disassembler::Disassemble(start, end); |
| 373 } else if (strcmp(cmd, "gdb") == 0) { |
| 374 OS::Print("relinquishing control to gdb\n"); |
| 375 OS::DebugBreak(); |
| 376 OS::Print("regaining control from gdb\n"); |
| 377 } else if (strcmp(cmd, "break") == 0) { |
| 378 if (args == 2) { |
| 379 uint32_t addr; |
| 380 if (GetValue(arg1, &addr)) { |
| 381 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) { |
| 382 OS::Print("setting breakpoint failed\n"); |
| 383 } |
| 384 } else { |
| 385 OS::Print("%s unrecognized\n", arg1); |
| 386 } |
| 387 } else { |
| 388 OS::Print("break <addr>\n"); |
| 389 } |
| 390 } else if (strcmp(cmd, "del") == 0) { |
| 391 if (!DeleteBreakpoint(NULL)) { |
| 392 OS::Print("deleting breakpoint failed\n"); |
| 393 } |
| 394 } else if (strcmp(cmd, "unstop") == 0) { |
| 395 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; |
| 396 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); |
| 397 if (stop_instr->IsBreakPoint()) { |
| 398 stop_instr->SetInstructionBits(Instr::kNopInstruction); |
| 399 } else { |
| 400 OS::Print("Not at debugger stop.\n"); |
| 401 } |
| 402 } else { |
| 403 OS::Print("Unknown command: %s\n", cmd); |
| 404 } |
| 405 } |
| 406 delete[] line; |
| 407 } |
| 408 |
| 409 // Add all the breakpoints back to stop execution and enter the debugger |
| 410 // shell when hit. |
| 411 RedoBreakpoints(); |
| 412 |
| 413 #undef COMMAND_SIZE |
| 414 #undef ARG_SIZE |
| 415 |
| 416 #undef STR |
| 417 #undef XSTR |
| 418 } |
| 419 |
| 420 |
| 421 char* SimulatorDebugger::ReadLine(const char* prompt) { |
| 422 char* result = NULL; |
| 423 char line_buf[256]; |
| 424 int offset = 0; |
| 425 bool keep_going = true; |
| 426 fprintf(stdout, "%s", prompt); |
| 427 fflush(stdout); |
| 428 while (keep_going) { |
| 429 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { |
| 430 // fgets got an error. Just give up. |
| 431 if (result != NULL) { |
| 432 delete[] result; |
| 433 } |
| 434 return NULL; |
| 435 } |
| 436 int len = strlen(line_buf); |
| 437 if (len > 1 && |
| 438 line_buf[len - 2] == '\\' && |
| 439 line_buf[len - 1] == '\n') { |
| 440 // When we read a line that ends with a "\" we remove the escape and |
| 441 // append the remainder. |
| 442 line_buf[len - 2] = '\n'; |
| 443 line_buf[len - 1] = 0; |
| 444 len -= 1; |
| 445 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { |
| 446 // Since we read a new line we are done reading the line. This |
| 447 // will exit the loop after copying this buffer into the result. |
| 448 keep_going = false; |
| 449 } |
| 450 if (result == NULL) { |
| 451 // Allocate the initial result and make room for the terminating '\0' |
| 452 result = new char[len + 1]; |
| 453 if (result == NULL) { |
| 454 // OOM, so cannot readline anymore. |
| 455 return NULL; |
| 456 } |
| 457 } else { |
| 458 // Allocate a new result with enough room for the new addition. |
| 459 int new_len = offset + len + 1; |
| 460 char* new_result = new char[new_len]; |
| 461 if (new_result == NULL) { |
| 462 // OOM, free the buffer allocated so far and return NULL. |
| 463 delete[] result; |
| 464 return NULL; |
| 465 } else { |
| 466 // Copy the existing input into the new array and set the new |
| 467 // array as the result. |
| 468 memmove(new_result, result, offset); |
| 469 delete[] result; |
| 470 result = new_result; |
| 471 } |
| 472 } |
| 473 // Copy the newly read line into the result. |
| 474 memmove(result + offset, line_buf, len); |
| 475 offset += len; |
| 476 } |
| 477 ASSERT(result != NULL); |
| 478 result[offset] = '\0'; |
| 479 return result; |
| 480 } |
| 481 |
| 482 |
| 21 void Simulator::InitOnce() { | 483 void Simulator::InitOnce() { |
| 22 } | 484 } |
| 23 | 485 |
| 24 | 486 |
| 25 Simulator::Simulator() { | 487 Simulator::Simulator() { |
| 26 // Setup simulator support first. Some of this information is needed to | 488 // Setup simulator support first. Some of this information is needed to |
| 27 // setup the architecture state. | 489 // setup the architecture state. |
| 28 // We allocate the stack here, the size is computed as the sum of | 490 // We allocate the stack here, the size is computed as the sum of |
| 29 // the size specified by the user and the buffer space needed for | 491 // the size specified by the user and the buffer space needed for |
| 30 // handling stack overflow exceptions. To be safe in potential | 492 // handling stack overflow exceptions. To be safe in potential |
| 31 // stack underflows we also add some underflow buffer space. | 493 // stack underflows we also add some underflow buffer space. |
| 32 stack_ = new char[(Isolate::GetSpecifiedStackSize() + | 494 stack_ = new char[(Isolate::GetSpecifiedStackSize() + |
| 33 Isolate::kStackSizeBuffer + | 495 Isolate::kStackSizeBuffer + |
| 34 kSimulatorStackUnderflowSize)]; | 496 kSimulatorStackUnderflowSize)]; |
| 35 icount_ = 0; | 497 icount_ = 0; |
| 36 delay_slot_ = false; | 498 delay_slot_ = false; |
| 499 break_pc_ = NULL; |
| 500 break_instr_ = 0; |
| 37 | 501 |
| 38 // Setup architecture state. | 502 // Setup architecture state. |
| 39 // All registers are initialized to zero to start with. | 503 // All registers are initialized to zero to start with. |
| 40 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 504 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 41 registers_[i] = 0; | 505 registers_[i] = 0; |
| 42 } | 506 } |
| 43 pc_ = 0; | 507 pc_ = 0; |
| 44 // The sp is initialized to point to the bottom (high address) of the | 508 // The sp is initialized to point to the bottom (high address) of the |
| 45 // allocated stack area. | 509 // allocated stack area. |
| 46 registers_[SP] = StackTop(); | 510 registers_[SP] = StackTop(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 // Get the register from the architecture state. This function does handle | 542 // Get the register from the architecture state. This function does handle |
| 79 // the special case of accessing the PC register. | 543 // the special case of accessing the PC register. |
| 80 int32_t Simulator::get_register(Register reg) const { | 544 int32_t Simulator::get_register(Register reg) const { |
| 81 if (reg == R0) { | 545 if (reg == R0) { |
| 82 return 0; | 546 return 0; |
| 83 } | 547 } |
| 84 return registers_[reg]; | 548 return registers_[reg]; |
| 85 } | 549 } |
| 86 | 550 |
| 87 | 551 |
| 552 void Simulator::set_fregister(FRegister reg, double value) { |
| 553 ASSERT((reg >= 0) && (reg < kNumberOfFRegisters)); |
| 554 fregisters_[reg] = value; |
| 555 } |
| 556 |
| 557 |
| 558 double Simulator::get_fregister(FRegister reg) const { |
| 559 ASSERT((reg >= 0) && (reg < kNumberOfFRegisters)); |
| 560 return fregisters_[reg]; |
| 561 } |
| 562 |
| 563 |
| 564 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
| 565 uword fault_pc = get_pc(); |
| 566 // The debugger will not be able to single step past this instruction, but |
| 567 // it will be possible to disassemble the code and inspect registers. |
| 568 char buffer[128]; |
| 569 snprintf(buffer, sizeof(buffer), |
| 570 "illegal memory access at 0x%"Px", pc=0x%"Px"\n", |
| 571 addr, fault_pc); |
| 572 SimulatorDebugger dbg(this); |
| 573 dbg.Stop(instr, buffer); |
| 574 // The debugger will return control in non-interactive mode. |
| 575 FATAL("Cannot continue execution after illegal memory access."); |
| 576 } |
| 577 |
| 578 |
| 579 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { |
| 580 // The debugger will not be able to single step past this instruction, but |
| 581 // it will be possible to disassemble the code and inspect registers. |
| 582 char buffer[64]; |
| 583 snprintf(buffer, sizeof(buffer), |
| 584 "unaligned %s at 0x%"Px", pc=%p\n", msg, addr, instr); |
| 585 SimulatorDebugger dbg(this); |
| 586 dbg.Stop(instr, buffer); |
| 587 // The debugger will return control in non-interactive mode. |
| 588 FATAL("Cannot continue execution after unaligned access."); |
| 589 } |
| 590 |
| 591 |
| 88 // Returns the top of the stack area to enable checking for stack pointer | 592 // Returns the top of the stack area to enable checking for stack pointer |
| 89 // validity. | 593 // validity. |
| 90 uword Simulator::StackTop() const { | 594 uword Simulator::StackTop() const { |
| 91 // To be safe in potential stack underflows we leave some buffer above and | 595 // To be safe in potential stack underflows we leave some buffer above and |
| 92 // set the stack top. | 596 // set the stack top. |
| 93 return reinterpret_cast<uword>(stack_) + | 597 return reinterpret_cast<uword>(stack_) + |
| 94 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); | 598 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); |
| 95 } | 599 } |
| 96 | 600 |
| 97 | 601 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 111 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 615 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 112 return *ptr; | 616 return *ptr; |
| 113 } | 617 } |
| 114 | 618 |
| 115 | 619 |
| 116 int16_t Simulator::ReadH(uword addr, Instr* instr) { | 620 int16_t Simulator::ReadH(uword addr, Instr* instr) { |
| 117 if ((addr & 1) == 0) { | 621 if ((addr & 1) == 0) { |
| 118 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 622 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 119 return *ptr; | 623 return *ptr; |
| 120 } | 624 } |
| 121 // TODO(zra) unaligned access. Trap into debugger. | 625 UnalignedAccess("signed halfword read", addr, instr); |
| 122 UNIMPLEMENTED(); | |
| 123 return 0; | 626 return 0; |
| 124 } | 627 } |
| 125 | 628 |
| 126 | 629 |
| 127 uint16_t Simulator::ReadHU(uword addr, Instr* instr) { | 630 uint16_t Simulator::ReadHU(uword addr, Instr* instr) { |
| 128 if ((addr & 1) == 0) { | 631 if ((addr & 1) == 0) { |
| 129 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 632 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 130 return *ptr; | 633 return *ptr; |
| 131 } | 634 } |
| 132 // TODO(zra) unaligned access. Trap into debugger. | 635 UnalignedAccess("unsigned halfword read", addr, instr); |
| 133 UNIMPLEMENTED(); | |
| 134 return 0; | 636 return 0; |
| 135 } | 637 } |
| 136 | 638 |
| 137 | 639 |
| 138 int Simulator::ReadW(uword addr, Instr* instr) { | 640 int Simulator::ReadW(uword addr, Instr* instr) { |
| 139 if ((addr & 3) == 0) { | 641 if ((addr & 3) == 0) { |
| 140 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 642 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 141 return *ptr; | 643 return *ptr; |
| 142 } | 644 } |
| 143 // TODO(zra) unaligned access. Trap into debugger. | 645 UnalignedAccess("read", addr, instr); |
| 144 UNIMPLEMENTED(); | |
| 145 return 0; | 646 return 0; |
| 146 } | 647 } |
| 147 | 648 |
| 148 | 649 |
| 149 void Simulator::WriteB(uword addr, uint8_t value) { | 650 void Simulator::WriteB(uword addr, uint8_t value) { |
| 150 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 651 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 151 *ptr = value; | 652 *ptr = value; |
| 152 } | 653 } |
| 153 | 654 |
| 154 | 655 |
| 155 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) { | 656 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) { |
| 156 if ((addr & 1) == 0) { | 657 if ((addr & 1) == 0) { |
| 157 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 658 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 158 *ptr = value; | 659 *ptr = value; |
| 159 return; | 660 return; |
| 160 } | 661 } |
| 161 // TODO(zra) unaligned access. Trap into debugger. | 662 UnalignedAccess("halfword write", addr, instr); |
| 162 UNIMPLEMENTED(); | |
| 163 } | 663 } |
| 164 | 664 |
| 165 | 665 |
| 166 void Simulator::WriteW(uword addr, int value, Instr* instr) { | 666 void Simulator::WriteW(uword addr, int value, Instr* instr) { |
| 167 if ((addr & 3) == 0) { | 667 if ((addr & 3) == 0) { |
| 168 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 668 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 169 *ptr = value; | 669 *ptr = value; |
| 170 return; | 670 return; |
| 171 } | 671 } |
| 172 // TODO(zra) unaligned access. Trap into debugger. | 672 UnalignedAccess("write", addr, instr); |
| 173 UNIMPLEMENTED(); | |
| 174 } | 673 } |
| 175 | 674 |
| 176 | 675 |
| 177 bool Simulator::OverflowFrom(int32_t alu_out, | 676 bool Simulator::OverflowFrom(int32_t alu_out, |
| 178 int32_t left, int32_t right, bool addition) { | 677 int32_t left, int32_t right, bool addition) { |
| 179 bool overflow; | 678 bool overflow; |
| 180 if (addition) { | 679 if (addition) { |
| 181 // Operands have the same sign. | 680 // Operands have the same sign. |
| 182 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) | 681 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) |
| 183 // And operands and result have different sign. | 682 // And operands and result have different sign. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 204 break; | 703 break; |
| 205 } | 704 } |
| 206 case AND: { | 705 case AND: { |
| 207 ASSERT(instr->SaField() == 0); | 706 ASSERT(instr->SaField() == 0); |
| 208 // Format(instr, "and 'rd, 'rs, 'rt"); | 707 // Format(instr, "and 'rd, 'rs, 'rt"); |
| 209 int32_t rs_val = get_register(instr->RsField()); | 708 int32_t rs_val = get_register(instr->RsField()); |
| 210 int32_t rt_val = get_register(instr->RtField()); | 709 int32_t rt_val = get_register(instr->RtField()); |
| 211 set_register(instr->RdField(), rs_val & rt_val); | 710 set_register(instr->RdField(), rs_val & rt_val); |
| 212 break; | 711 break; |
| 213 } | 712 } |
| 713 case BREAK: { |
| 714 SimulatorDebugger dbg(this); |
| 715 dbg.Stop(instr, "breakpoint"); |
| 716 break; |
| 717 } |
| 214 case DIV: { | 718 case DIV: { |
| 215 ASSERT(instr->RdField() == 0); | 719 ASSERT(instr->RdField() == 0); |
| 216 ASSERT(instr->SaField() == 0); | 720 ASSERT(instr->SaField() == 0); |
| 217 // Format(instr, "div 'rs, 'rt"); | 721 // Format(instr, "div 'rs, 'rt"); |
| 218 int32_t rs_val = get_register(instr->RsField()); | 722 int32_t rs_val = get_register(instr->RsField()); |
| 219 int32_t rt_val = get_register(instr->RtField()); | 723 int32_t rt_val = get_register(instr->RtField()); |
| 220 if (rt_val == 0) { | 724 if (rt_val == 0) { |
| 221 // Results are unpredictable. | 725 // Results are unpredictable. |
| 222 set_hi_register(0); | 726 set_hi_register(0); |
| 223 set_lo_register(0); | 727 set_lo_register(0); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 ASSERT(instr->RdField() == R0); | 792 ASSERT(instr->RdField() == R0); |
| 289 ASSERT(!delay_slot_); | 793 ASSERT(!delay_slot_); |
| 290 // Format(instr, "jr'hint 'rs"); | 794 // Format(instr, "jr'hint 'rs"); |
| 291 uword next_pc = get_register(instr->RsField()); | 795 uword next_pc = get_register(instr->RsField()); |
| 292 ExecuteDelaySlot(); | 796 ExecuteDelaySlot(); |
| 293 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. | 797 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. |
| 294 break; | 798 break; |
| 295 } | 799 } |
| 296 default: { | 800 default: { |
| 297 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | 801 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); |
| 298 UNREACHABLE(); | 802 UNIMPLEMENTED(); |
| 299 break; | 803 break; |
| 300 } | 804 } |
| 301 } | 805 } |
| 302 } | 806 } |
| 303 | 807 |
| 304 | 808 |
| 305 void Simulator::DecodeSpecial2(Instr* instr) { | 809 void Simulator::DecodeSpecial2(Instr* instr) { |
| 306 ASSERT(instr->OpcodeField() == SPECIAL2); | 810 ASSERT(instr->OpcodeField() == SPECIAL2); |
| 307 switch (instr->FunctionField()) { | 811 switch (instr->FunctionField()) { |
| 308 case CLO: { | 812 case CLO: { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 330 rs_val <<= 1; | 834 rs_val <<= 1; |
| 331 } | 835 } |
| 332 } else { | 836 } else { |
| 333 bitcount = 32; | 837 bitcount = 32; |
| 334 } | 838 } |
| 335 set_register(instr->RdField(), bitcount); | 839 set_register(instr->RdField(), bitcount); |
| 336 break; | 840 break; |
| 337 } | 841 } |
| 338 default: { | 842 default: { |
| 339 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); | 843 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); |
| 340 UNREACHABLE(); | 844 UNIMPLEMENTED(); |
| 341 break; | |
| 342 } | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 | |
| 347 void Simulator::DecodeSpecial3(Instr* instr) { | |
| 348 ASSERT(instr->OpcodeField() == SPECIAL3); | |
| 349 switch (instr->FunctionField()) { | |
| 350 default: { | |
| 351 OS::PrintErr("DecodeSpecial3: 0x%x\n", instr->InstructionBits()); | |
| 352 UNREACHABLE(); | |
| 353 break; | 845 break; |
| 354 } | 846 } |
| 355 } | 847 } |
| 356 } | 848 } |
| 357 | 849 |
| 358 | 850 |
| 359 void Simulator::InstructionDecode(Instr* instr) { | 851 void Simulator::InstructionDecode(Instr* instr) { |
| 360 switch (instr->OpcodeField()) { | 852 switch (instr->OpcodeField()) { |
| 361 case SPECIAL: { | 853 case SPECIAL: { |
| 362 DecodeSpecial(instr); | 854 DecodeSpecial(instr); |
| 363 break; | 855 break; |
| 364 } | 856 } |
| 365 case SPECIAL2: { | 857 case SPECIAL2: { |
| 366 DecodeSpecial2(instr); | 858 DecodeSpecial2(instr); |
| 367 break; | 859 break; |
| 368 } | 860 } |
| 369 case SPECIAL3: { | |
| 370 DecodeSpecial3(instr); | |
| 371 break; | |
| 372 } | |
| 373 case ADDIU: { | 861 case ADDIU: { |
| 374 // Format(instr, "addiu 'rt, 'rs, 'imms"); | 862 // Format(instr, "addiu 'rt, 'rs, 'imms"); |
| 375 int32_t rs_val = get_register(instr->RsField()); | 863 int32_t rs_val = get_register(instr->RsField()); |
| 376 int32_t imm_val = instr->SImmField(); | 864 int32_t imm_val = instr->SImmField(); |
| 377 int32_t res = rs_val + imm_val; | 865 int32_t res = rs_val + imm_val; |
| 378 // Rt is set even on overflow. | 866 // Rt is set even on overflow. |
| 379 set_register(instr->RtField(), res); | 867 set_register(instr->RtField(), res); |
| 380 break; | 868 break; |
| 381 } | 869 } |
| 382 case ANDI: { | 870 case ANDI: { |
| 383 // Format(instr, "andi 'rt, 'rs, 'immu"); | 871 // Format(instr, "andi 'rt, 'rs, 'immu"); |
| 384 int32_t rs_val = get_register(instr->RsField()); | 872 int32_t rs_val = get_register(instr->RsField()); |
| 385 set_register(instr->RtField(), rs_val & instr->UImmField()); | 873 set_register(instr->RtField(), rs_val & instr->UImmField()); |
| 386 break; | 874 break; |
| 387 } | 875 } |
| 388 case LB: { | 876 case LB: { |
| 389 // Format(instr, "lb 'rt, 'imms('rs)"); | 877 // Format(instr, "lb 'rt, 'imms('rs)"); |
| 390 int32_t base_val = get_register(instr->RsField()); | 878 int32_t base_val = get_register(instr->RsField()); |
| 391 int32_t imm_val = instr->SImmField(); | 879 int32_t imm_val = instr->SImmField(); |
| 392 uword addr = base_val + imm_val; | 880 uword addr = base_val + imm_val; |
| 393 if (Simulator::IsIllegalAddress(addr)) { | 881 if (Simulator::IsIllegalAddress(addr)) { |
| 394 // TODO(zra) trap into debugger. | 882 HandleIllegalAccess(addr, instr); |
| 395 UNIMPLEMENTED(); | |
| 396 } else { | 883 } else { |
| 397 int32_t res = ReadB(addr); | 884 int32_t res = ReadB(addr); |
| 398 set_register(instr->RtField(), res); | 885 set_register(instr->RtField(), res); |
| 399 } | 886 } |
| 400 break; | 887 break; |
| 401 } | 888 } |
| 402 case LBU: { | 889 case LBU: { |
| 403 // Format(instr, "lbu 'rt, 'imms('rs)"); | 890 // Format(instr, "lbu 'rt, 'imms('rs)"); |
| 404 int32_t base_val = get_register(instr->RsField()); | 891 int32_t base_val = get_register(instr->RsField()); |
| 405 int32_t imm_val = instr->SImmField(); | 892 int32_t imm_val = instr->SImmField(); |
| 406 uword addr = base_val + imm_val; | 893 uword addr = base_val + imm_val; |
| 407 if (Simulator::IsIllegalAddress(addr)) { | 894 if (Simulator::IsIllegalAddress(addr)) { |
| 408 // TODO(zra) trap into debugger. | 895 HandleIllegalAccess(addr, instr); |
| 409 UNIMPLEMENTED(); | |
| 410 } else { | 896 } else { |
| 411 int32_t res = ReadBU(addr); | 897 int32_t res = ReadBU(addr); |
| 412 set_register(instr->RtField(), res); | 898 set_register(instr->RtField(), res); |
| 413 } | 899 } |
| 414 break; | 900 break; |
| 415 } | 901 } |
| 416 case LH: { | 902 case LH: { |
| 417 // Format(instr, "lh 'rt, 'imms('rs)"); | 903 // Format(instr, "lh 'rt, 'imms('rs)"); |
| 418 int32_t base_val = get_register(instr->RsField()); | 904 int32_t base_val = get_register(instr->RsField()); |
| 419 int32_t imm_val = instr->SImmField(); | 905 int32_t imm_val = instr->SImmField(); |
| 420 uword addr = base_val + imm_val; | 906 uword addr = base_val + imm_val; |
| 421 if (Simulator::IsIllegalAddress(addr)) { | 907 if (Simulator::IsIllegalAddress(addr)) { |
| 422 // TODO(zra) trap into debugger. | 908 HandleIllegalAccess(addr, instr); |
| 423 UNIMPLEMENTED(); | |
| 424 } else { | 909 } else { |
| 425 int32_t res = ReadH(addr, instr); | 910 int32_t res = ReadH(addr, instr); |
| 426 set_register(instr->RtField(), res); | 911 set_register(instr->RtField(), res); |
| 427 } | 912 } |
| 428 break; | 913 break; |
| 429 } | 914 } |
| 430 case LHU: { | 915 case LHU: { |
| 431 // Format(instr, "lhu 'rt, 'imms('rs)"); | 916 // Format(instr, "lhu 'rt, 'imms('rs)"); |
| 432 int32_t base_val = get_register(instr->RsField()); | 917 int32_t base_val = get_register(instr->RsField()); |
| 433 int32_t imm_val = instr->SImmField(); | 918 int32_t imm_val = instr->SImmField(); |
| 434 uword addr = base_val + imm_val; | 919 uword addr = base_val + imm_val; |
| 435 if (Simulator::IsIllegalAddress(addr)) { | 920 if (Simulator::IsIllegalAddress(addr)) { |
| 436 // TODO(zra) trap into debugger. | 921 HandleIllegalAccess(addr, instr); |
| 437 UNIMPLEMENTED(); | |
| 438 } else { | 922 } else { |
| 439 int32_t res = ReadHU(addr, instr); | 923 int32_t res = ReadHU(addr, instr); |
| 440 set_register(instr->RtField(), res); | 924 set_register(instr->RtField(), res); |
| 441 } | 925 } |
| 442 break; | 926 break; |
| 443 } | 927 } |
| 444 case LUI: { | 928 case LUI: { |
| 445 ASSERT(instr->RsField() == 0); | 929 ASSERT(instr->RsField() == 0); |
| 446 set_register(instr->RtField(), instr->UImmField() << 16); | 930 set_register(instr->RtField(), instr->UImmField() << 16); |
| 447 break; | 931 break; |
| 448 } | 932 } |
| 449 case LW: { | 933 case LW: { |
| 450 // Format(instr, "lw 'rt, 'imms('rs)"); | 934 // Format(instr, "lw 'rt, 'imms('rs)"); |
| 451 int32_t base_val = get_register(instr->RsField()); | 935 int32_t base_val = get_register(instr->RsField()); |
| 452 int32_t imm_val = instr->SImmField(); | 936 int32_t imm_val = instr->SImmField(); |
| 453 uword addr = base_val + imm_val; | 937 uword addr = base_val + imm_val; |
| 454 if (Simulator::IsIllegalAddress(addr)) { | 938 if (Simulator::IsIllegalAddress(addr)) { |
| 455 // TODO(zra) trap into debugger. | 939 HandleIllegalAccess(addr, instr); |
| 456 UNIMPLEMENTED(); | |
| 457 } else { | 940 } else { |
| 458 int32_t res = ReadW(addr, instr); | 941 int32_t res = ReadW(addr, instr); |
| 459 set_register(instr->RtField(), res); | 942 set_register(instr->RtField(), res); |
| 460 } | 943 } |
| 461 break; | 944 break; |
| 462 } | 945 } |
| 463 case ORI: { | 946 case ORI: { |
| 464 // Format(instr, "ori 'rt, 'rs, 'immu"); | 947 // Format(instr, "ori 'rt, 'rs, 'immu"); |
| 465 int32_t rs_val = get_register(instr->RsField()); | 948 int32_t rs_val = get_register(instr->RsField()); |
| 466 set_register(instr->RtField(), rs_val | instr->UImmField()); | 949 set_register(instr->RtField(), rs_val | instr->UImmField()); |
| 467 break; | 950 break; |
| 468 } | 951 } |
| 469 case SB: { | 952 case SB: { |
| 470 // Format(instr, "sb 'rt, 'imms('rs)"); | 953 // Format(instr, "sb 'rt, 'imms('rs)"); |
| 471 int32_t rt_val = get_register(instr->RtField()); | 954 int32_t rt_val = get_register(instr->RtField()); |
| 472 int32_t base_val = get_register(instr->RsField()); | 955 int32_t base_val = get_register(instr->RsField()); |
| 473 int32_t imm_val = instr->SImmField(); | 956 int32_t imm_val = instr->SImmField(); |
| 474 uword addr = base_val + imm_val; | 957 uword addr = base_val + imm_val; |
| 475 if (Simulator::IsIllegalAddress(addr)) { | 958 if (Simulator::IsIllegalAddress(addr)) { |
| 476 // TODO(zra) trap into debugger. | 959 HandleIllegalAccess(addr, instr); |
| 477 UNIMPLEMENTED(); | |
| 478 } else { | 960 } else { |
| 479 WriteB(addr, rt_val & 0xff); | 961 WriteB(addr, rt_val & 0xff); |
| 480 } | 962 } |
| 481 break; | 963 break; |
| 482 } | 964 } |
| 483 case SH: { | 965 case SH: { |
| 484 // Format(instr, "sh 'rt, 'imms('rs)"); | 966 // Format(instr, "sh 'rt, 'imms('rs)"); |
| 485 int32_t rt_val = get_register(instr->RtField()); | 967 int32_t rt_val = get_register(instr->RtField()); |
| 486 int32_t base_val = get_register(instr->RsField()); | 968 int32_t base_val = get_register(instr->RsField()); |
| 487 int32_t imm_val = instr->SImmField(); | 969 int32_t imm_val = instr->SImmField(); |
| 488 uword addr = base_val + imm_val; | 970 uword addr = base_val + imm_val; |
| 489 if (Simulator::IsIllegalAddress(addr)) { | 971 if (Simulator::IsIllegalAddress(addr)) { |
| 490 // TODO(zra) trap into debugger. | 972 HandleIllegalAccess(addr, instr); |
| 491 UNIMPLEMENTED(); | |
| 492 } else { | 973 } else { |
| 493 WriteH(addr, rt_val & 0xffff, instr); | 974 WriteH(addr, rt_val & 0xffff, instr); |
| 494 } | 975 } |
| 495 break; | 976 break; |
| 496 } | 977 } |
| 497 case SW: { | 978 case SW: { |
| 498 // Format(instr, "sw 'rt, 'imms('rs)"); | 979 // Format(instr, "sw 'rt, 'imms('rs)"); |
| 499 int32_t rt_val = get_register(instr->RtField()); | 980 int32_t rt_val = get_register(instr->RtField()); |
| 500 int32_t base_val = get_register(instr->RsField()); | 981 int32_t base_val = get_register(instr->RsField()); |
| 501 int32_t imm_val = instr->SImmField(); | 982 int32_t imm_val = instr->SImmField(); |
| 502 uword addr = base_val + imm_val; | 983 uword addr = base_val + imm_val; |
| 503 if (Simulator::IsIllegalAddress(addr)) { | 984 if (Simulator::IsIllegalAddress(addr)) { |
| 504 // TODO(zra) trap into debugger. | 985 HandleIllegalAccess(addr, instr); |
| 505 UNIMPLEMENTED(); | |
| 506 } else { | 986 } else { |
| 507 WriteW(addr, rt_val, instr); | 987 WriteW(addr, rt_val, instr); |
| 508 } | 988 } |
| 509 break; | 989 break; |
| 510 } | 990 } |
| 511 default: { | 991 default: { |
| 512 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); | 992 OS::PrintErr("Undecoded instruction: 0x%x at %p\n", |
| 513 UNREACHABLE(); | 993 instr->InstructionBits(), instr); |
| 994 UNIMPLEMENTED(); |
| 514 break; | 995 break; |
| 515 } | 996 } |
| 516 } | 997 } |
| 517 pc_ += Instr::kInstrSize; | 998 pc_ += Instr::kInstrSize; |
| 518 } | 999 } |
| 519 | 1000 |
| 520 | 1001 |
| 521 void Simulator::ExecuteDelaySlot() { | 1002 void Simulator::ExecuteDelaySlot() { |
| 522 ASSERT(pc_ != kEndSimulatingPC); | 1003 ASSERT(pc_ != kEndSimulatingPC); |
| 523 delay_slot_ = true; | 1004 delay_slot_ = true; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 // Restore the SP register and return R1:R0. | 1116 // Restore the SP register and return R1:R0. |
| 636 set_register(SP, sp_before_call); | 1117 set_register(SP, sp_before_call); |
| 637 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); | 1118 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); |
| 638 } | 1119 } |
| 639 | 1120 |
| 640 } // namespace dart | 1121 } // namespace dart |
| 641 | 1122 |
| 642 #endif // !defined(HOST_ARCH_MIPS) | 1123 #endif // !defined(HOST_ARCH_MIPS) |
| 643 | 1124 |
| 644 #endif // defined TARGET_ARCH_MIPS | 1125 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |