25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_dyntrans.c,v 1.19 2005/10/07 22:10:51 debug Exp $ |
* $Id: cpu_dyntrans.c,v 1.41 2005/11/23 22:03:31 debug Exp $ |
29 |
* |
* |
30 |
* Common dyntrans routines. Included from cpu_*.c. |
* Common dyntrans routines. Included from cpu_*.c. |
31 |
*/ |
*/ |
32 |
|
|
33 |
|
|
34 |
#ifdef DYNTRANS_CPU_RUN_INSTR |
#ifdef DYNTRANS_CPU_RUN_INSTR |
35 |
|
static void gather_statistics(struct cpu *cpu) |
36 |
|
{ |
37 |
|
uint64_t a; |
38 |
|
int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) |
39 |
|
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
40 |
|
if (low_pc < 0 || low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE) |
41 |
|
return; |
42 |
|
|
43 |
|
#if 0 |
44 |
|
/* Use the physical address: */ |
45 |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
46 |
|
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
47 |
|
a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr; |
48 |
|
#else |
49 |
|
/* Use the PC (virtual address): */ |
50 |
|
a = cpu->pc; |
51 |
|
#endif |
52 |
|
|
53 |
|
a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
54 |
|
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
55 |
|
a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
56 |
|
|
57 |
|
/* |
58 |
|
* TODO: Everything below this line should be cleaned up :-) |
59 |
|
*/ |
60 |
|
a &= 0x03ffffff; |
61 |
|
{ |
62 |
|
static long long *array = NULL; |
63 |
|
static char *array_16kpage_in_use = NULL; |
64 |
|
static int n = 0; |
65 |
|
a >>= DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
66 |
|
if (array == NULL) |
67 |
|
array = zeroed_alloc(sizeof(long long) * 16384*1024); |
68 |
|
if (array_16kpage_in_use == NULL) |
69 |
|
array_16kpage_in_use = zeroed_alloc(sizeof(char) * 1024); |
70 |
|
a &= (16384*1024-1); |
71 |
|
array[a] ++; |
72 |
|
array_16kpage_in_use[a / 16384] = 1; |
73 |
|
n++; |
74 |
|
if ((n & 0x3fffffff) == 0) { |
75 |
|
FILE *f = fopen("statistics.out", "w"); |
76 |
|
int i, j; |
77 |
|
printf("Saving statistics... "); fflush(stdout); |
78 |
|
for (i=0; i<1024; i++) |
79 |
|
if (array_16kpage_in_use[i]) { |
80 |
|
for (j=0; j<16384; j++) |
81 |
|
if (array[i*16384 + j] > 0) |
82 |
|
fprintf(f, "%lli\t0x%016llx\n", |
83 |
|
(long long)array[i*16384+j], |
84 |
|
(long long)((i*16384+j) << |
85 |
|
DYNTRANS_INSTR_ALIGNMENT_SHIFT)); |
86 |
|
} |
87 |
|
fclose(f); |
88 |
|
printf("n=0x%08x\n", n); |
89 |
|
} |
90 |
|
} |
91 |
|
} |
92 |
|
|
93 |
|
|
94 |
|
#define S gather_statistics(cpu) |
95 |
|
|
96 |
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
97 |
|
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \ |
98 |
|
cpu->cd.DYNTRANS_ARCH.next_ic += ic->len; \ |
99 |
|
ic->f(cpu, ic); |
100 |
|
#else |
101 |
|
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); |
102 |
|
#endif |
103 |
|
|
104 |
|
|
105 |
/* |
/* |
106 |
* XXX_cpu_run_instr(): |
* XXX_cpu_run_instr(): |
107 |
* |
* |
136 |
if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I)) |
if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I)) |
137 |
arm_exception(cpu, ARM_EXCEPTION_IRQ); |
arm_exception(cpu, ARM_EXCEPTION_IRQ); |
138 |
#endif |
#endif |
139 |
|
#ifdef DYNTRANS_PPC |
140 |
|
if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { |
141 |
|
ppc_exception(cpu, PPC_EXCEPTION_DEC); |
142 |
|
cpu->cd.ppc.dec_intr_pending = 0; |
143 |
|
} |
144 |
|
if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE) |
145 |
|
ppc_exception(cpu, PPC_EXCEPTION_EI); |
146 |
|
#endif |
147 |
|
|
148 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
149 |
|
|
150 |
cpu->n_translated_instrs = 0; |
cpu->n_translated_instrs = 0; |
151 |
cpu->running_translated = 1; |
cpu->running_translated = 1; |
152 |
|
|
153 |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
154 |
|
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
155 |
|
|
156 |
if (single_step || cpu->machine->instruction_trace) { |
if (single_step || cpu->machine->instruction_trace) { |
157 |
/* |
/* |
158 |
* Single-step: |
* Single-step: |
203 |
~(COMBINATIONS | TRANSLATIONS); |
~(COMBINATIONS | TRANSLATIONS); |
204 |
} |
} |
205 |
|
|
206 |
|
if (show_opcode_statistics) |
207 |
|
S; |
208 |
|
|
209 |
/* Execute just one instruction: */ |
/* Execute just one instruction: */ |
210 |
ic->f(cpu, ic); |
ic->f(cpu, ic); |
211 |
n_instrs = 1; |
n_instrs = 1; |
212 |
} else { |
} else if (show_opcode_statistics) { |
213 |
/* Execute multiple instructions: */ |
/* Gather statistics while executing multiple instructions: */ |
214 |
n_instrs = 0; |
n_instrs = 0; |
215 |
for (;;) { |
for (;;) { |
216 |
struct DYNTRANS_IC *ic; |
struct DYNTRANS_IC *ic; |
217 |
|
|
218 |
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
S; I; S; I; S; I; S; I; S; I; S; I; |
219 |
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic); |
S; I; S; I; S; I; S; I; S; I; S; I; |
220 |
#else |
S; I; S; I; S; I; S; I; S; I; S; I; |
221 |
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); |
S; I; S; I; S; I; S; I; S; I; S; I; |
|
#endif |
|
222 |
|
|
223 |
I; I; I; I; I; I; I; I; I; I; |
n_instrs += 24; |
224 |
I; I; I; I; I; I; I; I; I; I; |
|
225 |
I; I; I; I; I; I; I; I; I; I; |
if (!cpu->running_translated || |
226 |
I; I; I; I; I; I; I; I; I; I; |
n_instrs + cpu->n_translated_instrs >= 16384) |
227 |
I; I; I; I; I; I; I; I; I; I; |
break; |
228 |
|
} |
229 |
|
} else { |
230 |
|
/* Execute multiple instructions: */ |
231 |
|
n_instrs = 0; |
232 |
|
for (;;) { |
233 |
|
struct DYNTRANS_IC *ic; |
234 |
|
|
235 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
236 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
239 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
240 |
|
|
241 |
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; |
|
242 |
|
|
243 |
n_instrs += 120; |
n_instrs += 60; |
244 |
|
|
245 |
if (!cpu->running_translated || |
if (!cpu->running_translated || |
246 |
n_instrs + cpu->n_translated_instrs >= 16384) |
n_instrs + cpu->n_translated_instrs >= 16384) |
248 |
} |
} |
249 |
} |
} |
250 |
|
|
251 |
|
n_instrs += cpu->n_translated_instrs; |
252 |
|
|
253 |
/* |
/* Synchronize the program counter: */ |
|
* Update the program counter and return the correct number of |
|
|
* executed instructions: |
|
|
*/ |
|
254 |
low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) |
low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) |
255 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
|
|
|
256 |
if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) { |
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 |
|
257 |
cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
258 |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
259 |
cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
|
#endif |
|
260 |
} else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) { |
} else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) { |
261 |
/* Switch to next 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 |
|
262 |
cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
263 |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
264 |
cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE << |
cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE << |
265 |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
|
#endif |
|
|
} else { |
|
|
/* debug("debug: Outside a page (This is actually ok)\n"); */ |
|
266 |
} |
} |
267 |
|
|
268 |
return n_instrs + cpu->n_translated_instrs; |
#ifdef DYNTRANS_PPC |
269 |
|
/* Update the Decrementer and Time base registers: */ |
270 |
|
{ |
271 |
|
uint32_t old = cpu->cd.ppc.spr[SPR_DEC]; |
272 |
|
cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs); |
273 |
|
if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1) |
274 |
|
cpu->cd.ppc.dec_intr_pending = 1; |
275 |
|
|
276 |
|
old = cpu->cd.ppc.spr[SPR_TBL]; |
277 |
|
cpu->cd.ppc.spr[SPR_TBL] += n_instrs; |
278 |
|
if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0) |
279 |
|
cpu->cd.ppc.spr[SPR_TBU] ++; |
280 |
|
} |
281 |
|
#endif |
282 |
|
|
283 |
|
/* Return the nr of instructions executed: */ |
284 |
|
return n_instrs; |
285 |
} |
} |
286 |
#endif /* DYNTRANS_CPU_RUN_INSTR */ |
#endif /* DYNTRANS_CPU_RUN_INSTR */ |
287 |
|
|
361 |
#ifdef DYNTRANS_MIPS |
#ifdef DYNTRANS_MIPS |
362 |
gpr[MIPS_GPR_A0 |
gpr[MIPS_GPR_A0 |
363 |
#endif |
#endif |
364 |
|
#ifdef DYNTRANS_NEWMIPS |
365 |
|
r[0 /* TODO */ |
366 |
|
#endif |
367 |
#ifdef DYNTRANS_PPC |
#ifdef DYNTRANS_PPC |
368 |
gpr[3 |
gpr[3 |
369 |
#endif |
#endif |
443 |
instr(end_of_page); |
instr(end_of_page); |
444 |
|
|
445 |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
446 |
|
|
447 |
|
cpu->translation_cache_cur_ofs --; |
448 |
|
cpu->translation_cache_cur_ofs |= 63; |
449 |
|
cpu->translation_cache_cur_ofs ++; |
450 |
} |
} |
451 |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
452 |
|
|
465 |
#else |
#else |
466 |
uint64_t |
uint64_t |
467 |
#endif |
#endif |
468 |
cached_pc, physaddr; |
cached_pc, physaddr = 0; |
469 |
uint32_t physpage_ofs; |
uint32_t physpage_ofs; |
470 |
int ok, pagenr, table_index; |
int ok, pagenr, table_index; |
471 |
uint32_t *physpage_entryp; |
uint32_t *physpage_entryp; |
474 |
#ifdef MODE32 |
#ifdef MODE32 |
475 |
int index; |
int index; |
476 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
477 |
index = cached_pc >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
478 |
#else |
#else |
479 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
480 |
uint32_t a, b; |
uint32_t a, b; |
531 |
ok = 1; |
ok = 1; |
532 |
} |
} |
533 |
if (!ok) { |
if (!ok) { |
534 |
/* |
/* fatal("TODO: instruction vaddr=>paddr translation" |
|
fatal("TODO: instruction vaddr=>paddr translation" |
|
535 |
" failed. vaddr=0x%llx\n", (long long)cached_pc); |
" failed. vaddr=0x%llx\n", (long long)cached_pc); |
536 |
fatal("!! cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc, |
fatal("!! cpu->pc=0x%llx\n", (long long)cpu->pc); */ |
537 |
cpu->cd.arm.r[ARM_PC]); |
|
|
*/ |
|
538 |
ok = cpu->translate_address(cpu, cpu->pc, &paddr, |
ok = cpu->translate_address(cpu, cpu->pc, &paddr, |
539 |
FLAG_INSTR); |
FLAG_INSTR); |
540 |
/* |
|
541 |
printf("EXCEPTION HANDLER: vaddr = 0x%x ==> paddr = 0x%x\n", |
/* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> " |
542 |
(int)cpu->pc, (int)paddr); |
"paddr = 0x%x\n", (int)cpu->pc, (int)paddr); |
543 |
fatal("!? cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc, |
fatal("!? cpu->pc=0x%llx\n", (long long)cpu->pc); */ |
544 |
cpu->cd.arm.r[ARM_PC]); |
|
|
*/ |
|
545 |
if (!ok) { |
if (!ok) { |
546 |
fatal("FATAL: could not find physical" |
fatal("FATAL: could not find physical" |
547 |
" address of the exception handler?"); |
" address of the exception handler?"); |
549 |
} |
} |
550 |
} |
} |
551 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
552 |
|
#ifdef MODE32 |
553 |
|
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
554 |
|
#endif |
555 |
physaddr = paddr; |
physaddr = paddr; |
556 |
} |
} |
557 |
|
|
558 |
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) |
#ifdef MODE32 |
559 |
|
if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) { |
560 |
|
unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem, |
561 |
|
physaddr, MEM_READ); |
562 |
|
if (host_page != NULL) { |
563 |
|
int q = DYNTRANS_PAGESIZE - 1; |
564 |
|
host_page += (physaddr & |
565 |
|
((1 << BITS_PER_MEMBLOCK) - 1) & ~q); |
566 |
|
cpu->update_translation_table(cpu, cached_pc & ~q, |
567 |
|
host_page, TLB_CODE, physaddr & ~q); |
568 |
|
} |
569 |
|
} |
570 |
|
#endif |
571 |
|
|
572 |
|
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { |
573 |
|
debug("[ dyntrans: resetting the translation cache ]\n"); |
574 |
cpu_create_or_reset_tc(cpu); |
cpu_create_or_reset_tc(cpu); |
575 |
|
} |
576 |
|
|
577 |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
578 |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
619 |
vph_p->phys_page[b] = ppp; |
vph_p->phys_page[b] = ppp; |
620 |
#endif |
#endif |
621 |
|
|
622 |
cpu->invalidate_translation_caches_paddr(cpu, physaddr, |
#ifdef MODE32 |
623 |
JUST_MARK_AS_NON_WRITABLE); |
/* Small optimization: only mark the physical page as non-writable |
624 |
|
if it did not contain translations. (Because if it does contain |
625 |
|
translations, it is already non-writable.) */ |
626 |
|
if (!cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] & |
627 |
|
(1 << (pagenr & 31))) |
628 |
|
#endif |
629 |
|
cpu->invalidate_translation_caches(cpu, physaddr, |
630 |
|
JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); |
631 |
|
|
|
cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; |
|
632 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
633 |
|
|
634 |
cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + |
cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + |
635 |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
636 |
|
|
666 |
#ifdef MODE32 |
#ifdef MODE32 |
667 |
int index; |
int index; |
668 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
669 |
index = cached_pc >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
670 |
ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index]; |
ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index]; |
671 |
if (ppp != NULL) |
if (ppp != NULL) |
672 |
goto have_it; |
goto have_it; |
689 |
goto have_it; |
goto have_it; |
690 |
} |
} |
691 |
#else |
#else |
692 |
|
/* Temporary, to avoid a compiler warning: */ |
693 |
|
cached_pc = 0; |
694 |
|
ppp = NULL; |
695 |
#ifdef DYNTRANS_IA64 |
#ifdef DYNTRANS_IA64 |
696 |
fatal("IA64 todo\n"); |
fatal("IA64 todo\n"); |
697 |
#else |
#else |
698 |
fatal("Neither alpha, ia64, nor 32-bit? 1\n"); |
fatal("Neither alpha, ia64, nor 32-bit? 1\n"); |
|
{ char *p = (char *) 0; *p = 0; } |
|
699 |
exit(1); |
exit(1); |
700 |
#endif |
#endif |
701 |
#endif |
#endif |
705 |
return; |
return; |
706 |
|
|
707 |
/* Quick return path: */ |
/* Quick return path: */ |
708 |
|
#if defined(MODE32) || defined(DYNTRANS_ALPHA) |
709 |
have_it: |
have_it: |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; |
|
710 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
711 |
cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + |
cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + |
712 |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
714 |
/* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, " |
/* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, " |
715 |
"physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr, |
"physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr, |
716 |
(long long)table_index, (long long)physpage_ofs); */ |
(long long)table_index, (long long)physpage_ofs); */ |
717 |
|
#endif |
718 |
} |
} |
719 |
#endif /* DYNTRANS_PC_TO_POINTERS_FUNC */ |
#endif /* DYNTRANS_PC_TO_POINTERS_FUNC */ |
720 |
|
|
730 |
* is just downgraded to non-writable (ie the host store page is set to |
* is just downgraded to non-writable (ie the host store page is set to |
731 |
* NULL). Otherwise, the entire translation is removed. |
* NULL). Otherwise, the entire translation is removed. |
732 |
*/ |
*/ |
733 |
void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu, |
static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu, |
734 |
#ifdef MODE32 |
#ifdef MODE32 |
735 |
uint32_t |
uint32_t |
736 |
#else |
#else |
739 |
vaddr_page, int flags) |
vaddr_page, int flags) |
740 |
{ |
{ |
741 |
#ifdef MODE32 |
#ifdef MODE32 |
742 |
uint32_t index = vaddr_page >> 12; |
uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
743 |
|
|
744 |
|
#ifdef DYNTRANS_ARM |
745 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31)); |
746 |
|
#endif |
747 |
|
|
748 |
if (flags & JUST_MARK_AS_NON_WRITABLE) { |
if (flags & JUST_MARK_AS_NON_WRITABLE) { |
749 |
/* printf("JUST MARKING NON-W: vaddr 0x%08x\n", |
/* printf("JUST MARKING NON-W: vaddr 0x%08x\n", |
754 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
755 |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0; |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0; |
756 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
757 |
|
cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0; |
758 |
} |
} |
759 |
#else |
#else |
760 |
/* 2-level: */ |
/* 2-level: */ |
811 |
#endif |
#endif |
812 |
|
|
813 |
|
|
814 |
#ifdef DYNTRANS_INVALIDATE_TC_PADDR |
#ifdef DYNTRANS_INVALIDATE_TC |
815 |
/* |
/* |
816 |
* XXX_invalidate_translation_caches_paddr(): |
* XXX_invalidate_translation_caches(): |
817 |
* |
* |
818 |
* Invalidate all entries matching a specific physical address, a specific |
* Invalidate all entries matching a specific physical address, a specific |
819 |
* virtual address, or ALL entries. |
* virtual address, or ALL entries. |
824 |
* In the case when all translations are invalidated, paddr doesn't need |
* In the case when all translations are invalidated, paddr doesn't need |
825 |
* to be supplied. |
* to be supplied. |
826 |
* |
* |
827 |
* NOTE/TODO: Poorly choosen name for this function, as it can |
* NOTE/TODO: When invalidating a virtual address, it is only cleared from |
828 |
* invalidate based on virtual address as well. |
* the quick translation array, not from the linear |
829 |
|
* vph_tlb_entry[] array. Hopefully this is enough anyway. |
830 |
*/ |
*/ |
831 |
void DYNTRANS_INVALIDATE_TC_PADDR(struct cpu *cpu, uint64_t paddr, int flags) |
void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t paddr, int flags) |
832 |
{ |
{ |
833 |
int r; |
int r; |
834 |
#ifdef MODE32 |
#ifdef MODE32 |
838 |
#endif |
#endif |
839 |
addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1); |
addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1); |
840 |
|
|
841 |
|
/* fatal("invalidate(): "); */ |
842 |
|
|
843 |
|
/* Quick case for virtual addresses: see note above. */ |
844 |
|
if (flags & INVALIDATE_VADDR) { |
845 |
|
/* fatal("vaddr 0x%08x\n", (int)addr_page); */ |
846 |
|
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags); |
847 |
|
return; |
848 |
|
} |
849 |
|
|
850 |
|
if (flags & INVALIDATE_ALL) { |
851 |
|
/* fatal("all\n"); */ |
852 |
|
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
853 |
|
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
854 |
|
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd. |
855 |
|
DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, |
856 |
|
0); |
857 |
|
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0; |
858 |
|
} |
859 |
|
} |
860 |
|
return; |
861 |
|
} |
862 |
|
|
863 |
|
/* fatal("paddr 0x%08x\n", (int)addr_page); */ |
864 |
|
|
865 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
866 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && ( |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && ( |
867 |
(cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page == |
(cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page == |
868 |
addr_page && flags & INVALIDATE_PADDR) || |
addr_page && flags & INVALIDATE_PADDR) || |
|
(cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page == |
|
|
addr_page && flags & INVALIDATE_VADDR) || |
|
869 |
flags & INVALIDATE_ALL) ) { |
flags & INVALIDATE_ALL) ) { |
870 |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
871 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, |
879 |
} |
} |
880 |
} |
} |
881 |
} |
} |
882 |
#endif /* DYNTRANS_INVALIDATE_TC_PADDR */ |
#endif /* DYNTRANS_INVALIDATE_TC */ |
883 |
|
|
884 |
|
|
885 |
|
|
893 |
void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags) |
void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags) |
894 |
{ |
{ |
895 |
int r; |
int r; |
896 |
#ifdef MODE_32 |
#ifdef MODE32 |
897 |
uint32_t |
uint32_t |
898 |
#else |
#else |
899 |
uint64_t |
uint64_t |
908 |
if (flags & INVALIDATE_PADDR) { |
if (flags & INVALIDATE_PADDR) { |
909 |
int pagenr, table_index; |
int pagenr, table_index; |
910 |
uint32_t physpage_ofs, *physpage_entryp; |
uint32_t physpage_ofs, *physpage_entryp; |
911 |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp; |
912 |
|
|
913 |
pagenr = DYNTRANS_ADDR_TO_PAGENR(addr); |
pagenr = DYNTRANS_ADDR_TO_PAGENR(addr); |
914 |
|
|
915 |
|
#ifdef MODE32 |
916 |
|
/* If this page isn't marked as having any translations, |
917 |
|
then return immediately. */ |
918 |
|
if (!(cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] |
919 |
|
& 1 << (pagenr & 31))) |
920 |
|
return; |
921 |
|
/* Remove the mark: */ |
922 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &= |
923 |
|
~ (1 << (pagenr & 31)); |
924 |
|
#endif |
925 |
|
|
926 |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
927 |
|
|
928 |
physpage_entryp = &(((uint32_t *)cpu-> |
physpage_entryp = &(((uint32_t *)cpu-> |
929 |
translation_cache)[table_index]); |
translation_cache)[table_index]); |
930 |
physpage_ofs = *physpage_entryp; |
physpage_ofs = *physpage_entryp; |
931 |
ppp = NULL; |
prev_ppp = ppp = NULL; |
932 |
|
|
933 |
/* Traverse the physical page chain: */ |
/* Traverse the physical page chain: */ |
934 |
while (physpage_ofs != 0) { |
while (physpage_ofs != 0) { |
935 |
|
prev_ppp = ppp; |
936 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
937 |
(cpu->translation_cache + physpage_ofs); |
(cpu->translation_cache + physpage_ofs); |
938 |
/* If we found the page in the cache, |
/* If we found the page in the cache, |
943 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
944 |
} |
} |
945 |
|
|
946 |
/* If the page was found, then we should invalidate all |
if (physpage_ofs == 0) |
947 |
code translations: */ |
ppp = NULL; |
948 |
|
|
949 |
|
#if 1 |
950 |
|
/* |
951 |
|
* "Bypass" the page, removing it from the code cache. |
952 |
|
* |
953 |
|
* NOTE/TODO: This gives _TERRIBLE_ performance with self- |
954 |
|
* modifying code, or when a single page is used for both |
955 |
|
* code and (writable) data. |
956 |
|
*/ |
957 |
|
if (ppp != NULL) { |
958 |
|
if (prev_ppp != NULL) |
959 |
|
prev_ppp->next_ofs = ppp->next_ofs; |
960 |
|
else |
961 |
|
*physpage_entryp = ppp->next_ofs; |
962 |
|
} |
963 |
|
#else |
964 |
|
/* |
965 |
|
* Instead of removing the page from the code cache, each |
966 |
|
* entry can be set to "to_be_translated". This is slow in |
967 |
|
* the general case, but in the case of self-modifying code, |
968 |
|
* it might be faster since we don't risk wasting cache |
969 |
|
* memory as quickly (which would force unnecessary Restarts). |
970 |
|
*/ |
971 |
if (ppp != NULL) { |
if (ppp != NULL) { |
972 |
/* TODO: Is this faster than copying an entire |
/* TODO: Is this faster than copying an entire |
973 |
template page? */ |
template page? */ |
979 |
#endif |
#endif |
980 |
instr(to_be_translated); |
instr(to_be_translated); |
981 |
} |
} |
982 |
|
#endif |
983 |
} |
} |
984 |
|
|
985 |
/* Invalidate entries in the VPH table: */ |
/* Invalidate entries (NOTE: only code entries) in the VPH table: */ |
986 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2; |
987 |
|
r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) { |
988 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
989 |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
990 |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
995 |
(flags & INVALIDATE_PADDR && paddr_page == addr) || |
(flags & INVALIDATE_PADDR && paddr_page == addr) || |
996 |
(flags & INVALIDATE_VADDR && vaddr_page == addr)) { |
(flags & INVALIDATE_VADDR && vaddr_page == addr)) { |
997 |
#ifdef MODE32 |
#ifdef MODE32 |
998 |
uint32_t index = vaddr_page >> 12; |
uint32_t index = |
999 |
|
DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
1000 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
1001 |
|
/* Remove the mark: */ |
1002 |
|
index = DYNTRANS_ADDR_TO_PAGENR(paddr_page); |
1003 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[ |
1004 |
|
index >> 5] &= ~ (1 << (index & 31)); |
1005 |
#else |
#else |
1006 |
/* 2-level: */ |
/* 2-level: */ |
1007 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1047 |
void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, |
void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, |
1048 |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
1049 |
{ |
{ |
1050 |
|
#ifndef MODE32 |
1051 |
int64_t lowest, highest = -1; |
int64_t lowest, highest = -1; |
1052 |
int found, r, lowest_index; |
#endif |
1053 |
|
int found, r, lowest_index, start, end, useraccess = 0; |
1054 |
|
|
1055 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1056 |
uint32_t a, b; |
uint32_t a, b; |
1077 |
#endif |
#endif |
1078 |
#endif |
#endif |
1079 |
|
|
1080 |
|
if (writeflag & MEMORY_USER_ACCESS) { |
1081 |
|
writeflag &= ~MEMORY_USER_ACCESS; |
1082 |
|
useraccess = 1; |
1083 |
|
} |
1084 |
|
|
1085 |
|
start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2; |
1086 |
|
#if 1 |
1087 |
|
/* Half of the TLB used for data, half for code: */ |
1088 |
|
if (writeflag & TLB_CODE) { |
1089 |
|
writeflag &= ~TLB_CODE; |
1090 |
|
start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
1091 |
|
} |
1092 |
|
#else |
1093 |
|
/* Data and code entries are mixed. */ |
1094 |
|
end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
1095 |
|
#endif |
1096 |
|
|
1097 |
/* Scan the current TLB entries: */ |
/* Scan the current TLB entries: */ |
1098 |
found = -1; lowest_index = 0; |
lowest_index = start; |
1099 |
|
|
1100 |
|
#ifdef MODE32 |
1101 |
|
/* |
1102 |
|
* NOTE 1: vaddr_to_tlbindex is one more than the index, so that |
1103 |
|
* 0 becomes -1, which means a miss. |
1104 |
|
* |
1105 |
|
* NOTE 2: When a miss occurs, instead of scanning the entire tlb |
1106 |
|
* for the entry with the lowest time stamp, just choosing |
1107 |
|
* one at random will work as well. |
1108 |
|
*/ |
1109 |
|
found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ |
1110 |
|
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
1111 |
|
if (found < 0) { |
1112 |
|
static unsigned int x = 0; |
1113 |
|
lowest_index = (x % (end-start)) + start; |
1114 |
|
x ++; |
1115 |
|
} |
1116 |
|
#else |
1117 |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
1118 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
found = -1; |
1119 |
|
for (r=start; r<end; r++) { |
1120 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
1121 |
lowest = cpu->cd.DYNTRANS_ARCH. |
lowest = cpu->cd.DYNTRANS_ARCH. |
1122 |
vph_tlb_entry[r].timestamp; |
vph_tlb_entry[r].timestamp; |
1132 |
break; |
break; |
1133 |
} |
} |
1134 |
} |
} |
1135 |
|
#endif |
1136 |
|
|
1137 |
if (found < 0) { |
if (found < 0) { |
1138 |
/* Create the new TLB entry, overwriting the oldest one: */ |
/* Create the new TLB entry, overwriting the oldest one: */ |
1148 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page; |
1149 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page; |
1150 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; |
1151 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = |
1152 |
|
writeflag & MEM_WRITE; |
1153 |
|
#ifndef MODE32 |
1154 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
1155 |
|
#endif |
1156 |
|
|
1157 |
/* Add the new translation to the table: */ |
/* Add the new translation to the table: */ |
1158 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1192 |
vph_p->phys_page[b] = NULL; |
vph_p->phys_page[b] = NULL; |
1193 |
#else |
#else |
1194 |
#ifdef MODE32 |
#ifdef MODE32 |
1195 |
index = vaddr_page >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
1196 |
cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; |
cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; |
1197 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
1198 |
writeflag? host_page : NULL; |
writeflag? host_page : NULL; |
1199 |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; |
1200 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
1201 |
|
cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1; |
1202 |
|
#ifdef DYNTRANS_ARM |
1203 |
|
if (useraccess) |
1204 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] |
1205 |
|
|= 1 << (index & 31); |
1206 |
|
#endif |
1207 |
#endif /* 32 */ |
#endif /* 32 */ |
1208 |
#endif /* !ALPHA */ |
#endif /* !ALPHA */ |
1209 |
} else { |
} else { |
1211 |
* The translation was already in the TLB. |
* The translation was already in the TLB. |
1212 |
* Writeflag = 0: Do nothing. |
* Writeflag = 0: Do nothing. |
1213 |
* Writeflag = 1: Make sure the page is writable. |
* Writeflag = 1: Make sure the page is writable. |
1214 |
* Writeflag = -1: Downgrade to readonly. |
* Writeflag = MEM_DOWNGRADE: Downgrade to readonly. |
1215 |
*/ |
*/ |
1216 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp = |
r = found; |
1217 |
highest + 1; |
#ifndef MODE32 |
1218 |
if (writeflag == 1) |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
1219 |
|
#endif |
1220 |
|
if (writeflag & MEM_WRITE) |
1221 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
1222 |
if (writeflag == -1) |
if (writeflag & MEM_DOWNGRADE) |
1223 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0; |
1224 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1225 |
a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1); |
a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1); |
1231 |
vph_p = cpu->cd.alpha.vph_table0[a]; |
vph_p = cpu->cd.alpha.vph_table0[a]; |
1232 |
vph_p->phys_page[b] = NULL; |
vph_p->phys_page[b] = NULL; |
1233 |
if (vph_p->phys_addr[b] == paddr_page) { |
if (vph_p->phys_addr[b] == paddr_page) { |
1234 |
if (writeflag == 1) |
if (writeflag & MEM_WRITE) |
1235 |
vph_p->host_store[b] = host_page; |
vph_p->host_store[b] = host_page; |
1236 |
if (writeflag == -1) |
if (writeflag & MEM_DOWNGRADE) |
1237 |
vph_p->host_store[b] = NULL; |
vph_p->host_store[b] = NULL; |
1238 |
} else { |
} else { |
1239 |
/* Change the entire physical/host mapping: */ |
/* Change the entire physical/host mapping: */ |
1243 |
} |
} |
1244 |
#else |
#else |
1245 |
#ifdef MODE32 |
#ifdef MODE32 |
1246 |
index = vaddr_page >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
1247 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
1248 |
|
#ifdef DYNTRANS_ARM |
1249 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31)); |
1250 |
|
if (useraccess) |
1251 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] |
1252 |
|
|= 1 << (index & 31); |
1253 |
|
#endif |
1254 |
if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { |
if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { |
1255 |
if (writeflag == 1) |
if (writeflag & MEM_WRITE) |
1256 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
1257 |
host_page; |
host_page; |
1258 |
if (writeflag == -1) |
if (writeflag & MEM_DOWNGRADE) |
1259 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
1260 |
} else { |
} else { |
1261 |
/* Change the entire physical/host mapping: */ |
/* Change the entire physical/host mapping: */ |
1314 |
#ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL |
#ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL |
1315 |
/* |
/* |
1316 |
* If we end up here, then an instruction was translated. |
* If we end up here, then an instruction was translated. |
1317 |
|
* Mark the page as containing a translation. |
1318 |
|
* |
1319 |
|
* (Special case for 32-bit mode: set the corresponding bit in the |
1320 |
|
* phystranslation[] array.) |
1321 |
*/ |
*/ |
1322 |
translated; |
#ifdef MODE32 |
1323 |
|
if (!(cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & TRANSLATIONS)) { |
1324 |
|
uint32_t index = DYNTRANS_ADDR_TO_PAGENR(addr); |
1325 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[index >> 5] |= |
1326 |
|
(1 << (index & 31)); |
1327 |
|
} |
1328 |
|
#endif |
1329 |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= TRANSLATIONS; |
1330 |
|
|
1331 |
|
|
1332 |
/* |
/* |
1333 |
* Now it is time to check for combinations of instructions that can |
* Now it is time to check for combinations of instructions that can |
1336 |
* Note: Single-stepping or instruction tracing doesn't work with |
* Note: Single-stepping or instruction tracing doesn't work with |
1337 |
* instruction combination. |
* instruction combination. |
1338 |
*/ |
*/ |
1339 |
if (!single_step && !cpu->machine->instruction_trace) |
if (!single_step && !cpu->machine->instruction_trace) { |
1340 |
COMBINE_INSTRUCTIONS(cpu, ic, addr); |
if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL && |
1341 |
|
cpu->machine->speed_tricks) |
1342 |
|
cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, |
1343 |
|
addr & (DYNTRANS_PAGESIZE - 1)); |
1344 |
|
cpu->cd.DYNTRANS_ARCH.combination_check = NULL; |
1345 |
|
} |
1346 |
|
|
1347 |
/* ... and finally execute the translated instruction: */ |
/* ... and finally execute the translated instruction: */ |
1348 |
if (single_step_breakpoint) { |
if (single_step_breakpoint) { |