| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 // shell when hit. | 426 // shell when hit. |
| 427 RedoBreakpoints(); | 427 RedoBreakpoints(); |
| 428 | 428 |
| 429 #undef COMMAND_SIZE | 429 #undef COMMAND_SIZE |
| 430 #undef ARG_SIZE | 430 #undef ARG_SIZE |
| 431 | 431 |
| 432 #undef STR | 432 #undef STR |
| 433 #undef XSTR | 433 #undef XSTR |
| 434 } | 434 } |
| 435 | 435 |
| 436 static const int kICachePageSize = 0x1000; |
| 437 static const int kICachePageMask = 0xfff; |
| 438 static const int kICachePageShift = 12; |
| 439 static const int kICacheLineLength = 4; |
| 440 static const int kICacheLineMask = 3; |
| 441 static const int kPageSpace = kICachePageSize |
| 442 + kICachePageSize / kICacheLineLength; |
| 443 |
| 444 |
| 445 static bool ICacheMatch(void* one, void* two) { |
| 446 ASSERT((reinterpret_cast<intptr_t>(one) & kICachePageMask) == 0); |
| 447 return one == two; |
| 448 } |
| 449 |
| 450 |
| 451 static uint32_t ICacheHash(void* key) { |
| 452 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2; |
| 453 } |
| 454 |
| 455 |
| 456 static char* CacheValid(char* cache_page, int offset) { |
| 457 return &cache_page[kICachePageSize + offset / kICacheLineLength]; |
| 458 } |
| 459 |
| 460 |
| 461 static bool AllOnOnePage(uintptr_t start, int size) { |
| 462 intptr_t start_page = (start & ~kICachePageMask); |
| 463 intptr_t end_page = ((start + size) & ~kICachePageMask); |
| 464 return start_page == end_page; |
| 465 } |
| 466 |
| 467 |
| 468 void Simulator::FlushICache(void* start_addr, size_t size) { |
| 469 intptr_t start = reinterpret_cast<intptr_t>(start_addr); |
| 470 int intra_line = (start & kICacheLineMask); |
| 471 start -= intra_line; |
| 472 size += intra_line; |
| 473 size = ((size - 1) | kICacheLineMask) + 1; |
| 474 int offset = (start & kICachePageMask); |
| 475 while (!AllOnOnePage(start, size - 1)) { |
| 476 int bytes_to_flush = kICachePageSize - offset; |
| 477 FlushOnePage(start, bytes_to_flush); |
| 478 start += bytes_to_flush; |
| 479 size -= bytes_to_flush; |
| 480 ASSERT_EQ(0, start & kICachePageMask); |
| 481 offset = 0; |
| 482 } |
| 483 if (size != 0) { |
| 484 FlushOnePage(start, size); |
| 485 } |
| 486 } |
| 487 |
| 488 |
| 489 char* Simulator::GetCachePage(void* page) { |
| 490 v8::internal::HashMap::Entry* entry = i_cache_.Lookup(page, |
| 491 ICacheHash(page), |
| 492 true); |
| 493 if (entry->value == NULL) { |
| 494 char* new_page = new char[kPageSpace]; |
| 495 // Set the ICache to invalid for the new pages. |
| 496 memset(new_page, 1, kPageSpace); |
| 497 entry->value = new_page; |
| 498 // printf("New cache allocated from %p to %p\n", |
| 499 // (void*)(new_page), (void*)(new_page + kPageSpace)); |
| 500 } |
| 501 return reinterpret_cast<char*>(entry->value); |
| 502 } |
| 503 |
| 504 |
| 505 // Flush from start up to and not including start + size. |
| 506 void Simulator::FlushOnePage(intptr_t start, int size) { |
| 507 // printf("Flushing icache from %p to %p\n", |
| 508 // (void*)start, (void*)(start + size)); |
| 509 ASSERT(size <= kICachePageSize); |
| 510 ASSERT(AllOnOnePage(start, size - 1)); |
| 511 ASSERT((start & kICacheLineMask) == 0); |
| 512 ASSERT((size & kICacheLineMask) == 0); |
| 513 void* page = reinterpret_cast<void*>(start & (~kICachePageMask)); |
| 514 int offset = (start & kICachePageMask); |
| 515 char* cache_page = GetCachePage(page); |
| 516 char* valid_bytemap = CacheValid(cache_page, offset); |
| 517 // printf("Zero bytes from %p to %p\n", (void*)valid_bytemap, |
| 518 // (void*)(valid_bytemap + size / kICacheLineLength)); |
| 519 memset(valid_bytemap, 0, size / kICacheLineLength); |
| 520 } |
| 521 |
| 522 |
| 523 void Simulator::CheckICache(Instr* instr) { |
| 524 intptr_t address = reinterpret_cast<intptr_t>(instr); |
| 525 void* page = reinterpret_cast<void*>(address & (~kICachePageMask)); |
| 526 void* line = reinterpret_cast<void*>(address & (~kICacheLineMask)); |
| 527 int offset = (address & kICachePageMask); |
| 528 char* cache_page = GetCachePage(page); |
| 529 char* cache_valid_byte = CacheValid(cache_page, offset); |
| 530 bool cache_hit = (*cache_valid_byte != 0); |
| 531 char* cached_insn = cache_page + (offset & ~kICacheLineMask); |
| 532 if (cache_hit) { |
| 533 // Check that the data in memory matches the contents of the I-cache. |
| 534 // printf("Checked cache byte at %p\n", (void*)cache_valid_byte); |
| 535 // printf("Check instructions in cache for %p from %p to %p\n", |
| 536 // (void*)instr, (void*)cached_insn, |
| 537 // (void*)(cached_insn + kICacheLineLength)); |
| 538 CHECK(memcmp(reinterpret_cast<void*>(instr), |
| 539 cache_page + offset, |
| 540 Instr::kInstrSize) == 0); |
| 541 } { |
| 542 // Cache miss. Load memory into the cache. |
| 543 // printf("Set instructions in cache for %p from %p to %p\n", |
| 544 // (void*)instr, (void*)cached_insn, |
| 545 // (void*)(cached_insn + kICacheLineLength)); |
| 546 memcpy(cached_insn, line, Instr::kInstrSize); |
| 547 // printf("Set cache byte at %p\n", (void*)cache_valid_byte); |
| 548 *cache_valid_byte = 1; |
| 549 } |
| 550 } |
| 551 |
| 436 | 552 |
| 437 // Create one simulator per thread and keep it in thread local storage. | 553 // Create one simulator per thread and keep it in thread local storage. |
| 438 static v8::internal::Thread::LocalStorageKey simulator_key; | 554 static v8::internal::Thread::LocalStorageKey simulator_key; |
| 439 | 555 |
| 440 | 556 |
| 441 bool Simulator::initialized_ = false; | 557 bool Simulator::initialized_ = false; |
| 442 | 558 |
| 443 | 559 |
| 444 void Simulator::Initialize() { | 560 void Simulator::Initialize() { |
| 445 if (initialized_) return; | 561 if (initialized_) return; |
| 446 simulator_key = v8::internal::Thread::CreateThreadLocalKey(); | 562 simulator_key = v8::internal::Thread::CreateThreadLocalKey(); |
| 447 initialized_ = true; | 563 initialized_ = true; |
| 448 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); | 564 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); |
| 449 } | 565 } |
| 450 | 566 |
| 451 | 567 |
| 452 Simulator::Simulator() { | 568 Simulator::Simulator() : i_cache_(&ICacheMatch) { |
| 453 Initialize(); | 569 Initialize(); |
| 454 // Setup simulator support first. Some of this information is needed to | 570 // Setup simulator support first. Some of this information is needed to |
| 455 // setup the architecture state. | 571 // setup the architecture state. |
| 456 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack | 572 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
| 457 stack_ = reinterpret_cast<char*>(malloc(stack_size)); | 573 stack_ = reinterpret_cast<char*>(malloc(stack_size)); |
| 458 pc_modified_ = false; | 574 pc_modified_ = false; |
| 459 icount_ = 0; | 575 icount_ = 0; |
| 460 break_pc_ = NULL; | 576 break_pc_ = NULL; |
| 461 break_instr_ = 0; | 577 break_instr_ = 0; |
| 462 | 578 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 // reference to a swi (software-interrupt) instruction that is handled by | 623 // reference to a swi (software-interrupt) instruction that is handled by |
| 508 // the simulator. We write the original destination of the jump just at a known | 624 // the simulator. We write the original destination of the jump just at a known |
| 509 // offset from the swi instruction so the simulator knows what to call. | 625 // offset from the swi instruction so the simulator knows what to call. |
| 510 class Redirection { | 626 class Redirection { |
| 511 public: | 627 public: |
| 512 Redirection(void* external_function, bool fp_return) | 628 Redirection(void* external_function, bool fp_return) |
| 513 : external_function_(external_function), | 629 : external_function_(external_function), |
| 514 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), | 630 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), |
| 515 fp_return_(fp_return), | 631 fp_return_(fp_return), |
| 516 next_(list_) { | 632 next_(list_) { |
| 633 assembler::arm::Simulator::current()-> |
| 634 FlushICache(reinterpret_cast<void*>(&swi_instruction_), |
| 635 Instr::kInstrSize); |
| 517 list_ = this; | 636 list_ = this; |
| 518 } | 637 } |
| 519 | 638 |
| 520 void* address_of_swi_instruction() { | 639 void* address_of_swi_instruction() { |
| 521 return reinterpret_cast<void*>(&swi_instruction_); | 640 return reinterpret_cast<void*>(&swi_instruction_); |
| 522 } | 641 } |
| 523 | 642 |
| 524 void* external_function() { return external_function_; } | 643 void* external_function() { return external_function_; } |
| 525 bool fp_return() { return fp_return_; } | 644 bool fp_return() { return fp_return_; } |
| 526 | 645 |
| (...skipping 1035 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 } | 1681 } |
| 1563 | 1682 |
| 1564 case TST: { | 1683 case TST: { |
| 1565 if (instr->HasS()) { | 1684 if (instr->HasS()) { |
| 1566 // Format(instr, "tst'cond 'rn, 'shift_rm"); | 1685 // Format(instr, "tst'cond 'rn, 'shift_rm"); |
| 1567 // Format(instr, "tst'cond 'rn, 'imm"); | 1686 // Format(instr, "tst'cond 'rn, 'imm"); |
| 1568 alu_out = rn_val & shifter_operand; | 1687 alu_out = rn_val & shifter_operand; |
| 1569 SetNZFlags(alu_out); | 1688 SetNZFlags(alu_out); |
| 1570 SetCFlag(shifter_carry_out); | 1689 SetCFlag(shifter_carry_out); |
| 1571 } else { | 1690 } else { |
| 1572 UNIMPLEMENTED(); | 1691 // Format(instr, "movw'cond 'rd, 'imm"); |
| 1692 alu_out = instr->ImmedMovwMovtField(); |
| 1693 set_register(rd, alu_out); |
| 1573 } | 1694 } |
| 1574 break; | 1695 break; |
| 1575 } | 1696 } |
| 1576 | 1697 |
| 1577 case TEQ: { | 1698 case TEQ: { |
| 1578 if (instr->HasS()) { | 1699 if (instr->HasS()) { |
| 1579 // Format(instr, "teq'cond 'rn, 'shift_rm"); | 1700 // Format(instr, "teq'cond 'rn, 'shift_rm"); |
| 1580 // Format(instr, "teq'cond 'rn, 'imm"); | 1701 // Format(instr, "teq'cond 'rn, 'imm"); |
| 1581 alu_out = rn_val ^ shifter_operand; | 1702 alu_out = rn_val ^ shifter_operand; |
| 1582 SetNZFlags(alu_out); | 1703 SetNZFlags(alu_out); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1603 | 1724 |
| 1604 case CMP: { | 1725 case CMP: { |
| 1605 if (instr->HasS()) { | 1726 if (instr->HasS()) { |
| 1606 // Format(instr, "cmp'cond 'rn, 'shift_rm"); | 1727 // Format(instr, "cmp'cond 'rn, 'shift_rm"); |
| 1607 // Format(instr, "cmp'cond 'rn, 'imm"); | 1728 // Format(instr, "cmp'cond 'rn, 'imm"); |
| 1608 alu_out = rn_val - shifter_operand; | 1729 alu_out = rn_val - shifter_operand; |
| 1609 SetNZFlags(alu_out); | 1730 SetNZFlags(alu_out); |
| 1610 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); | 1731 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); |
| 1611 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); | 1732 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); |
| 1612 } else { | 1733 } else { |
| 1613 UNIMPLEMENTED(); | 1734 // Format(instr, "movt'cond 'rd, 'imm"); |
| 1735 alu_out = (get_register(rd) & 0xffff) | |
| 1736 (instr->ImmedMovwMovtField() << 16); |
| 1737 set_register(rd, alu_out); |
| 1614 } | 1738 } |
| 1615 break; | 1739 break; |
| 1616 } | 1740 } |
| 1617 | 1741 |
| 1618 case CMN: { | 1742 case CMN: { |
| 1619 if (instr->HasS()) { | 1743 if (instr->HasS()) { |
| 1620 // Format(instr, "cmn'cond 'rn, 'shift_rm"); | 1744 // Format(instr, "cmn'cond 'rn, 'shift_rm"); |
| 1621 // Format(instr, "cmn'cond 'rn, 'imm"); | 1745 // Format(instr, "cmn'cond 'rn, 'imm"); |
| 1622 alu_out = rn_val + shifter_operand; | 1746 alu_out = rn_val + shifter_operand; |
| 1623 SetNZFlags(alu_out); | 1747 SetNZFlags(alu_out); |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2265 break; | 2389 break; |
| 2266 } | 2390 } |
| 2267 } else { | 2391 } else { |
| 2268 UNIMPLEMENTED(); // Not used by V8. | 2392 UNIMPLEMENTED(); // Not used by V8. |
| 2269 } | 2393 } |
| 2270 } | 2394 } |
| 2271 | 2395 |
| 2272 | 2396 |
| 2273 // Executes the current instruction. | 2397 // Executes the current instruction. |
| 2274 void Simulator::InstructionDecode(Instr* instr) { | 2398 void Simulator::InstructionDecode(Instr* instr) { |
| 2399 CheckICache(instr); |
| 2275 pc_modified_ = false; | 2400 pc_modified_ = false; |
| 2276 if (::v8::internal::FLAG_trace_sim) { | 2401 if (::v8::internal::FLAG_trace_sim) { |
| 2277 disasm::NameConverter converter; | 2402 disasm::NameConverter converter; |
| 2278 disasm::Disassembler dasm(converter); | 2403 disasm::Disassembler dasm(converter); |
| 2279 // use a reasonably large buffer | 2404 // use a reasonably large buffer |
| 2280 v8::internal::EmbeddedVector<char, 256> buffer; | 2405 v8::internal::EmbeddedVector<char, 256> buffer; |
| 2281 dasm.InstructionDecode(buffer, | 2406 dasm.InstructionDecode(buffer, |
| 2282 reinterpret_cast<byte*>(instr)); | 2407 reinterpret_cast<byte*>(instr)); |
| 2283 PrintF(" 0x%08x %s\n", instr, buffer.start()); | 2408 PrintF(" 0x%08x %s\n", instr, buffer.start()); |
| 2284 } | 2409 } |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2459 | 2584 |
| 2460 | 2585 |
| 2461 uintptr_t Simulator::PopAddress() { | 2586 uintptr_t Simulator::PopAddress() { |
| 2462 int current_sp = get_register(sp); | 2587 int current_sp = get_register(sp); |
| 2463 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); | 2588 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
| 2464 uintptr_t address = *stack_slot; | 2589 uintptr_t address = *stack_slot; |
| 2465 set_register(sp, current_sp + sizeof(uintptr_t)); | 2590 set_register(sp, current_sp + sizeof(uintptr_t)); |
| 2466 return address; | 2591 return address; |
| 2467 } | 2592 } |
| 2468 | 2593 |
| 2469 | |
| 2470 } } // namespace assembler::arm | 2594 } } // namespace assembler::arm |
| 2471 | 2595 |
| 2472 #endif // !defined(__arm__) | 2596 #endif // !defined(__arm__) |
| OLD | NEW |