| Index: src/arm/simulator-arm.cc
|
| ===================================================================
|
| --- src/arm/simulator-arm.cc (revision 4311)
|
| +++ src/arm/simulator-arm.cc (working copy)
|
| @@ -433,7 +433,123 @@
|
| #undef XSTR
|
| }
|
|
|
| +static const int kICachePageSize = 0x1000;
|
| +static const int kICachePageMask = 0xfff;
|
| +static const int kICachePageShift = 12;
|
| +static const int kICacheLineLength = 4;
|
| +static const int kICacheLineMask = 3;
|
| +static const int kPageSpace = kICachePageSize
|
| ++ kICachePageSize / kICacheLineLength;
|
|
|
| +
|
| +static bool ICacheMatch(void* one, void* two) {
|
| + ASSERT((reinterpret_cast<intptr_t>(one) & kICachePageMask) == 0);
|
| + return one == two;
|
| +}
|
| +
|
| +
|
| +static uint32_t ICacheHash(void* key) {
|
| + return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
|
| +}
|
| +
|
| +
|
| +static char* CacheValid(char* cache_page, int offset) {
|
| + return &cache_page[kICachePageSize + offset / kICacheLineLength];
|
| +}
|
| +
|
| +
|
| +static bool AllOnOnePage(uintptr_t start, int size) {
|
| + intptr_t start_page = (start & ~kICachePageMask);
|
| + intptr_t end_page = ((start + size) & ~kICachePageMask);
|
| + return start_page == end_page;
|
| +}
|
| +
|
| +
|
| +void Simulator::FlushICache(void* start_addr, size_t size) {
|
| + intptr_t start = reinterpret_cast<intptr_t>(start_addr);
|
| + int intra_line = (start & kICacheLineMask);
|
| + start -= intra_line;
|
| + size += intra_line;
|
| + size = ((size - 1) | kICacheLineMask) + 1;
|
| + int offset = (start & kICachePageMask);
|
| + while (!AllOnOnePage(start, size - 1)) {
|
| + int bytes_to_flush = kICachePageSize - offset;
|
| + FlushOnePage(start, bytes_to_flush);
|
| + start += bytes_to_flush;
|
| + size -= bytes_to_flush;
|
| + ASSERT_EQ(0, start & kICachePageMask);
|
| + offset = 0;
|
| + }
|
| + if (size != 0) {
|
| + FlushOnePage(start, size);
|
| + }
|
| +}
|
| +
|
| +
|
| +char* Simulator::GetCachePage(void* page) {
|
| + v8::internal::HashMap::Entry* entry = i_cache_.Lookup(page,
|
| + ICacheHash(page),
|
| + true);
|
| + if (entry->value == NULL) {
|
| + char* new_page = new char[kPageSpace];
|
| + // Set the ICache to invalid for the new pages.
|
| + memset(new_page, 1, kPageSpace);
|
| + entry->value = new_page;
|
| + // printf("New cache allocated from %p to %p\n",
|
| + // (void*)(new_page), (void*)(new_page + kPageSpace));
|
| + }
|
| + return reinterpret_cast<char*>(entry->value);
|
| +}
|
| +
|
| +
|
| +// Flush from start up to and not including start + size.
|
| +void Simulator::FlushOnePage(intptr_t start, int size) {
|
| + // printf("Flushing icache from %p to %p\n",
|
| + // (void*)start, (void*)(start + size));
|
| + ASSERT(size <= kICachePageSize);
|
| + ASSERT(AllOnOnePage(start, size - 1));
|
| + ASSERT((start & kICacheLineMask) == 0);
|
| + ASSERT((size & kICacheLineMask) == 0);
|
| + void* page = reinterpret_cast<void*>(start & (~kICachePageMask));
|
| + int offset = (start & kICachePageMask);
|
| + char* cache_page = GetCachePage(page);
|
| + char* valid_bytemap = CacheValid(cache_page, offset);
|
| + // printf("Zero bytes from %p to %p\n", (void*)valid_bytemap,
|
| + // (void*)(valid_bytemap + size / kICacheLineLength));
|
| + memset(valid_bytemap, 0, size / kICacheLineLength);
|
| +}
|
| +
|
| +
|
| +void Simulator::CheckICache(Instr* instr) {
|
| + intptr_t address = reinterpret_cast<intptr_t>(instr);
|
| + void* page = reinterpret_cast<void*>(address & (~kICachePageMask));
|
| + void* line = reinterpret_cast<void*>(address & (~kICacheLineMask));
|
| + int offset = (address & kICachePageMask);
|
| + char* cache_page = GetCachePage(page);
|
| + char* cache_valid_byte = CacheValid(cache_page, offset);
|
| + bool cache_hit = (*cache_valid_byte != 0);
|
| + char* cached_insn = cache_page + (offset & ~kICacheLineMask);
|
| + if (cache_hit) {
|
| + // Check that the data in memory matches the contents of the I-cache.
|
| + // printf("Checked cache byte at %p\n", (void*)cache_valid_byte);
|
| + // printf("Check instructions in cache for %p from %p to %p\n",
|
| + // (void*)instr, (void*)cached_insn,
|
| + // (void*)(cached_insn + kICacheLineLength));
|
| + CHECK(memcmp(reinterpret_cast<void*>(instr),
|
| + cache_page + offset,
|
| + Instr::kInstrSize) == 0);
|
| + } {
|
| + // Cache miss. Load memory into the cache.
|
| + // printf("Set instructions in cache for %p from %p to %p\n",
|
| + // (void*)instr, (void*)cached_insn,
|
| + // (void*)(cached_insn + kICacheLineLength));
|
| + memcpy(cached_insn, line, Instr::kInstrSize);
|
| + // printf("Set cache byte at %p\n", (void*)cache_valid_byte);
|
| + *cache_valid_byte = 1;
|
| + }
|
| +}
|
| +
|
| +
|
| // Create one simulator per thread and keep it in thread local storage.
|
| static v8::internal::Thread::LocalStorageKey simulator_key;
|
|
|
| @@ -449,7 +565,7 @@
|
| }
|
|
|
|
|
| -Simulator::Simulator() {
|
| +Simulator::Simulator() : i_cache_(&ICacheMatch) {
|
| Initialize();
|
| // Setup simulator support first. Some of this information is needed to
|
| // setup the architecture state.
|
| @@ -514,6 +630,9 @@
|
| swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected),
|
| fp_return_(fp_return),
|
| next_(list_) {
|
| + assembler::arm::Simulator::current()->
|
| + FlushICache(reinterpret_cast<void*>(&swi_instruction_),
|
| + Instr::kInstrSize);
|
| list_ = this;
|
| }
|
|
|
| @@ -1569,7 +1688,9 @@
|
| SetNZFlags(alu_out);
|
| SetCFlag(shifter_carry_out);
|
| } else {
|
| - UNIMPLEMENTED();
|
| + // Format(instr, "movw'cond 'rd, 'imm");
|
| + alu_out = instr->ImmedMovwMovtField();
|
| + set_register(rd, alu_out);
|
| }
|
| break;
|
| }
|
| @@ -1610,7 +1731,10 @@
|
| SetCFlag(!BorrowFrom(rn_val, shifter_operand));
|
| SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
|
| } else {
|
| - UNIMPLEMENTED();
|
| + // Format(instr, "movt'cond 'rd, 'imm");
|
| + alu_out = (get_register(rd) & 0xffff) |
|
| + (instr->ImmedMovwMovtField() << 16);
|
| + set_register(rd, alu_out);
|
| }
|
| break;
|
| }
|
| @@ -2272,6 +2396,7 @@
|
|
|
| // Executes the current instruction.
|
| void Simulator::InstructionDecode(Instr* instr) {
|
| + CheckICache(instr);
|
| pc_modified_ = false;
|
| if (::v8::internal::FLAG_trace_sim) {
|
| disasm::NameConverter converter;
|
| @@ -2466,7 +2591,6 @@
|
| return address;
|
| }
|
|
|
| -
|
| } } // namespace assembler::arm
|
|
|
| #endif // !defined(__arm__)
|
|
|