--- trunk/src/cpus/cpu_dyntrans.c 2007/10/08 16:19:11 18 +++ trunk/src/cpus/cpu_dyntrans.c 2007/10/08 16:19:23 20 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_dyntrans.c,v 1.27 2005/10/27 14:01:13 debug Exp $ + * $Id: cpu_dyntrans.c,v 1.41 2005/11/23 22:03:31 debug Exp $ * * Common dyntrans routines. Included from cpu_*.c. */ @@ -40,7 +40,7 @@ if (low_pc < 0 || low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE) return; -#if 1 +#if 0 /* Use the physical address: */ cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) cpu->cd.DYNTRANS_ARCH.cur_ic_page; @@ -94,7 +94,9 @@ #define S gather_statistics(cpu) #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH -#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic); +#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \ + cpu->cd.DYNTRANS_ARCH.next_ic += ic->len; \ + ic->f(cpu, ic); #else #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); #endif @@ -134,6 +136,14 @@ if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I)) arm_exception(cpu, ARM_EXCEPTION_IRQ); #endif +#ifdef DYNTRANS_PPC + if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { + ppc_exception(cpu, PPC_EXCEPTION_DEC); + cpu->cd.ppc.dec_intr_pending = 0; + } + if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE) + ppc_exception(cpu, PPC_EXCEPTION_EI); +#endif cached_pc = cpu->pc; @@ -238,41 +248,40 @@ } } + n_instrs += cpu->n_translated_instrs; - /* - * Update the program counter and return the correct number of - * executed instructions: - */ + /* Synchronize the program counter: */ low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); - if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) { -#ifdef DYNTRANS_ARM - cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2); - cpu->cd.arm.r[ARM_PC] += (low_pc << 2); - cpu->pc = cpu->cd.arm.r[ARM_PC]; -#else cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); -#endif } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) { /* Switch to next page: */ -#ifdef DYNTRANS_ARM - cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2); - cpu->pc = cpu->cd.arm.r[ARM_PC]; -#else cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE << DYNTRANS_INSTR_ALIGNMENT_SHIFT); -#endif - } else { - /* debug("debug: Outside a page (This is actually ok)\n"); */ } - return n_instrs + cpu->n_translated_instrs; +#ifdef DYNTRANS_PPC + /* Update the Decrementer and Time base registers: */ + { + uint32_t old = cpu->cd.ppc.spr[SPR_DEC]; + cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs); + if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1) + cpu->cd.ppc.dec_intr_pending = 1; + + old = cpu->cd.ppc.spr[SPR_TBL]; + cpu->cd.ppc.spr[SPR_TBL] += n_instrs; + if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0) + cpu->cd.ppc.spr[SPR_TBU] ++; + } +#endif + + /* Return the nr of instructions executed: */ + return n_instrs; } #endif /* DYNTRANS_CPU_RUN_INSTR */ @@ -352,6 +361,9 @@ #ifdef DYNTRANS_MIPS gpr[MIPS_GPR_A0 #endif +#ifdef DYNTRANS_NEWMIPS + r[0 /* TODO */ +#endif #ifdef DYNTRANS_PPC gpr[3 #endif @@ -453,7 +465,7 @@ #else uint64_t #endif - cached_pc, physaddr; + cached_pc, physaddr = 0; uint32_t physpage_ofs; int ok, pagenr, table_index; uint32_t *physpage_entryp; @@ -519,20 +531,17 @@ ok = 1; } if (!ok) { -/* - fatal("TODO: instruction vaddr=>paddr translation" + /* fatal("TODO: instruction vaddr=>paddr translation" " failed. vaddr=0x%llx\n", (long long)cached_pc); -fatal("!! cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc, -cpu->cd.arm.r[ARM_PC]); -*/ + fatal("!! cpu->pc=0x%llx\n", (long long)cpu->pc); */ + ok = cpu->translate_address(cpu, cpu->pc, &paddr, FLAG_INSTR); -/* -printf("EXCEPTION HANDLER: vaddr = 0x%x ==> paddr = 0x%x\n", - (int)cpu->pc, (int)paddr); -fatal("!? cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc, -cpu->cd.arm.r[ARM_PC]); -*/ + + /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> " + "paddr = 0x%x\n", (int)cpu->pc, (int)paddr); + fatal("!? cpu->pc=0x%llx\n", (long long)cpu->pc); */ + if (!ok) { fatal("FATAL: could not find physical" " address of the exception handler?"); @@ -561,7 +570,7 @@ #endif if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { - fatal("[ dyntrans: resetting the translation cache ]\n"); + debug("[ dyntrans: resetting the translation cache ]\n"); cpu_create_or_reset_tc(cpu); } @@ -610,10 +619,16 @@ vph_p->phys_page[b] = ppp; #endif +#ifdef MODE32 + /* Small optimization: only mark the physical page as non-writable + if it did not contain translations. (Because if it does contain + translations, it is already non-writable.) */ + if (!cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] & + (1 << (pagenr & 31))) +#endif cpu->invalidate_translation_caches(cpu, physaddr, JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); -/* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */ cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + @@ -674,11 +689,13 @@ goto have_it; } #else + /* Temporary, to avoid a compiler warning: */ + cached_pc = 0; + ppp = NULL; #ifdef DYNTRANS_IA64 fatal("IA64 todo\n"); #else fatal("Neither alpha, ia64, nor 32-bit? 1\n"); - { char *p = (char *) 0; *p = 0; } exit(1); #endif #endif @@ -688,8 +705,8 @@ return; /* Quick return path: */ +#if defined(MODE32) || defined(DYNTRANS_ALPHA) have_it: -/* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */ cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + DYNTRANS_PC_TO_IC_ENTRY(cached_pc); @@ -697,6 +714,7 @@ /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, " "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr, (long long)table_index, (long long)physpage_ofs); */ +#endif } #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */ @@ -724,7 +742,7 @@ uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); #ifdef DYNTRANS_ARM - cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] &= ~(1 << (index & 7)); + cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31)); #endif if (flags & JUST_MARK_AS_NON_WRITABLE) { @@ -820,12 +838,30 @@ #endif addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1); + /* fatal("invalidate(): "); */ + /* Quick case for virtual addresses: see note above. */ if (flags & INVALIDATE_VADDR) { + /* fatal("vaddr 0x%08x\n", (int)addr_page); */ DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags); return; } + if (flags & INVALIDATE_ALL) { + /* fatal("all\n"); */ + for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { + DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd. + DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, + 0); + cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0; + } + } + return; + } + + /* fatal("paddr 0x%08x\n", (int)addr_page); */ + for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && ( (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page == @@ -1011,7 +1047,9 @@ void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page) { +#ifndef MODE32 int64_t lowest, highest = -1; +#endif int found, r, lowest_index, start, end, useraccess = 0; #ifdef DYNTRANS_ALPHA @@ -1057,19 +1095,27 @@ #endif /* Scan the current TLB entries: */ - found = -1; lowest_index = start; - lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; + lowest_index = start; #ifdef MODE32 - /* NOTE: vaddr_to_tlbindex is one more than the index, so that - 0 becomes -1, which means a miss. */ - found = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ + /* + * NOTE 1: vaddr_to_tlbindex is one more than the index, so that + * 0 becomes -1, which means a miss. + * + * NOTE 2: When a miss occurs, instead of scanning the entire tlb + * for the entry with the lowest time stamp, just choosing + * one at random will work as well. + */ + found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; - if (found < 0) - lowest_index = (random() % (end-start)) + start; - if (0) -#endif - + if (found < 0) { + static unsigned int x = 0; + lowest_index = (x % (end-start)) + start; + x ++; + } +#else + lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; + found = -1; for (r=start; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { lowest = cpu->cd.DYNTRANS_ARCH. @@ -1086,6 +1132,7 @@ break; } } +#endif if (found < 0) { /* Create the new TLB entry, overwriting the oldest one: */ @@ -1101,8 +1148,11 @@ cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; - cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag; + cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = + writeflag & MEM_WRITE; +#ifndef MODE32 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; +#endif /* Add the new translation to the table: */ #ifdef DYNTRANS_ALPHA @@ -1151,8 +1201,8 @@ cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1; #ifdef DYNTRANS_ARM if (useraccess) - cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] - |= 1 << (index & 7); + cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] + |= 1 << (index & 31); #endif #endif /* 32 */ #endif /* !ALPHA */ @@ -1161,13 +1211,15 @@ * The translation was already in the TLB. * Writeflag = 0: Do nothing. * Writeflag = 1: Make sure the page is writable. - * Writeflag = -1: Downgrade to readonly. + * Writeflag = MEM_DOWNGRADE: Downgrade to readonly. */ r = found; +#ifndef MODE32 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; - if (writeflag == 1) +#endif + if (writeflag & MEM_WRITE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; - if (writeflag == -1) + if (writeflag & MEM_DOWNGRADE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0; #ifdef DYNTRANS_ALPHA a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1); @@ -1179,9 +1231,9 @@ vph_p = cpu->cd.alpha.vph_table0[a]; vph_p->phys_page[b] = NULL; if (vph_p->phys_addr[b] == paddr_page) { - if (writeflag == 1) + if (writeflag & MEM_WRITE) vph_p->host_store[b] = host_page; - if (writeflag == -1) + if (writeflag & MEM_DOWNGRADE) vph_p->host_store[b] = NULL; } else { /* Change the entire physical/host mapping: */ @@ -1194,16 +1246,16 @@ index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; #ifdef DYNTRANS_ARM - cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3]&=~(1<<(index&7)); + cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31)); if (useraccess) - cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] - |= 1 << (index & 7); + cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] + |= 1 << (index & 31); #endif if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { - if (writeflag == 1) + if (writeflag & MEM_WRITE) cpu->cd.DYNTRANS_ARCH.host_store[index] = host_page; - if (writeflag == -1) + if (writeflag & MEM_DOWNGRADE) cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; } else { /* Change the entire physical/host mapping: */ @@ -1285,11 +1337,11 @@ * instruction combination. */ if (!single_step && !cpu->machine->instruction_trace) { - if (cpu->combination_check != NULL && + if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL && cpu->machine->speed_tricks) - cpu->combination_check(cpu, ic, + cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, addr & (DYNTRANS_PAGESIZE - 1)); - cpu->combination_check = NULL; + cpu->cd.DYNTRANS_ARCH.combination_check = NULL; } /* ... and finally execute the translated instruction: */