| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 <math.h> // for isnan. | 5 #include <math.h> // for isnan. |
| 6 #include <setjmp.h> | 6 #include <setjmp.h> |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 | 8 |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #if defined(TARGET_ARCH_ARM64) | 10 #if defined(TARGET_ARCH_ARM64) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 56 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 57 registers_[i] = 0; | 57 registers_[i] = 0; |
| 58 } | 58 } |
| 59 n_flag_ = false; | 59 n_flag_ = false; |
| 60 z_flag_ = false; | 60 z_flag_ = false; |
| 61 c_flag_ = false; | 61 c_flag_ = false; |
| 62 v_flag_ = false; | 62 v_flag_ = false; |
| 63 | 63 |
| 64 // The sp is initialized to point to the bottom (high address) of the | 64 // The sp is initialized to point to the bottom (high address) of the |
| 65 // allocated stack area. | 65 // allocated stack area. |
| 66 registers_[SP] = StackTop(); | 66 registers_[R31] = StackTop(); |
| 67 // The lr and pc are initialized to a known bad value that will cause an | 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. | 68 // access violation if the simulator ever tries to execute it. |
| 69 registers_[LR] = kBadLR; | 69 registers_[LR] = kBadLR; |
| 70 pc_ = kBadLR; | 70 pc_ = kBadLR; |
| 71 } | 71 } |
| 72 | 72 |
| 73 | 73 |
| 74 Simulator::~Simulator() { | 74 Simulator::~Simulator() { |
| 75 delete[] stack_; | 75 delete[] stack_; |
| 76 Isolate* isolate = Isolate::Current(); | 76 Isolate* isolate = Isolate::Current(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 // TODO(zra): drop into debugger. | 154 // TODO(zra): drop into debugger. |
| 155 char buffer[128]; | 155 char buffer[128]; |
| 156 snprintf(buffer, sizeof(buffer), | 156 snprintf(buffer, sizeof(buffer), |
| 157 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", | 157 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", |
| 158 addr, fault_pc); | 158 addr, fault_pc); |
| 159 // The debugger will return control in non-interactive mode. | 159 // The debugger will return control in non-interactive mode. |
| 160 FATAL("Cannot continue execution after illegal memory access."); | 160 FATAL("Cannot continue execution after illegal memory access."); |
| 161 } | 161 } |
| 162 | 162 |
| 163 | 163 |
| 164 // The ARMv8 manual advises that an unaligned access may generate a fault, |
| 165 // and if not, will likely take a number of additional cycles to execute, |
| 166 // so let's just not generate any. |
| 167 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { |
| 168 char buffer[64]; |
| 169 snprintf(buffer, sizeof(buffer), |
| 170 "unaligned %s at 0x%" Px ", pc=%p\n", msg, addr, instr); |
| 171 // TODO(zra): Drop into the simulator debugger when it exists. |
| 172 // The debugger will not be able to single step past this instruction, but |
| 173 // it will be possible to disassemble the code and inspect registers. |
| 174 FATAL("Cannot continue execution after unaligned access."); |
| 175 } |
| 176 |
| 177 |
| 164 void Simulator::UnimplementedInstruction(Instr* instr) { | 178 void Simulator::UnimplementedInstruction(Instr* instr) { |
| 165 char buffer[64]; | 179 char buffer[64]; |
| 166 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); | 180 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); |
| 167 // TODO(zra): drop into debugger. | 181 // TODO(zra): drop into debugger. |
| 168 FATAL("Cannot continue execution after unimplemented instruction."); | 182 FATAL("Cannot continue execution after unimplemented instruction."); |
| 169 } | 183 } |
| 170 | 184 |
| 171 | 185 |
| 172 // Returns the top of the stack area to enable checking for stack pointer | 186 // Returns the top of the stack area to enable checking for stack pointer |
| 173 // validity. | 187 // validity. |
| 174 uword Simulator::StackTop() const { | 188 uword Simulator::StackTop() const { |
| 175 // To be safe in potential stack underflows we leave some buffer above and | 189 // To be safe in potential stack underflows we leave some buffer above and |
| 176 // set the stack top. | 190 // set the stack top. |
| 177 return reinterpret_cast<uword>(stack_) + | 191 return reinterpret_cast<uword>(stack_) + |
| 178 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); | 192 (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer); |
| 179 } | 193 } |
| 180 | 194 |
| 181 | 195 |
| 196 intptr_t Simulator::ReadX(uword addr, Instr* instr) { |
| 197 if ((addr & 7) == 0) { |
| 198 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 199 return *ptr; |
| 200 } |
| 201 UnalignedAccess("read", addr, instr); |
| 202 return 0; |
| 203 } |
| 204 |
| 205 |
| 206 void Simulator::WriteX(uword addr, intptr_t value, Instr* instr) { |
| 207 if ((addr & 7) == 0) { |
| 208 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 209 *ptr = value; |
| 210 return; |
| 211 } |
| 212 UnalignedAccess("write", addr, instr); |
| 213 } |
| 214 |
| 215 |
| 216 uint32_t Simulator::ReadWU(uword addr, Instr* instr) { |
| 217 if ((addr & 3) == 0) { |
| 218 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
| 219 return *ptr; |
| 220 } |
| 221 UnalignedAccess("read unsigned single word", addr, instr); |
| 222 return 0; |
| 223 } |
| 224 |
| 225 |
| 226 int32_t Simulator::ReadW(uword addr, Instr* instr) { |
| 227 if ((addr & 3) == 0) { |
| 228 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
| 229 return *ptr; |
| 230 } |
| 231 UnalignedAccess("read single word", addr, instr); |
| 232 return 0; |
| 233 } |
| 234 |
| 235 |
| 236 void Simulator::WriteW(uword addr, uint32_t value, Instr* instr) { |
| 237 if ((addr & 3) == 0) { |
| 238 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
| 239 *ptr = value; |
| 240 return; |
| 241 } |
| 242 UnalignedAccess("write single word", addr, instr); |
| 243 } |
| 244 |
| 245 |
| 246 uint16_t Simulator::ReadHU(uword addr, Instr* instr) { |
| 247 if ((addr & 1) == 0) { |
| 248 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 249 return *ptr; |
| 250 } |
| 251 UnalignedAccess("unsigned halfword read", addr, instr); |
| 252 return 0; |
| 253 } |
| 254 |
| 255 |
| 256 int16_t Simulator::ReadH(uword addr, Instr* instr) { |
| 257 if ((addr & 1) == 0) { |
| 258 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 259 return *ptr; |
| 260 } |
| 261 UnalignedAccess("signed halfword read", addr, instr); |
| 262 return 0; |
| 263 } |
| 264 |
| 265 |
| 266 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) { |
| 267 if ((addr & 1) == 0) { |
| 268 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 269 *ptr = value; |
| 270 return; |
| 271 } |
| 272 UnalignedAccess("halfword write", addr, instr); |
| 273 } |
| 274 |
| 275 |
| 276 uint8_t Simulator::ReadBU(uword addr) { |
| 277 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 278 return *ptr; |
| 279 } |
| 280 |
| 281 |
| 282 int8_t Simulator::ReadB(uword addr) { |
| 283 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 284 return *ptr; |
| 285 } |
| 286 |
| 287 |
| 288 void Simulator::WriteB(uword addr, uint8_t value) { |
| 289 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 290 *ptr = value; |
| 291 } |
| 292 |
| 293 |
| 182 // Unsupported instructions use Format to print an error and stop execution. | 294 // Unsupported instructions use Format to print an error and stop execution. |
| 183 void Simulator::Format(Instr* instr, const char* format) { | 295 void Simulator::Format(Instr* instr, const char* format) { |
| 184 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", | 296 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", |
| 185 instr, | 297 instr, |
| 186 format); | 298 format); |
| 187 UNIMPLEMENTED(); | 299 UNIMPLEMENTED(); |
| 188 } | 300 } |
| 189 | 301 |
| 190 | 302 |
| 191 // Calculate and set the Negative and Zero flags. | 303 // Calculate and set the Negative and Zero flags. |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 } else if (instr->IsSystemOp()) { | 535 } else if (instr->IsSystemOp()) { |
| 424 DecodeSystem(instr); | 536 DecodeSystem(instr); |
| 425 } else if (instr->IsUnconditionalBranchRegOp()) { | 537 } else if (instr->IsUnconditionalBranchRegOp()) { |
| 426 DecodeUnconditionalBranchReg(instr); | 538 DecodeUnconditionalBranchReg(instr); |
| 427 } else { | 539 } else { |
| 428 UnimplementedInstruction(instr); | 540 UnimplementedInstruction(instr); |
| 429 } | 541 } |
| 430 } | 542 } |
| 431 | 543 |
| 432 | 544 |
| 545 void Simulator::DecodeLoadStoreReg(Instr* instr) { |
| 546 // TODO(zra): SIMD loads and stores have bit 26 (V) set. |
| 547 // (bit 25 is never set for loads and stores). |
| 548 if (instr->Bits(25, 2) != 0) { |
| 549 UnimplementedInstruction(instr); |
| 550 return; |
| 551 } |
| 552 |
| 553 // Calculate the address. |
| 554 const Register rn = instr->RnField(); |
| 555 const Register rt = instr->RtField(); |
| 556 const int64_t rn_val = get_register(rn, R31IsSP); |
| 557 const uint32_t size = instr->SzField(); |
| 558 uword address = 0; |
| 559 uword wb_address = 0; |
| 560 bool wb = false; |
| 561 if (instr->Bit(24) == 1) { |
| 562 // addr = rn + scaled unsigned 12-bit immediate offset. |
| 563 const uint32_t imm12 = static_cast<uint32_t>(instr->Imm12Field()); |
| 564 const uint32_t offset = imm12 << size; |
| 565 address = rn_val + offset; |
| 566 } else if (instr->Bit(10) == 1) { |
| 567 // addr = rn + signed 9-bit immediate offset. |
| 568 wb = true; |
| 569 const int64_t offset = static_cast<int64_t>(instr->SImm9Field()); |
| 570 if (instr->Bit(11) == 1) { |
| 571 // Pre-index. |
| 572 address = rn_val + offset; |
| 573 wb_address = address; |
| 574 } else { |
| 575 // Post-index. |
| 576 address = rn_val; |
| 577 wb_address = rn_val + offset; |
| 578 } |
| 579 } else if (instr->Bits(10, 2) == 2) { |
| 580 // addr = rn + (rm EXT optionally scaled by operand instruction size). |
| 581 const Register rm = instr->RmField(); |
| 582 const Extend ext = instr->ExtendTypeField(); |
| 583 const uint8_t scale = |
| 584 (ext == UXTX) && (instr->Bit(12) == 1) ? size : 0; |
| 585 const int64_t rm_val = get_register(rm, R31IsZR); |
| 586 const int64_t offset = ExtendOperand(kXRegSizeInBits, rm_val, ext, scale); |
| 587 address = rn_val + offset; |
| 588 } else { |
| 589 UnimplementedInstruction(instr); |
| 590 } |
| 591 |
| 592 // Check the address. |
| 593 if (IsIllegalAddress(address)) { |
| 594 HandleIllegalAccess(address, instr); |
| 595 return; |
| 596 } |
| 597 |
| 598 // Do access. |
| 599 if (instr->Bits(22, 2) == 0) { |
| 600 // Format(instr, "str'sz 'rt, 'memop"); |
| 601 int32_t rt_val32 = get_wregister(rt, R31IsZR); |
| 602 switch (size) { |
| 603 case 0: { |
| 604 uint8_t val = static_cast<uint8_t>(rt_val32); |
| 605 WriteB(address, val); |
| 606 break; |
| 607 } |
| 608 case 1: { |
| 609 uint16_t val = static_cast<uint16_t>(rt_val32); |
| 610 WriteH(address, val, instr); |
| 611 break; |
| 612 } |
| 613 case 2: { |
| 614 uint32_t val = static_cast<uint32_t>(rt_val32); |
| 615 WriteW(address, val, instr); |
| 616 break; |
| 617 } |
| 618 case 3: { |
| 619 int64_t val = get_register(rt, R31IsZR); |
| 620 WriteX(address, val, instr); |
| 621 break; |
| 622 } |
| 623 default: |
| 624 UNREACHABLE(); |
| 625 break; |
| 626 } |
| 627 } else { |
| 628 // Format(instr, "ldr'sz 'rt, 'memop"); |
| 629 // Undefined case. |
| 630 if ((size == 3) && (instr->Bits(22, 0) == 3)) { |
| 631 UnimplementedInstruction(instr); |
| 632 return; |
| 633 } |
| 634 |
| 635 // Read the value. |
| 636 const bool signd = instr->Bit(23) == 1; |
| 637 // Write the W register for signed values when size < 2. |
| 638 // Write the W register for unsigned values when size == 2. |
| 639 const bool use_w = |
| 640 (signd && (instr->Bit(22) == 1)) || (!signd && (size == 2)); |
| 641 int64_t val = 0; // Sign extend into an int64_t. |
| 642 switch (size) { |
| 643 case 0: { |
| 644 if (signd) { |
| 645 val = static_cast<int64_t>(ReadB(address)); |
| 646 } else { |
| 647 val = static_cast<int64_t>(ReadBU(address)); |
| 648 } |
| 649 break; |
| 650 } |
| 651 case 1: { |
| 652 if (signd) { |
| 653 val = static_cast<int64_t>(ReadH(address, instr)); |
| 654 } else { |
| 655 val = static_cast<int64_t>(ReadHU(address, instr)); |
| 656 } |
| 657 break; |
| 658 } |
| 659 case 2: { |
| 660 if (signd) { |
| 661 val = static_cast<int64_t>(ReadW(address, instr)); |
| 662 } else { |
| 663 val = static_cast<int64_t>(ReadWU(address, instr)); |
| 664 } |
| 665 break; |
| 666 } |
| 667 case 3: |
| 668 val = ReadX(address, instr); |
| 669 break; |
| 670 default: |
| 671 UNREACHABLE(); |
| 672 break; |
| 673 } |
| 674 |
| 675 // Write to register. |
| 676 if (use_w) { |
| 677 set_wregister(rt, static_cast<int32_t>(val), R31IsZR); |
| 678 } else { |
| 679 set_register(rt, val, R31IsZR); |
| 680 } |
| 681 } |
| 682 |
| 683 // Do writeback. |
| 684 if (wb) { |
| 685 set_register(rn, wb_address, R31IsSP); |
| 686 } |
| 687 } |
| 688 |
| 689 |
| 433 void Simulator::DecodeLoadStore(Instr* instr) { | 690 void Simulator::DecodeLoadStore(Instr* instr) { |
| 434 UnimplementedInstruction(instr); | 691 if (instr->IsLoadStoreRegOp()) { |
| 692 DecodeLoadStoreReg(instr); |
| 693 } else { |
| 694 UnimplementedInstruction(instr); |
| 695 } |
| 435 } | 696 } |
| 436 | 697 |
| 437 | 698 |
| 438 int64_t Simulator::ShiftOperand(uint8_t reg_size, | 699 int64_t Simulator::ShiftOperand(uint8_t reg_size, |
| 439 int64_t value, | 700 int64_t value, |
| 440 Shift shift_type, | 701 Shift shift_type, |
| 441 uint8_t amount) { | 702 uint8_t amount) { |
| 442 if (amount == 0) { | 703 if (amount == 0) { |
| 443 return value; | 704 return value; |
| 444 } | 705 } |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 } | 907 } |
| 647 } | 908 } |
| 648 | 909 |
| 649 | 910 |
| 650 int64_t Simulator::Call(int64_t entry, | 911 int64_t Simulator::Call(int64_t entry, |
| 651 int64_t parameter0, | 912 int64_t parameter0, |
| 652 int64_t parameter1, | 913 int64_t parameter1, |
| 653 int64_t parameter2, | 914 int64_t parameter2, |
| 654 int64_t parameter3) { | 915 int64_t parameter3) { |
| 655 // Save the SP register before the call so we can restore it. | 916 // Save the SP register before the call so we can restore it. |
| 656 int32_t sp_before_call = get_register(SP, R31IsSP); | 917 intptr_t sp_before_call = get_register(R31, R31IsSP); |
| 657 | 918 |
| 658 // Setup parameters. | 919 // Setup parameters. |
| 659 set_register(R0, parameter0); | 920 set_register(R0, parameter0); |
| 660 set_register(R1, parameter1); | 921 set_register(R1, parameter1); |
| 661 set_register(R2, parameter2); | 922 set_register(R2, parameter2); |
| 662 set_register(R3, parameter3); | 923 set_register(R3, parameter3); |
| 663 | 924 |
| 664 // Make sure the activation frames are properly aligned. | 925 // Make sure the activation frames are properly aligned. |
| 665 int32_t stack_pointer = sp_before_call; | 926 intptr_t stack_pointer = sp_before_call; |
| 666 if (OS::ActivationFrameAlignment() > 1) { | 927 if (OS::ActivationFrameAlignment() > 1) { |
| 667 stack_pointer = | 928 stack_pointer = |
| 668 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment()); | 929 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment()); |
| 669 } | 930 } |
| 670 set_register(SP, stack_pointer, R31IsSP); | 931 set_register(R31, stack_pointer, R31IsSP); |
| 671 | 932 |
| 672 // Prepare to execute the code at entry. | 933 // Prepare to execute the code at entry. |
| 673 set_pc(entry); | 934 set_pc(entry); |
| 674 // Put down marker for end of simulation. The simulator will stop simulation | 935 // Put down marker for end of simulation. The simulator will stop simulation |
| 675 // when the PC reaches this value. By saving the "end simulation" value into | 936 // when the PC reaches this value. By saving the "end simulation" value into |
| 676 // the LR the simulation stops when returning to this call point. | 937 // the LR the simulation stops when returning to this call point. |
| 677 set_register(LR, kEndSimulatingPC); | 938 set_register(LR, kEndSimulatingPC); |
| 678 | 939 |
| 679 // Remember the values of callee-saved registers. | 940 // Remember the values of callee-saved registers. |
| 680 int64_t r19_val = get_register(R19); | 941 int64_t r19_val = get_register(R19); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 set_register(R22, r22_val); | 988 set_register(R22, r22_val); |
| 728 set_register(R23, r23_val); | 989 set_register(R23, r23_val); |
| 729 set_register(R24, r24_val); | 990 set_register(R24, r24_val); |
| 730 set_register(R25, r25_val); | 991 set_register(R25, r25_val); |
| 731 set_register(R26, r26_val); | 992 set_register(R26, r26_val); |
| 732 set_register(R27, r27_val); | 993 set_register(R27, r27_val); |
| 733 set_register(R28, r28_val); | 994 set_register(R28, r28_val); |
| 734 set_register(R29, r29_val); | 995 set_register(R29, r29_val); |
| 735 | 996 |
| 736 // Restore the SP register and return R1:R0. | 997 // Restore the SP register and return R1:R0. |
| 737 set_register(SP, sp_before_call, R31IsSP); | 998 set_register(R31, sp_before_call, R31IsSP); |
| 738 int64_t return_value; | 999 int64_t return_value; |
| 739 return_value = get_register(R0); | 1000 return_value = get_register(R0); |
| 740 return return_value; | 1001 return return_value; |
| 741 } | 1002 } |
| 742 | 1003 |
| 743 } // namespace dart | 1004 } // namespace dart |
| 744 | 1005 |
| 745 #endif // !defined(HOST_ARCH_ARM64) | 1006 #endif // !defined(HOST_ARCH_ARM64) |
| 746 | 1007 |
| 747 #endif // defined TARGET_ARCH_ARM64 | 1008 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |