1 |
/* |
/* |
2 |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $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 $ |
29 |
* |
* |
30 |
* Common dyntrans routines. Included from cpu_*.c. |
* Common dyntrans routines. Included from cpu_*.c. |
31 |
*/ |
*/ |
45 |
int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) |
int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) |
46 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
47 |
|
|
48 |
|
if (cpu->machine->statistics_file == NULL) { |
49 |
|
fatal("statistics gathering with no filename set is" |
50 |
|
" meaningless\n"); |
51 |
|
return; |
52 |
|
} |
53 |
|
|
54 |
buf[0] = '\0'; |
buf[0] = '\0'; |
55 |
|
|
56 |
while ((ch = cpu->machine->statistics_fields[i]) != '\0') { |
while ((ch = cpu->machine->statistics_fields[i]) != '\0') { |
229 |
#endif |
#endif |
230 |
#ifdef DYNTRANS_PPC |
#ifdef DYNTRANS_PPC |
231 |
if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { |
if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { |
232 |
ppc_exception(cpu, PPC_EXCEPTION_DEC); |
if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) |
233 |
|
ppc_exception(cpu, PPC_EXCEPTION_DEC); |
234 |
cpu->cd.ppc.dec_intr_pending = 0; |
cpu->cd.ppc.dec_intr_pending = 0; |
235 |
} |
} |
236 |
if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE) |
if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE) |
237 |
ppc_exception(cpu, PPC_EXCEPTION_EI); |
ppc_exception(cpu, PPC_EXCEPTION_EI); |
238 |
#endif |
#endif |
239 |
|
#ifdef DYNTRANS_SH |
240 |
|
if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL) |
241 |
|
&& ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) |
242 |
|
< cpu->cd.sh.int_level) |
243 |
|
sh_exception(cpu, 0, cpu->cd.sh.int_to_assert, 0); |
244 |
|
#endif |
245 |
|
|
246 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
247 |
|
|
248 |
cpu->n_translated_instrs = 0; |
cpu->n_translated_instrs = 0; |
|
cpu->running_translated = 1; |
|
249 |
|
|
250 |
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
251 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
261 |
cpu_register_dump(cpu->machine, cpu, 1, 0x1); |
cpu_register_dump(cpu->machine, cpu, 1, 0x1); |
262 |
} |
} |
263 |
if (cpu->machine->instruction_trace) { |
if (cpu->machine->instruction_trace) { |
264 |
#ifdef DYNTRANS_X86 |
/* TODO/Note: This must be large enough to hold |
265 |
unsigned char instr[17]; |
any instruction for any ISA: */ |
266 |
cpu->cd.x86.cursegment = X86_S_CS; |
unsigned char instr[1 << |
267 |
cpu->cd.x86.seg_override = 0; |
DYNTRANS_INSTR_ALIGNMENT_SHIFT]; |
|
#else |
|
|
#ifdef DYNTRANS_M68K |
|
|
unsigned char instr[16]; /* TODO: 16? */ |
|
|
#else |
|
|
unsigned char instr[4]; /* General case... */ |
|
|
#endif |
|
|
#endif |
|
|
|
|
268 |
if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0], |
if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0], |
269 |
sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) { |
sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) { |
270 |
fatal("XXX_run_instr(): could not read " |
fatal("XXX_run_instr(): could not read " |
271 |
"the instruction\n"); |
"the instruction\n"); |
272 |
} else { |
} else { |
273 |
cpu_disassemble_instr(cpu->machine, cpu, |
#ifdef DYNTRANS_DELAYSLOT |
274 |
instr, 1, 0); |
int len = |
275 |
|
#endif |
276 |
|
cpu_disassemble_instr( |
277 |
|
cpu->machine, cpu, instr, 1, 0); |
278 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
279 |
/* Show the instruction in the delay slot, |
/* Show the instruction in the delay slot, |
280 |
if any: */ |
if any: */ |
285 |
instr)) { |
instr)) { |
286 |
int saved_delayslot = cpu->delay_slot; |
int saved_delayslot = cpu->delay_slot; |
287 |
cpu->memory_rw(cpu, cpu->mem, cached_pc |
cpu->memory_rw(cpu, cpu->mem, cached_pc |
288 |
+ sizeof(instr), &instr[0], |
+ len, &instr[0], |
289 |
sizeof(instr), MEM_READ, |
sizeof(instr), MEM_READ, |
290 |
CACHE_INSTRUCTION); |
CACHE_INSTRUCTION); |
291 |
cpu->delay_slot = DELAYED; |
cpu->delay_slot = DELAYED; |
292 |
cpu->pc += sizeof(instr); |
cpu->pc += len; |
293 |
cpu_disassemble_instr(cpu->machine, |
cpu_disassemble_instr(cpu->machine, |
294 |
cpu, instr, 1, 0); |
cpu, instr, 1, 0); |
295 |
cpu->delay_slot = saved_delayslot; |
cpu->delay_slot = saved_delayslot; |
296 |
cpu->pc -= sizeof(instr); |
cpu->pc -= len; |
297 |
} |
} |
298 |
#endif |
#endif |
299 |
} |
} |
300 |
} |
} |
301 |
|
|
|
/* 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; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) { |
|
|
cpu->cd.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; |
|
|
} |
|
|
|
|
302 |
if (cpu->machine->statistics_enabled) |
if (cpu->machine->statistics_enabled) |
303 |
S; |
S; |
304 |
|
|
323 |
cpu->machine->tick_func[1](cpu, cpu->machine->tick_extra[1]); |
cpu->machine->tick_func[1](cpu, cpu->machine->tick_extra[1]); |
324 |
/* printf("B\n"); */ |
/* printf("B\n"); */ |
325 |
|
|
326 |
if (!cpu->running_translated || |
if (n_instrs + cpu->n_translated_instrs >= |
|
n_instrs + cpu->n_translated_instrs >= |
|
327 |
N_SAFE_DYNTRANS_LIMIT) |
N_SAFE_DYNTRANS_LIMIT) |
328 |
break; |
break; |
329 |
} |
} |
340 |
|
|
341 |
n_instrs += 24; |
n_instrs += 24; |
342 |
|
|
343 |
if (!cpu->running_translated || |
if (n_instrs + cpu->n_translated_instrs >= |
|
n_instrs + cpu->n_translated_instrs >= |
|
344 |
N_SAFE_DYNTRANS_LIMIT) |
N_SAFE_DYNTRANS_LIMIT) |
345 |
break; |
break; |
346 |
} |
} |
358 |
|
|
359 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
360 |
|
|
361 |
n_instrs += 60; |
I; I; I; I; I; I; I; I; I; I; |
362 |
|
I; I; I; I; I; I; I; I; I; I; |
363 |
|
I; I; I; I; I; I; I; I; I; I; |
364 |
|
I; I; I; I; I; I; I; I; I; I; |
365 |
|
I; I; I; I; I; I; I; I; I; I; |
366 |
|
|
367 |
if (!cpu->running_translated || |
I; I; I; I; I; I; I; I; I; I; |
368 |
n_instrs + cpu->n_translated_instrs >= |
|
369 |
N_SAFE_DYNTRANS_LIMIT) |
cpu->n_translated_instrs += 120; |
370 |
|
if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) |
371 |
break; |
break; |
372 |
} |
} |
373 |
} |
} |
406 |
(int32_t) (old + n_instrs); |
(int32_t) (old + n_instrs); |
407 |
diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - |
diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - |
408 |
cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; |
cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; |
409 |
if (cpu->cd.mips.compare_register_set && diff1>0 && diff2<=0) |
|
410 |
cpu_interrupt(cpu, 7); |
if (cpu->cd.mips.compare_register_set) { |
411 |
|
#if 1 |
412 |
|
/* Not yet. TODO */ |
413 |
|
if (cpu->machine->emulated_hz > 0) { |
414 |
|
if (cpu->cd.mips.compare_interrupts_pending > 0) |
415 |
|
INTERRUPT_ASSERT( |
416 |
|
cpu->cd.mips.irq_compare); |
417 |
|
} else |
418 |
|
#endif |
419 |
|
{ |
420 |
|
if (diff1 > 0 && diff2 <= 0) |
421 |
|
INTERRUPT_ASSERT( |
422 |
|
cpu->cd.mips.irq_compare); |
423 |
|
} |
424 |
|
} |
425 |
} |
} |
426 |
#endif |
#endif |
427 |
#ifdef DYNTRANS_PPC |
#ifdef DYNTRANS_PPC |
464 |
6 |
6 |
465 |
#else |
#else |
466 |
#ifdef DYNTRANS_SH |
#ifdef DYNTRANS_SH |
467 |
8 |
8 /* Both for 32-bit and 64-bit SuperH */ |
468 |
#else |
#else |
469 |
4 /* Default value for most archs */ |
4 /* Default value for most archs */ |
470 |
#endif |
#endif |
488 |
* than were passed in register. |
* than were passed in register. |
489 |
*/ |
*/ |
490 |
for (x=0; x<n_args_to_print; x++) { |
for (x=0; x<n_args_to_print; x++) { |
491 |
int64_t d; |
int64_t d = cpu->cd.DYNTRANS_ARCH. |
|
#if defined(DYNTRANS_X86) || defined(DYNTRANS_TRANSPUTER) |
|
|
d = 0; /* TODO */ |
|
|
#else |
|
|
/* Args in registers: */ |
|
|
d = cpu->cd.DYNTRANS_ARCH. |
|
492 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
493 |
r[ALPHA_A0 |
r[ALPHA_A0 |
494 |
#endif |
#endif |
500 |
they go downwards, ie. 22,23 and so on */ |
they go downwards, ie. 22,23 and so on */ |
501 |
r[24 |
r[24 |
502 |
#endif |
#endif |
|
#ifdef DYNTRANS_HPPA |
|
|
r[0 /* TODO */ |
|
|
#endif |
|
|
#ifdef DYNTRANS_I960 |
|
|
r[0 /* TODO */ |
|
|
#endif |
|
|
#ifdef DYNTRANS_IA64 |
|
|
r[0 /* TODO */ |
|
|
#endif |
|
503 |
#ifdef DYNTRANS_M68K |
#ifdef DYNTRANS_M68K |
504 |
d[0 /* TODO */ |
d[0 /* TODO */ |
505 |
#endif |
#endif |
510 |
gpr[3 |
gpr[3 |
511 |
#endif |
#endif |
512 |
#ifdef DYNTRANS_SH |
#ifdef DYNTRANS_SH |
513 |
r[2 |
r[4 /* NetBSD seems to use 4? But 2 seems |
514 |
|
to be used by other code? TODO */ |
515 |
#endif |
#endif |
516 |
#ifdef DYNTRANS_SPARC |
#ifdef DYNTRANS_SPARC |
517 |
r[24 |
r[8 /* o0..o5 */ |
518 |
#endif |
#endif |
519 |
+ x]; |
+ x]; |
520 |
#endif |
|
521 |
symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot); |
symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot); |
522 |
|
|
523 |
if (d > -256 && d < 256) |
if (d > -256 && d < 256) |
633 |
if (!ok) { |
if (!ok) { |
634 |
uint64_t paddr; |
uint64_t paddr; |
635 |
if (cpu->translate_v2p != NULL) { |
if (cpu->translate_v2p != NULL) { |
636 |
|
uint64_t vaddr = |
637 |
|
#if defined(MODE32) && defined(DYNTRANS_MIPS) |
638 |
|
/* 32-bit MIPS is _sign_ extend, not zero. */ |
639 |
|
(int32_t) |
640 |
|
#endif |
641 |
|
cached_pc; |
642 |
ok = cpu->translate_v2p( |
ok = cpu->translate_v2p( |
643 |
cpu, cached_pc, &paddr, FLAG_INSTR); |
cpu, vaddr, &paddr, FLAG_INSTR); |
644 |
} else { |
} else { |
645 |
paddr = cached_pc; |
paddr = cached_pc; |
646 |
ok = 1; |
ok = 1; |
668 |
} |
} |
669 |
#else |
#else |
670 |
x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; |
x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; |
671 |
x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; |
x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) |
672 |
x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) |
& mask2; |
673 |
& mask3; |
x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N |
674 |
|
- DYNTRANS_L3N)) & mask3; |
675 |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; |
676 |
l3 = l2->l3[x2]; |
l3 = l2->l3[x2]; |
677 |
if (l3->host_load[x3] != NULL) { |
if (l3->host_load[x3] != NULL) { |
715 |
} |
} |
716 |
} |
} |
717 |
|
|
718 |
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { |
if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) { |
719 |
#ifdef UNSTABLE_DEVEL |
#ifdef UNSTABLE_DEVEL |
720 |
fatal("[ dyntrans: resetting the translation cache ]\n"); |
fatal("[ dyntrans: resetting the translation cache ]\n"); |
721 |
#endif |
#endif |
742 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
743 |
} |
} |
744 |
|
|
745 |
/* If the offset is 0 (or ppp is NULL), then we need to create a |
/* |
746 |
new "default" empty translation page. */ |
* If the offset is 0, then no translation exists yet for this |
747 |
|
* physical address. Let's create a new page, and add it first in |
748 |
|
* the chain. |
749 |
|
*/ |
750 |
|
if (physpage_ofs == 0) { |
751 |
|
uint32_t previous_first_page_in_chain; |
752 |
|
|
|
if (ppp == NULL) { |
|
753 |
/* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table " |
/* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table " |
754 |
"index %i\n", (long long)pagenr, (uint64_t)physaddr, |
"index %i\n", (long long)pagenr, (uint64_t)physaddr, |
755 |
(int)table_index); */ |
(int)table_index); */ |
756 |
|
|
757 |
|
previous_first_page_in_chain = *physpage_entryp; |
758 |
|
|
759 |
|
/* Insert the new page first in the chain: */ |
760 |
*physpage_entryp = physpage_ofs = |
*physpage_entryp = physpage_ofs = |
761 |
cpu->translation_cache_cur_ofs; |
cpu->translation_cache_cur_ofs; |
762 |
|
|
765 |
|
|
766 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
767 |
+ physpage_ofs); |
+ physpage_ofs); |
768 |
|
|
769 |
|
/* Point to the other pages in the same chain: */ |
770 |
|
ppp->next_ofs = previous_first_page_in_chain; |
771 |
} |
} |
772 |
|
|
773 |
|
/* Here, ppp points to a valid physical page struct. */ |
774 |
|
|
775 |
#ifdef MODE32 |
#ifdef MODE32 |
776 |
if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) |
if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) |
777 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp; |
905 |
} |
} |
906 |
|
|
907 |
ppp->next_ofs = 0; |
ppp->next_ofs = 0; |
|
ppp->flags = 0; |
|
908 |
ppp->translations = 0; |
ppp->translations = 0; |
909 |
/* ppp->physaddr is filled in by the page allocator */ |
/* ppp->physaddr is filled in by the page allocator */ |
910 |
|
|
1251 |
physpage_entryp = &(((uint32_t *)cpu-> |
physpage_entryp = &(((uint32_t *)cpu-> |
1252 |
translation_cache)[table_index]); |
translation_cache)[table_index]); |
1253 |
physpage_ofs = *physpage_entryp; |
physpage_ofs = *physpage_entryp; |
1254 |
|
|
1255 |
|
/* Return immediately if there is no code translation |
1256 |
|
for this page. */ |
1257 |
|
if (physpage_ofs == 0) |
1258 |
|
return; |
1259 |
|
|
1260 |
prev_ppp = ppp = NULL; |
prev_ppp = ppp = NULL; |
1261 |
|
|
1262 |
/* Traverse the physical page chain: */ |
/* Traverse the physical page chain: */ |
1274 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
1275 |
} |
} |
1276 |
|
|
1277 |
|
/* If there is no translation, there is no need to go |
1278 |
|
on and try to remove it from the vph_tlb_entry array: */ |
1279 |
if (physpage_ofs == 0) |
if (physpage_ofs == 0) |
1280 |
ppp = NULL; |
return; |
1281 |
|
|
1282 |
#if 0 |
#if 0 |
1283 |
/* |
/* |
1322 |
x >>= 1; |
x >>= 1; |
1323 |
} |
} |
1324 |
|
|
|
ppp->flags &= ~COMBINATIONS; |
|
1325 |
ppp->translations = 0; |
ppp->translations = 0; |
1326 |
} |
} |
1327 |
#endif |
#endif |
1376 |
void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, |
void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, |
1377 |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
1378 |
{ |
{ |
1379 |
#ifndef MODE32 |
int found, r, useraccess = 0; |
|
int64_t lowest, highest = -1; |
|
|
#endif |
|
|
int found, r, lowest_index, useraccess = 0; |
|
1380 |
|
|
1381 |
#ifdef MODE32 |
#ifdef MODE32 |
1382 |
uint32_t index; |
uint32_t index; |
1407 |
} |
} |
1408 |
|
|
1409 |
/* Scan the current TLB entries: */ |
/* Scan the current TLB entries: */ |
|
lowest_index = 0; |
|
1410 |
|
|
1411 |
#ifdef MODE32 |
#ifdef MODE32 |
1412 |
/* |
/* |
1419 |
*/ |
*/ |
1420 |
found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ |
found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ |
1421 |
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
|
if (found < 0) { |
|
|
static unsigned int x = 0; |
|
|
lowest_index = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; |
|
|
} |
|
1422 |
#else |
#else |
1423 |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; |
1424 |
found = -1; |
x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; |
1425 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) |
1426 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
& mask3; |
1427 |
lowest = cpu->cd.DYNTRANS_ARCH. |
|
1428 |
vph_tlb_entry[r].timestamp; |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; |
1429 |
lowest_index = r; |
if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) |
1430 |
} |
found = -1; |
1431 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest) |
else { |
1432 |
highest = cpu->cd.DYNTRANS_ARCH. |
l3 = l2->l3[x2]; |
1433 |
vph_tlb_entry[r].timestamp; |
if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) |
1434 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && |
found = -1; |
1435 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page == |
else |
1436 |
vaddr_page) { |
found = (int)l3->vaddr_to_tlbindex[x3] - 1; |
|
found = r; |
|
|
break; |
|
|
} |
|
1437 |
} |
} |
1438 |
#endif |
#endif |
1439 |
|
|
1440 |
if (found < 0) { |
if (found < 0) { |
1441 |
/* Create the new TLB entry, overwriting the oldest one: */ |
/* Create the new TLB entry, overwriting a "random" entry: */ |
1442 |
r = lowest_index; |
static unsigned int x = 0; |
1443 |
|
r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; |
1444 |
|
|
1445 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
1446 |
/* This one has to be invalidated first: */ |
/* This one has to be invalidated first: */ |
1447 |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
1455 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; |
1456 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = |
1457 |
writeflag & MEM_WRITE; |
writeflag & MEM_WRITE; |
|
#ifndef MODE32 |
|
|
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
|
|
#endif |
|
1458 |
|
|
1459 |
/* Add the new translation to the table: */ |
/* Add the new translation to the table: */ |
1460 |
#ifdef MODE32 |
#ifdef MODE32 |
1471 |
|= 1 << (index & 31); |
|= 1 << (index & 31); |
1472 |
#endif |
#endif |
1473 |
#else /* !MODE32 */ |
#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; |
|
|
|
|
1474 |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; |
1475 |
if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) { |
if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) { |
1476 |
if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) { |
if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) { |
1555 |
* Writeflag = MEM_DOWNGRADE: Downgrade to readonly. |
* Writeflag = MEM_DOWNGRADE: Downgrade to readonly. |
1556 |
*/ |
*/ |
1557 |
r = found; |
r = found; |
|
#ifndef MODE32 |
|
|
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
|
|
#endif |
|
1558 |
if (writeflag & MEM_WRITE) |
if (writeflag & MEM_WRITE) |
1559 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
1560 |
if (writeflag & MEM_DOWNGRADE) |
if (writeflag & MEM_DOWNGRADE) |
1703 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
1704 |
&& !in_crosspage_delayslot |
&& !in_crosspage_delayslot |
1705 |
#endif |
#endif |
1706 |
) { |
&& cpu->cd.DYNTRANS_ARCH.combination_check != NULL |
1707 |
if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL && |
&& cpu->machine->allow_instruction_combinations) { |
1708 |
cpu->machine->allow_instruction_combinations) |
cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, |
1709 |
cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, |
addr & (DYNTRANS_PAGESIZE - 1)); |
|
addr & (DYNTRANS_PAGESIZE - 1)); |
|
1710 |
} |
} |
1711 |
|
|
1712 |
cpu->cd.DYNTRANS_ARCH.combination_check = NULL; |
cpu->cd.DYNTRANS_ARCH.combination_check = NULL; |
1786 |
} |
} |
1787 |
|
|
1788 |
cpu->running = 0; |
cpu->running = 0; |
1789 |
cpu->dead = 1; |
|
1790 |
|
/* Note: Single-stepping can jump here. */ |
1791 |
stop_running_translated: |
stop_running_translated: |
1792 |
|
|
1793 |
debugger_n_steps_left_before_interaction = 0; |
debugger_n_steps_left_before_interaction = 0; |
1794 |
cpu->running_translated = 0; |
|
1795 |
ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; |
ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; |
1796 |
cpu->cd.DYNTRANS_ARCH.next_ic ++; |
cpu->cd.DYNTRANS_ARCH.next_ic ++; |
1797 |
|
|
1798 |
/* Execute the "nothing" instruction: */ |
/* Execute the "nothing" instruction: */ |
1799 |
ic->f(cpu, ic); |
ic->f(cpu, ic); |
1800 |
|
|
1801 |
#endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */ |
#endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */ |
1802 |
|
|