OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 #include <math.h> // for isnan. |
| 6 #include <setjmp.h> |
| 7 #include <stdlib.h> |
| 8 |
| 9 #include "vm/globals.h" |
| 10 #if defined(TARGET_ARCH_ARM64) |
| 11 |
| 12 // Only build the simulator if not compiling for real ARM hardware. |
| 13 #if !defined(HOST_ARCH_ARM64) |
| 14 |
| 15 #include "vm/simulator.h" |
| 16 |
| 17 #include "vm/assembler.h" |
| 18 #include "vm/constants_arm64.h" |
| 19 #include "vm/cpu.h" |
| 20 #include "vm/disassembler.h" |
| 21 #include "vm/native_arguments.h" |
| 22 #include "vm/stack_frame.h" |
| 23 #include "vm/thread.h" |
| 24 |
| 25 namespace dart { |
| 26 |
| 27 DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution."); |
| 28 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); |
| 29 |
| 30 |
| 31 // This macro provides a platform independent use of sscanf. The reason for |
| 32 // SScanF not being implemented in a platform independent way through |
| 33 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 34 // Library does not provide vsscanf. |
| 35 #define SScanF sscanf // NOLINT |
| 36 |
| 37 |
| 38 Simulator::Simulator() { |
| 39 // Setup simulator support first. Some of this information is needed to |
| 40 // setup the architecture state. |
| 41 // We allocate the stack here, the size is computed as the sum of |
| 42 // the size specified by the user and the buffer space needed for |
| 43 // handling stack overflow exceptions. To be safe in potential |
| 44 // stack underflows we also add some underflow buffer space. |
| 45 stack_ = new char[(Isolate::GetSpecifiedStackSize() + |
| 46 Isolate::kStackSizeBuffer + |
| 47 kSimulatorStackUnderflowSize)]; |
| 48 pc_modified_ = false; |
| 49 icount_ = 0; |
| 50 break_pc_ = NULL; |
| 51 break_instr_ = 0; |
| 52 top_exit_frame_info_ = 0; |
| 53 |
| 54 // Setup architecture state. |
| 55 // All registers are initialized to zero to start with. |
| 56 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 57 registers_[i] = 0; |
| 58 } |
| 59 n_flag_ = false; |
| 60 z_flag_ = false; |
| 61 c_flag_ = false; |
| 62 v_flag_ = false; |
| 63 |
| 64 // The sp is initialized to point to the bottom (high address) of the |
| 65 // allocated stack area. |
| 66 registers_[SP] = StackTop(); |
| 67 // The lr and pc are initialized to a known bad value that will cause an |
| 68 // access violation if the simulator ever tries to execute it. |
| 69 registers_[LR] = kBadLR; |
| 70 pc_ = kBadLR; |
| 71 } |
| 72 |
| 73 |
| 74 Simulator::~Simulator() { |
| 75 delete[] stack_; |
| 76 Isolate* isolate = Isolate::Current(); |
| 77 if (isolate != NULL) { |
| 78 isolate->set_simulator(NULL); |
| 79 } |
| 80 } |
| 81 |
| 82 |
| 83 // Get the active Simulator for the current isolate. |
| 84 Simulator* Simulator::Current() { |
| 85 Simulator* simulator = Isolate::Current()->simulator(); |
| 86 if (simulator == NULL) { |
| 87 simulator = new Simulator(); |
| 88 Isolate::Current()->set_simulator(simulator); |
| 89 } |
| 90 return simulator; |
| 91 } |
| 92 |
| 93 |
| 94 // Sets the register in the architecture state. |
| 95 void Simulator::set_register(Register reg, int64_t value, R31Type r31t) { |
| 96 // register is in range, and if it is R31, a mode is specified. |
| 97 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); |
| 98 ASSERT((reg != R31) || (r31t != R31IsUndef)); |
| 99 if ((reg != R31) || (r31t != R31IsZR)) { |
| 100 registers_[reg] = value; |
| 101 } |
| 102 } |
| 103 |
| 104 |
| 105 // Get the register from the architecture state. |
| 106 int64_t Simulator::get_register(Register reg, R31Type r31t) const { |
| 107 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); |
| 108 ASSERT((reg != R31) || (r31t != R31IsUndef)); |
| 109 if ((reg == R31) && (r31t == R31IsZR)) { |
| 110 return 0; |
| 111 } else { |
| 112 return registers_[reg]; |
| 113 } |
| 114 } |
| 115 |
| 116 |
| 117 void Simulator::set_wregister(Register reg, int32_t value, R31Type r31t) { |
| 118 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); |
| 119 ASSERT((reg != R31) || (r31t != R31IsUndef)); |
| 120 // When setting in W mode, clear the high bits. |
| 121 if ((reg != R31) || (r31t != R31IsZR)) { |
| 122 registers_[reg] = Utils::LowHighTo64Bits(static_cast<uint32_t>(value), 0); |
| 123 } |
| 124 } |
| 125 |
| 126 |
| 127 // Get the register from the architecture state. |
| 128 int32_t Simulator::get_wregister(Register reg, R31Type r31t) const { |
| 129 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); |
| 130 ASSERT((reg != R31) || (r31t != R31IsUndef)); |
| 131 if ((reg == R31) && (r31t == R31IsZR)) { |
| 132 return 0; |
| 133 } else { |
| 134 return registers_[reg]; |
| 135 } |
| 136 } |
| 137 |
| 138 |
| 139 // Raw access to the PC register. |
| 140 void Simulator::set_pc(int64_t value) { |
| 141 pc_modified_ = true; |
| 142 pc_ = value; |
| 143 } |
| 144 |
| 145 |
| 146 // Raw access to the PC register without the special adjustment when reading. |
| 147 int64_t Simulator::get_pc() const { |
| 148 return pc_; |
| 149 } |
| 150 |
| 151 |
| 152 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
| 153 uword fault_pc = get_pc(); |
| 154 // TODO(zra): drop into debugger. |
| 155 char buffer[128]; |
| 156 snprintf(buffer, sizeof(buffer), |
| 157 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", |
| 158 addr, fault_pc); |
| 159 // The debugger will return control in non-interactive mode. |
| 160 FATAL("Cannot continue execution after illegal memory access."); |
| 161 } |
| 162 |
| 163 |
| 164 void Simulator::UnimplementedInstruction(Instr* instr) { |
| 165 char buffer[64]; |
| 166 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); |
| 167 // TODO(zra): drop into debugger. |
| 168 FATAL("Cannot continue execution after unimplemented instruction."); |
| 169 } |
| 170 |
| 171 |
| 172 // Returns the top of the stack area to enable checking for stack pointer |
| 173 // validity. |
| 174 uword Simulator::StackTop() const { |
| 175 // To be safe in potential stack underflows we leave some buffer above and |
| 176 // set the stack top. |
| 177 return reinterpret_cast<uword>(stack_) + |
| 178 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); |
| 179 } |
| 180 |
| 181 |
| 182 // Unsupported instructions use Format to print an error and stop execution. |
| 183 void Simulator::Format(Instr* instr, const char* format) { |
| 184 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", |
| 185 instr, |
| 186 format); |
| 187 UNIMPLEMENTED(); |
| 188 } |
| 189 |
| 190 |
| 191 // Calculate and set the Negative and Zero flags. |
| 192 void Simulator::SetNZFlagsW(int32_t val) { |
| 193 n_flag_ = (val < 0); |
| 194 z_flag_ = (val == 0); |
| 195 } |
| 196 |
| 197 |
| 198 // Calculate C flag value for additions. |
| 199 bool Simulator::CarryFromW(int32_t left, int32_t right) { |
| 200 uint32_t uleft = static_cast<uint32_t>(left); |
| 201 uint32_t uright = static_cast<uint32_t>(right); |
| 202 uint32_t urest = 0xffffffffU - uleft; |
| 203 |
| 204 return (uright > urest); |
| 205 } |
| 206 |
| 207 |
| 208 // Calculate C flag value for subtractions. |
| 209 bool Simulator::BorrowFromW(int32_t left, int32_t right) { |
| 210 uint32_t uleft = static_cast<uint32_t>(left); |
| 211 uint32_t uright = static_cast<uint32_t>(right); |
| 212 |
| 213 return (uright > uleft); |
| 214 } |
| 215 |
| 216 |
| 217 // Calculate V flag value for additions and subtractions. |
| 218 bool Simulator::OverflowFromW(int32_t alu_out, |
| 219 int32_t left, int32_t right, bool addition) { |
| 220 bool overflow; |
| 221 if (addition) { |
| 222 // operands have the same sign |
| 223 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) |
| 224 // and operands and result have different sign |
| 225 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 226 } else { |
| 227 // operands have different signs |
| 228 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) |
| 229 // and first operand and result have different signs |
| 230 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 231 } |
| 232 return overflow; |
| 233 } |
| 234 |
| 235 |
| 236 // Calculate and set the Negative and Zero flags. |
| 237 void Simulator::SetNZFlagsX(int64_t val) { |
| 238 n_flag_ = (val < 0); |
| 239 z_flag_ = (val == 0); |
| 240 } |
| 241 |
| 242 |
| 243 // Calculate C flag value for additions. |
| 244 bool Simulator::CarryFromX(int64_t left, int64_t right) { |
| 245 uint64_t uleft = static_cast<uint64_t>(left); |
| 246 uint64_t uright = static_cast<uint64_t>(right); |
| 247 uint64_t urest = 0xffffffffffffffffULL - uleft; |
| 248 |
| 249 return (uright > urest); |
| 250 } |
| 251 |
| 252 |
| 253 // Calculate C flag value for subtractions. |
| 254 bool Simulator::BorrowFromX(int64_t left, int64_t right) { |
| 255 uint64_t uleft = static_cast<uint64_t>(left); |
| 256 uint64_t uright = static_cast<uint64_t>(right); |
| 257 |
| 258 return (uright > uleft); |
| 259 } |
| 260 |
| 261 |
| 262 // Calculate V flag value for additions and subtractions. |
| 263 bool Simulator::OverflowFromX(int64_t alu_out, |
| 264 int64_t left, int64_t right, bool addition) { |
| 265 bool overflow; |
| 266 if (addition) { |
| 267 // operands have the same sign |
| 268 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) |
| 269 // and operands and result have different sign |
| 270 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 271 } else { |
| 272 // operands have different signs |
| 273 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) |
| 274 // and first operand and result have different signs |
| 275 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
| 276 } |
| 277 return overflow; |
| 278 } |
| 279 |
| 280 |
| 281 // Set the Carry flag. |
| 282 void Simulator::SetCFlag(bool val) { |
| 283 c_flag_ = val; |
| 284 } |
| 285 |
| 286 |
| 287 // Set the oVerflow flag. |
| 288 void Simulator::SetVFlag(bool val) { |
| 289 v_flag_ = val; |
| 290 } |
| 291 |
| 292 |
| 293 void Simulator::DecodeMoveWide(Instr* instr) { |
| 294 UnimplementedInstruction(instr); |
| 295 } |
| 296 |
| 297 |
| 298 void Simulator::DecodeAddSubImm(Instr* instr) { |
| 299 switch (instr->Bit(30)) { |
| 300 case 0: { |
| 301 // Format(instr, "addi'sf's 'rd, 'rn, 'imm12s"); |
| 302 const Register rd = instr->RdField(); |
| 303 const Register rn = instr->RnField(); |
| 304 const uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12) |
| 305 : (instr->Imm12Field()); |
| 306 if (instr->SFField()) { |
| 307 // 64-bit add. |
| 308 const int64_t rn_val = get_register(rn, instr->RnMode()); |
| 309 const int64_t alu_out = rn_val + imm; |
| 310 set_register(rd, alu_out, instr->RdMode()); |
| 311 if (instr->HasS()) { |
| 312 SetNZFlagsX(alu_out); |
| 313 SetCFlag(CarryFromX(rn_val, imm)); |
| 314 SetVFlag(OverflowFromX(alu_out, rn_val, imm, true)); |
| 315 } |
| 316 } else { |
| 317 // 32-bit add. |
| 318 const int32_t rn_val = get_wregister(rn, instr->RnMode()); |
| 319 const int32_t alu_out = rn_val + imm; |
| 320 set_wregister(rd, alu_out, instr->RdMode()); |
| 321 if (instr->HasS()) { |
| 322 SetNZFlagsW(alu_out); |
| 323 SetCFlag(CarryFromW(rn_val, imm)); |
| 324 SetVFlag(OverflowFromW(alu_out, rn_val, imm, true)); |
| 325 } |
| 326 } |
| 327 break; |
| 328 } |
| 329 default: |
| 330 UnimplementedInstruction(instr); |
| 331 break; |
| 332 } |
| 333 } |
| 334 |
| 335 void Simulator::DecodeDPImmediate(Instr* instr) { |
| 336 if (instr->IsMoveWideOp()) { |
| 337 DecodeMoveWide(instr); |
| 338 } else if (instr->IsAddSubImmOp()) { |
| 339 DecodeAddSubImm(instr); |
| 340 } else { |
| 341 UnimplementedInstruction(instr); |
| 342 } |
| 343 } |
| 344 |
| 345 |
| 346 void Simulator::DecodeExceptionGen(Instr* instr) { |
| 347 UnimplementedInstruction(instr); |
| 348 } |
| 349 |
| 350 |
| 351 void Simulator::DecodeSystem(Instr* instr) { |
| 352 if ((instr->Bits(0, 8) == 0x5f) && (instr->Bits(12, 4) == 2) && |
| 353 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && |
| 354 (instr->Bit(21) == 0)) { |
| 355 if (instr->Bits(8, 4) == 0) { |
| 356 // Format(instr, "nop"); |
| 357 } else { |
| 358 UnimplementedInstruction(instr); |
| 359 } |
| 360 } else { |
| 361 UnimplementedInstruction(instr); |
| 362 } |
| 363 } |
| 364 |
| 365 |
| 366 void Simulator::DecodeUnconditionalBranchReg(Instr* instr) { |
| 367 if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 6) == 0) && |
| 368 (instr->Bits(16, 5) == 0x1f)) { |
| 369 switch (instr->Bits(21, 4)) { |
| 370 case 2: { |
| 371 // Format(instr, "ret 'rn"); |
| 372 const Register rn = instr->RnField(); |
| 373 const int64_t rn_val = get_register(rn, instr->RnMode()); |
| 374 set_pc(rn_val); |
| 375 break; |
| 376 } |
| 377 default: |
| 378 UnimplementedInstruction(instr); |
| 379 break; |
| 380 } |
| 381 } else { |
| 382 UnimplementedInstruction(instr); |
| 383 } |
| 384 } |
| 385 |
| 386 |
| 387 void Simulator::DecodeCompareBranch(Instr* instr) { |
| 388 if (instr->IsExceptionGenOp()) { |
| 389 DecodeExceptionGen(instr); |
| 390 } else if (instr->IsSystemOp()) { |
| 391 DecodeSystem(instr); |
| 392 } else if (instr->IsUnconditionalBranchRegOp()) { |
| 393 DecodeUnconditionalBranchReg(instr); |
| 394 } else { |
| 395 UnimplementedInstruction(instr); |
| 396 } |
| 397 } |
| 398 |
| 399 |
| 400 void Simulator::DecodeLoadStore(Instr* instr) { |
| 401 UnimplementedInstruction(instr); |
| 402 } |
| 403 |
| 404 |
| 405 int64_t Simulator::ShiftOperand(uint8_t reg_size, |
| 406 int64_t value, |
| 407 Shift shift_type, |
| 408 uint8_t amount) { |
| 409 if (amount == 0) { |
| 410 return value; |
| 411 } |
| 412 int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask; |
| 413 switch (shift_type) { |
| 414 case LSL: |
| 415 return (value << amount) & mask; |
| 416 case LSR: |
| 417 return static_cast<uint64_t>(value) >> amount; |
| 418 case ASR: { |
| 419 // Shift used to restore the sign. |
| 420 uint8_t s_shift = kXRegSizeInBits - reg_size; |
| 421 // Value with its sign restored. |
| 422 int64_t s_value = (value << s_shift) >> s_shift; |
| 423 return (s_value >> amount) & mask; |
| 424 } |
| 425 case ROR: { |
| 426 if (reg_size == kWRegSizeInBits) { |
| 427 value &= kWRegMask; |
| 428 } |
| 429 return (static_cast<uint64_t>(value) >> amount) | |
| 430 ((value & ((1L << amount) - 1L)) << (reg_size - amount)); |
| 431 } |
| 432 default: |
| 433 UNIMPLEMENTED(); |
| 434 return 0; |
| 435 } |
| 436 } |
| 437 |
| 438 |
| 439 int64_t Simulator::ExtendOperand(uint8_t reg_size, |
| 440 int64_t value, |
| 441 Extend extend_type, |
| 442 uint8_t amount) { |
| 443 switch (extend_type) { |
| 444 case UXTB: |
| 445 value &= 0xff; |
| 446 break; |
| 447 case UXTH: |
| 448 value &= 0xffff; |
| 449 break; |
| 450 case UXTW: |
| 451 value &= 0xffffffff; |
| 452 break; |
| 453 case SXTB: |
| 454 value = (value << 56) >> 56; |
| 455 break; |
| 456 case SXTH: |
| 457 value = (value << 48) >> 48; |
| 458 break; |
| 459 case SXTW: |
| 460 value = (value << 32) >> 32; |
| 461 break; |
| 462 case UXTX: |
| 463 case SXTX: |
| 464 break; |
| 465 default: |
| 466 UNREACHABLE(); |
| 467 } |
| 468 int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask; |
| 469 return (value << amount) & mask; |
| 470 } |
| 471 |
| 472 |
| 473 int64_t Simulator::DecodeShiftExtendOperand(Instr* instr) { |
| 474 const Register rm = instr->RmField(); |
| 475 const int64_t rm_val = get_register(rm, R31IsZR); |
| 476 const uint8_t size = instr->SFField() ? kXRegSizeInBits : kWRegSizeInBits; |
| 477 if (instr->IsShift()) { |
| 478 const Shift shift_type = instr->ShiftTypeField(); |
| 479 const uint8_t shift_amount = instr->Imm6Field(); |
| 480 return ShiftOperand(size, rm_val, shift_type, shift_amount); |
| 481 } else { |
| 482 ASSERT(instr->IsExtend()); |
| 483 const Extend extend_type = instr->ExtendTypeField(); |
| 484 const uint8_t shift_amount = instr->Imm3Field(); |
| 485 return ExtendOperand(size, rm_val, extend_type, shift_amount); |
| 486 } |
| 487 UNREACHABLE(); |
| 488 return -1; |
| 489 } |
| 490 |
| 491 |
| 492 void Simulator::DecodeAddSubShiftExt(Instr* instr) { |
| 493 switch (instr->Bit(30)) { |
| 494 case 0: { |
| 495 // Format(instr, "add'sf's 'rd, 'rn, 'shift_op"); |
| 496 const Register rd = instr->RdField(); |
| 497 const Register rn = instr->RnField(); |
| 498 const int64_t rm_val = DecodeShiftExtendOperand(instr); |
| 499 if (instr->SFField()) { |
| 500 // 64-bit add. |
| 501 const int64_t rn_val = get_register(rn, instr->RnMode()); |
| 502 const int64_t alu_out = rn_val + rm_val; |
| 503 set_register(rd, alu_out, instr->RdMode()); |
| 504 if (instr->HasS()) { |
| 505 SetNZFlagsX(alu_out); |
| 506 SetCFlag(CarryFromX(rn_val, rm_val)); |
| 507 SetVFlag(OverflowFromX(alu_out, rn_val, rm_val, true)); |
| 508 } |
| 509 } else { |
| 510 // 32-bit add. |
| 511 const int32_t rn_val = get_wregister(rn, instr->RnMode()); |
| 512 const int32_t rm_val32 = static_cast<int32_t>(rm_val & kWRegMask); |
| 513 const int32_t alu_out = rn_val + rm_val32; |
| 514 set_wregister(rd, alu_out, instr->RdMode()); |
| 515 if (instr->HasS()) { |
| 516 SetNZFlagsW(alu_out); |
| 517 SetCFlag(CarryFromW(rn_val, rm_val32)); |
| 518 SetVFlag(OverflowFromW(alu_out, rn_val, rm_val32, true)); |
| 519 } |
| 520 } |
| 521 break; |
| 522 } |
| 523 default: |
| 524 UnimplementedInstruction(instr); |
| 525 break; |
| 526 } |
| 527 } |
| 528 |
| 529 |
| 530 void Simulator::DecodeDPRegister(Instr* instr) { |
| 531 if (instr->IsAddSubShiftExtOp()) { |
| 532 DecodeAddSubShiftExt(instr); |
| 533 } else { |
| 534 UnimplementedInstruction(instr); |
| 535 } |
| 536 } |
| 537 |
| 538 |
| 539 void Simulator::DecodeDPSimd1(Instr* instr) { |
| 540 UnimplementedInstruction(instr); |
| 541 } |
| 542 |
| 543 |
| 544 void Simulator::DecodeDPSimd2(Instr* instr) { |
| 545 UnimplementedInstruction(instr); |
| 546 } |
| 547 |
| 548 |
| 549 // Executes the current instruction. |
| 550 void Simulator::InstructionDecode(Instr* instr) { |
| 551 pc_modified_ = false; |
| 552 if (FLAG_trace_sim) { |
| 553 const uword start = reinterpret_cast<uword>(instr); |
| 554 const uword end = start + Instr::kInstrSize; |
| 555 Disassembler::Disassemble(start, end); |
| 556 } |
| 557 |
| 558 if (instr->IsDPImmediateOp()) { |
| 559 DecodeDPImmediate(instr); |
| 560 } else if (instr->IsCompareBranchOp()) { |
| 561 DecodeCompareBranch(instr); |
| 562 } else if (instr->IsLoadStoreOp()) { |
| 563 DecodeLoadStore(instr); |
| 564 } else if (instr->IsDPRegisterOp()) { |
| 565 DecodeDPRegister(instr); |
| 566 } else if (instr->IsDPSimd1Op()) { |
| 567 DecodeDPSimd1(instr); |
| 568 } else { |
| 569 ASSERT(instr->IsDPSimd2Op()); |
| 570 DecodeDPSimd2(instr); |
| 571 } |
| 572 |
| 573 if (!pc_modified_) { |
| 574 set_pc(reinterpret_cast<int64_t>(instr) + Instr::kInstrSize); |
| 575 } |
| 576 } |
| 577 |
| 578 |
| 579 void Simulator::Execute() { |
| 580 // Get the PC to simulate. Cannot use the accessor here as we need the |
| 581 // raw PC value and not the one used as input to arithmetic instructions. |
| 582 uword program_counter = get_pc(); |
| 583 |
| 584 if (FLAG_stop_sim_at == 0) { |
| 585 // Fast version of the dispatch loop without checking whether the simulator |
| 586 // should be stopping at a particular executed instruction. |
| 587 while (program_counter != kEndSimulatingPC) { |
| 588 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 589 icount_++; |
| 590 if (IsIllegalAddress(program_counter)) { |
| 591 HandleIllegalAccess(program_counter, instr); |
| 592 } else { |
| 593 InstructionDecode(instr); |
| 594 } |
| 595 program_counter = get_pc(); |
| 596 } |
| 597 } else { |
| 598 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
| 599 // we reach the particular instruction count. |
| 600 while (program_counter != kEndSimulatingPC) { |
| 601 Instr* instr = reinterpret_cast<Instr*>(program_counter); |
| 602 icount_++; |
| 603 if (icount_ == FLAG_stop_sim_at) { |
| 604 // TODO(zra): Add a debugger. |
| 605 UNIMPLEMENTED(); |
| 606 } else if (IsIllegalAddress(program_counter)) { |
| 607 HandleIllegalAccess(program_counter, instr); |
| 608 } else { |
| 609 InstructionDecode(instr); |
| 610 } |
| 611 program_counter = get_pc(); |
| 612 } |
| 613 } |
| 614 } |
| 615 |
| 616 |
| 617 int64_t Simulator::Call(int64_t entry, |
| 618 int64_t parameter0, |
| 619 int64_t parameter1, |
| 620 int64_t parameter2, |
| 621 int64_t parameter3) { |
| 622 // Save the SP register before the call so we can restore it. |
| 623 int32_t sp_before_call = get_register(SP, R31IsSP); |
| 624 |
| 625 // Setup parameters. |
| 626 set_register(R0, parameter0); |
| 627 set_register(R1, parameter1); |
| 628 set_register(R2, parameter2); |
| 629 set_register(R3, parameter3); |
| 630 |
| 631 // Make sure the activation frames are properly aligned. |
| 632 int32_t stack_pointer = sp_before_call; |
| 633 if (OS::ActivationFrameAlignment() > 1) { |
| 634 stack_pointer = |
| 635 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment()); |
| 636 } |
| 637 set_register(SP, stack_pointer, R31IsSP); |
| 638 |
| 639 // Prepare to execute the code at entry. |
| 640 set_pc(entry); |
| 641 // Put down marker for end of simulation. The simulator will stop simulation |
| 642 // when the PC reaches this value. By saving the "end simulation" value into |
| 643 // the LR the simulation stops when returning to this call point. |
| 644 set_register(LR, kEndSimulatingPC); |
| 645 |
| 646 // Remember the values of callee-saved registers. |
| 647 int64_t r19_val = get_register(R19); |
| 648 int64_t r20_val = get_register(R20); |
| 649 int64_t r21_val = get_register(R21); |
| 650 int64_t r22_val = get_register(R22); |
| 651 int64_t r23_val = get_register(R23); |
| 652 int64_t r24_val = get_register(R24); |
| 653 int64_t r25_val = get_register(R25); |
| 654 int64_t r26_val = get_register(R26); |
| 655 int64_t r27_val = get_register(R27); |
| 656 int64_t r28_val = get_register(R28); |
| 657 int64_t r29_val = get_register(R29); |
| 658 |
| 659 // Setup the callee-saved registers with a known value. To be able to check |
| 660 // that they are preserved properly across dart execution. |
| 661 int64_t callee_saved_value = icount_; |
| 662 set_register(R19, callee_saved_value); |
| 663 set_register(R20, callee_saved_value); |
| 664 set_register(R21, callee_saved_value); |
| 665 set_register(R22, callee_saved_value); |
| 666 set_register(R23, callee_saved_value); |
| 667 set_register(R24, callee_saved_value); |
| 668 set_register(R25, callee_saved_value); |
| 669 set_register(R26, callee_saved_value); |
| 670 set_register(R27, callee_saved_value); |
| 671 set_register(R28, callee_saved_value); |
| 672 set_register(R29, callee_saved_value); |
| 673 |
| 674 // Start the simulation |
| 675 Execute(); |
| 676 |
| 677 // Check that the callee-saved registers have been preserved. |
| 678 ASSERT(callee_saved_value == get_register(R19)); |
| 679 ASSERT(callee_saved_value == get_register(R20)); |
| 680 ASSERT(callee_saved_value == get_register(R21)); |
| 681 ASSERT(callee_saved_value == get_register(R22)); |
| 682 ASSERT(callee_saved_value == get_register(R23)); |
| 683 ASSERT(callee_saved_value == get_register(R24)); |
| 684 ASSERT(callee_saved_value == get_register(R25)); |
| 685 ASSERT(callee_saved_value == get_register(R26)); |
| 686 ASSERT(callee_saved_value == get_register(R27)); |
| 687 ASSERT(callee_saved_value == get_register(R28)); |
| 688 ASSERT(callee_saved_value == get_register(R29)); |
| 689 |
| 690 // Restore callee-saved registers with the original value. |
| 691 set_register(R19, r19_val); |
| 692 set_register(R20, r20_val); |
| 693 set_register(R21, r21_val); |
| 694 set_register(R22, r22_val); |
| 695 set_register(R23, r23_val); |
| 696 set_register(R24, r24_val); |
| 697 set_register(R25, r25_val); |
| 698 set_register(R26, r26_val); |
| 699 set_register(R27, r27_val); |
| 700 set_register(R28, r28_val); |
| 701 set_register(R29, r29_val); |
| 702 |
| 703 // Restore the SP register and return R1:R0. |
| 704 set_register(SP, sp_before_call, R31IsSP); |
| 705 int64_t return_value; |
| 706 return_value = get_register(R0); |
| 707 return return_value; |
| 708 } |
| 709 |
| 710 } // namespace dart |
| 711 |
| 712 #endif // !defined(HOST_ARCH_ARM64) |
| 713 |
| 714 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |