--- trunk/src/cpus/cpu_dyntrans.c 2007/10/08 16:20:26 28 +++ trunk/src/cpus/cpu_dyntrans.c 2007/10/08 16:21:53 38 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_dyntrans.c,v 1.113 2006/07/21 20:09:15 debug Exp $ + * $Id: cpu_dyntrans.c,v 1.145 2007/04/10 17:26:20 debug Exp $ * * Common dyntrans routines. Included from cpu_*.c. */ @@ -45,6 +45,12 @@ int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); + if (cpu->machine->statistics_file == NULL) { + fatal("statistics gathering with no filename set is" + " meaningless\n"); + return; + } + buf[0] = '\0'; while ((ch = cpu->machine->statistics_fields[i]) != '\0') { @@ -223,17 +229,23 @@ #endif #ifdef DYNTRANS_PPC if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { - ppc_exception(cpu, PPC_EXCEPTION_DEC); + if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) + 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 +#ifdef DYNTRANS_SH + if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL) + && ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) + < cpu->cd.sh.int_level) + sh_exception(cpu, 0, cpu->cd.sh.int_to_assert, 0); +#endif cached_pc = cpu->pc; cpu->n_translated_instrs = 0; - cpu->running_translated = 1; cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) cpu->cd.DYNTRANS_ARCH.cur_ic_page; @@ -249,25 +261,20 @@ cpu_register_dump(cpu->machine, cpu, 1, 0x1); } if (cpu->machine->instruction_trace) { -#ifdef DYNTRANS_X86 - unsigned char instr[17]; - cpu->cd.x86.cursegment = X86_S_CS; - cpu->cd.x86.seg_override = 0; -#else -#ifdef DYNTRANS_M68K - unsigned char instr[16]; /* TODO: 16? */ -#else - unsigned char instr[4]; /* General case... */ -#endif -#endif - + /* TODO/Note: This must be large enough to hold + any instruction for any ISA: */ + unsigned char instr[1 << + DYNTRANS_INSTR_ALIGNMENT_SHIFT]; if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0], sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) { fatal("XXX_run_instr(): could not read " "the instruction\n"); } else { - cpu_disassemble_instr(cpu->machine, cpu, - instr, 1, 0); +#ifdef DYNTRANS_DELAYSLOT + int len = +#endif + cpu_disassemble_instr( + cpu->machine, cpu, instr, 1, 0); #ifdef DYNTRANS_DELAYSLOT /* Show the instruction in the delay slot, if any: */ @@ -278,48 +285,20 @@ instr)) { int saved_delayslot = cpu->delay_slot; cpu->memory_rw(cpu, cpu->mem, cached_pc - + sizeof(instr), &instr[0], + + len, &instr[0], sizeof(instr), MEM_READ, CACHE_INSTRUCTION); cpu->delay_slot = DELAYED; - cpu->pc += sizeof(instr); + cpu->pc += len; cpu_disassemble_instr(cpu->machine, cpu, instr, 1, 0); cpu->delay_slot = saved_delayslot; - cpu->pc -= sizeof(instr); + cpu->pc -= len; } #endif } } - /* When single-stepping, multiple instruction calls cannot - be combined into one. This clears all translations: */ - if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) { - int i; - for (i=0; icd.DYNTRANS_ARCH.cur_physpage->ics[i].f = -#ifdef DYNTRANS_DUALMODE_32 - cpu->is_32bit? - instr32(to_be_translated) : -#endif - instr(to_be_translated); -#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH - cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i]. - arg[0] = 0; -#endif - } - - fatal("[ Note: The translation of physical page 0x%" - PRIx64" contained combinations of instructions; " - "these are now flushed because we are single-" - "stepping. ]\n", (long long)cpu->cd.DYNTRANS_ARCH. - cur_physpage->physaddr); - - cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &= - ~COMBINATIONS; - cpu->cd.DYNTRANS_ARCH.cur_physpage->translations = 0; - } - if (cpu->machine->statistics_enabled) S; @@ -344,8 +323,7 @@ cpu->machine->tick_func[1](cpu, cpu->machine->tick_extra[1]); /* printf("B\n"); */ - if (!cpu->running_translated || - n_instrs + cpu->n_translated_instrs >= + if (n_instrs + cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) break; } @@ -362,8 +340,7 @@ n_instrs += 24; - if (!cpu->running_translated || - n_instrs + cpu->n_translated_instrs >= + if (n_instrs + cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) break; } @@ -381,11 +358,16 @@ I; I; I; I; I; I; I; I; I; I; - n_instrs += 60; + I; I; I; I; I; I; I; I; I; I; + I; I; I; I; I; I; I; I; I; I; + I; I; I; I; I; I; I; I; I; I; + I; I; I; I; I; I; I; I; I; I; + I; I; I; I; I; I; I; I; I; I; - if (!cpu->running_translated || - n_instrs + cpu->n_translated_instrs >= - N_SAFE_DYNTRANS_LIMIT) + I; I; I; I; I; I; I; I; I; I; + + cpu->n_translated_instrs += 120; + if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) break; } } @@ -424,8 +406,22 @@ (int32_t) (old + n_instrs); diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; - if (cpu->cd.mips.compare_register_set && diff1>0 && diff2<=0) - cpu_interrupt(cpu, 7); + + if (cpu->cd.mips.compare_register_set) { +#if 1 +/* Not yet. TODO */ + if (cpu->machine->emulated_hz > 0) { + if (cpu->cd.mips.compare_interrupts_pending > 0) + INTERRUPT_ASSERT( + cpu->cd.mips.irq_compare); + } else +#endif + { + if (diff1 > 0 && diff2 <= 0) + INTERRUPT_ASSERT( + cpu->cd.mips.irq_compare); + } + } } #endif #ifdef DYNTRANS_PPC @@ -468,7 +464,7 @@ 6 #else #ifdef DYNTRANS_SH - 8 + 8 /* Both for 32-bit and 64-bit SuperH */ #else 4 /* Default value for most archs */ #endif @@ -492,12 +488,7 @@ * than were passed in register. */ for (x=0; xcd.DYNTRANS_ARCH. + int64_t d = cpu->cd.DYNTRANS_ARCH. #ifdef DYNTRANS_ALPHA r[ALPHA_A0 #endif @@ -509,15 +500,6 @@ they go downwards, ie. 22,23 and so on */ r[24 #endif -#ifdef DYNTRANS_HPPA - r[0 /* TODO */ -#endif -#ifdef DYNTRANS_I960 - r[0 /* TODO */ -#endif -#ifdef DYNTRANS_IA64 - r[0 /* TODO */ -#endif #ifdef DYNTRANS_M68K d[0 /* TODO */ #endif @@ -528,13 +510,14 @@ gpr[3 #endif #ifdef DYNTRANS_SH - r[2 + r[4 /* NetBSD seems to use 4? But 2 seems + to be used by other code? TODO */ #endif #ifdef DYNTRANS_SPARC - r[24 + r[8 /* o0..o5 */ #endif + x]; -#endif + symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot); if (d > -256 && d < 256) @@ -650,8 +633,14 @@ if (!ok) { uint64_t paddr; if (cpu->translate_v2p != NULL) { + uint64_t vaddr = +#if defined(MODE32) && defined(DYNTRANS_MIPS) + /* 32-bit MIPS is _sign_ extend, not zero. */ + (int32_t) +#endif + cached_pc; ok = cpu->translate_v2p( - cpu, cached_pc, &paddr, FLAG_INSTR); + cpu, vaddr, &paddr, FLAG_INSTR); } else { paddr = cached_pc; ok = 1; @@ -679,9 +668,10 @@ } #else x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; - x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; - x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) - & mask3; + x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) + & mask2; + x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N + - DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; l3 = l2->l3[x2]; if (l3->host_load[x3] != NULL) { @@ -725,7 +715,7 @@ } } - if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { + if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) { #ifdef UNSTABLE_DEVEL fatal("[ dyntrans: resetting the translation cache ]\n"); #endif @@ -752,13 +742,21 @@ physpage_ofs = ppp->next_ofs; } - /* If the offset is 0 (or ppp is NULL), then we need to create a - new "default" empty translation page. */ + /* + * If the offset is 0, then no translation exists yet for this + * physical address. Let's create a new page, and add it first in + * the chain. + */ + if (physpage_ofs == 0) { + uint32_t previous_first_page_in_chain; - if (ppp == NULL) { /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table " "index %i\n", (long long)pagenr, (uint64_t)physaddr, (int)table_index); */ + + previous_first_page_in_chain = *physpage_entryp; + + /* Insert the new page first in the chain: */ *physpage_entryp = physpage_ofs = cpu->translation_cache_cur_ofs; @@ -767,8 +765,13 @@ ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache + physpage_ofs); + + /* Point to the other pages in the same chain: */ + ppp->next_ofs = previous_first_page_in_chain; } + /* Here, ppp points to a valid physical page struct. */ + #ifdef MODE32 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp; @@ -902,7 +905,6 @@ } ppp->next_ofs = 0; - ppp->flags = 0; ppp->translations = 0; /* ppp->physaddr is filled in by the page allocator */ @@ -1249,6 +1251,12 @@ physpage_entryp = &(((uint32_t *)cpu-> translation_cache)[table_index]); physpage_ofs = *physpage_entryp; + + /* Return immediately if there is no code translation + for this page. */ + if (physpage_ofs == 0) + return; + prev_ppp = ppp = NULL; /* Traverse the physical page chain: */ @@ -1266,8 +1274,10 @@ physpage_ofs = ppp->next_ofs; } + /* If there is no translation, there is no need to go + on and try to remove it from the vph_tlb_entry array: */ if (physpage_ofs == 0) - ppp = NULL; + return; #if 0 /* @@ -1312,7 +1322,6 @@ x >>= 1; } - ppp->flags &= ~COMBINATIONS; ppp->translations = 0; } #endif @@ -1367,10 +1376,7 @@ 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, useraccess = 0; + int found, r, useraccess = 0; #ifdef MODE32 uint32_t index; @@ -1401,7 +1407,6 @@ } /* Scan the current TLB entries: */ - lowest_index = 0; #ifdef MODE32 /* @@ -1414,34 +1419,29 @@ */ found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; - if (found < 0) { - static unsigned int x = 0; - lowest_index = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; - } #else - lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; - found = -1; - for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { - lowest = cpu->cd.DYNTRANS_ARCH. - vph_tlb_entry[r].timestamp; - lowest_index = r; - } - if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest) - highest = cpu->cd.DYNTRANS_ARCH. - vph_tlb_entry[r].timestamp; - if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && - cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page == - vaddr_page) { - found = r; - break; - } + x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; + x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; + x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) + & mask3; + + l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; + if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) + found = -1; + else { + l3 = l2->l3[x2]; + if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) + found = -1; + else + found = (int)l3->vaddr_to_tlbindex[x3] - 1; } #endif if (found < 0) { - /* Create the new TLB entry, overwriting the oldest one: */ - r = lowest_index; + /* Create the new TLB entry, overwriting a "random" entry: */ + static unsigned int x = 0; + r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; + if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { /* This one has to be invalidated first: */ DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, @@ -1455,9 +1455,6 @@ cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; 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 MODE32 @@ -1474,11 +1471,6 @@ |= 1 << (index & 31); #endif #else /* !MODE32 */ - x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; - x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; - x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) - & mask3; - l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) { if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) { @@ -1563,9 +1555,6 @@ * Writeflag = MEM_DOWNGRADE: Downgrade to readonly. */ r = found; -#ifndef MODE32 - cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; -#endif if (writeflag & MEM_WRITE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; if (writeflag & MEM_DOWNGRADE) @@ -1714,11 +1703,10 @@ #ifdef DYNTRANS_DELAYSLOT && !in_crosspage_delayslot #endif - ) { - if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL && - cpu->machine->allow_instruction_combinations) - cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, - addr & (DYNTRANS_PAGESIZE - 1)); + && cpu->cd.DYNTRANS_ARCH.combination_check != NULL + && cpu->machine->allow_instruction_combinations) { + cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, + addr & (DYNTRANS_PAGESIZE - 1)); } cpu->cd.DYNTRANS_ARCH.combination_check = NULL; @@ -1798,14 +1786,17 @@ } cpu->running = 0; - cpu->dead = 1; + + /* Note: Single-stepping can jump here. */ stop_running_translated: + debugger_n_steps_left_before_interaction = 0; - cpu->running_translated = 0; + ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; cpu->cd.DYNTRANS_ARCH.next_ic ++; /* Execute the "nothing" instruction: */ ic->f(cpu, ic); + #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */