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.27 2005/10/27 14:01:13 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 1 |
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; ic->f(cpu, ic); |
98 |
|
#else |
99 |
|
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); |
100 |
|
#endif |
101 |
|
|
102 |
|
|
103 |
/* |
/* |
104 |
* XXX_cpu_run_instr(): |
* XXX_cpu_run_instr(): |
105 |
* |
* |
140 |
cpu->n_translated_instrs = 0; |
cpu->n_translated_instrs = 0; |
141 |
cpu->running_translated = 1; |
cpu->running_translated = 1; |
142 |
|
|
143 |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
144 |
|
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
145 |
|
|
146 |
if (single_step || cpu->machine->instruction_trace) { |
if (single_step || cpu->machine->instruction_trace) { |
147 |
/* |
/* |
148 |
* Single-step: |
* Single-step: |
193 |
~(COMBINATIONS | TRANSLATIONS); |
~(COMBINATIONS | TRANSLATIONS); |
194 |
} |
} |
195 |
|
|
196 |
|
if (show_opcode_statistics) |
197 |
|
S; |
198 |
|
|
199 |
/* Execute just one instruction: */ |
/* Execute just one instruction: */ |
200 |
ic->f(cpu, ic); |
ic->f(cpu, ic); |
201 |
n_instrs = 1; |
n_instrs = 1; |
202 |
} else { |
} else if (show_opcode_statistics) { |
203 |
/* Execute multiple instructions: */ |
/* Gather statistics while executing multiple instructions: */ |
204 |
n_instrs = 0; |
n_instrs = 0; |
205 |
for (;;) { |
for (;;) { |
206 |
struct DYNTRANS_IC *ic; |
struct DYNTRANS_IC *ic; |
207 |
|
|
208 |
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
S; I; S; I; S; I; S; I; S; I; S; I; |
209 |
#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; |
210 |
#else |
S; I; S; I; S; I; S; I; S; I; S; I; |
211 |
#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 |
|
212 |
|
|
213 |
I; I; I; I; I; I; I; I; I; I; |
n_instrs += 24; |
214 |
I; I; I; I; I; I; I; I; I; I; |
|
215 |
I; I; I; I; I; I; I; I; I; I; |
if (!cpu->running_translated || |
216 |
I; I; I; I; I; I; I; I; I; I; |
n_instrs + cpu->n_translated_instrs >= 16384) |
217 |
I; I; I; I; I; I; I; I; I; I; |
break; |
218 |
|
} |
219 |
|
} else { |
220 |
|
/* Execute multiple instructions: */ |
221 |
|
n_instrs = 0; |
222 |
|
for (;;) { |
223 |
|
struct DYNTRANS_IC *ic; |
224 |
|
|
225 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
226 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
229 |
I; I; I; I; I; I; I; I; I; I; |
I; I; I; I; I; I; I; I; I; I; |
230 |
|
|
231 |
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; |
|
232 |
|
|
233 |
n_instrs += 120; |
n_instrs += 60; |
234 |
|
|
235 |
if (!cpu->running_translated || |
if (!cpu->running_translated || |
236 |
n_instrs + cpu->n_translated_instrs >= 16384) |
n_instrs + cpu->n_translated_instrs >= 16384) |
431 |
instr(end_of_page); |
instr(end_of_page); |
432 |
|
|
433 |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
434 |
|
|
435 |
|
cpu->translation_cache_cur_ofs --; |
436 |
|
cpu->translation_cache_cur_ofs |= 63; |
437 |
|
cpu->translation_cache_cur_ofs ++; |
438 |
} |
} |
439 |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
440 |
|
|
462 |
#ifdef MODE32 |
#ifdef MODE32 |
463 |
int index; |
int index; |
464 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
465 |
index = cached_pc >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
466 |
#else |
#else |
467 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
468 |
uint32_t a, b; |
uint32_t a, b; |
540 |
} |
} |
541 |
} |
} |
542 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
543 |
|
#ifdef MODE32 |
544 |
|
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
545 |
|
#endif |
546 |
physaddr = paddr; |
physaddr = paddr; |
547 |
} |
} |
548 |
|
|
549 |
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) |
#ifdef MODE32 |
550 |
|
if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) { |
551 |
|
unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem, |
552 |
|
physaddr, MEM_READ); |
553 |
|
if (host_page != NULL) { |
554 |
|
int q = DYNTRANS_PAGESIZE - 1; |
555 |
|
host_page += (physaddr & |
556 |
|
((1 << BITS_PER_MEMBLOCK) - 1) & ~q); |
557 |
|
cpu->update_translation_table(cpu, cached_pc & ~q, |
558 |
|
host_page, TLB_CODE, physaddr & ~q); |
559 |
|
} |
560 |
|
} |
561 |
|
#endif |
562 |
|
|
563 |
|
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { |
564 |
|
fatal("[ dyntrans: resetting the translation cache ]\n"); |
565 |
cpu_create_or_reset_tc(cpu); |
cpu_create_or_reset_tc(cpu); |
566 |
|
} |
567 |
|
|
568 |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
569 |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
610 |
vph_p->phys_page[b] = ppp; |
vph_p->phys_page[b] = ppp; |
611 |
#endif |
#endif |
612 |
|
|
613 |
cpu->invalidate_translation_caches_paddr(cpu, physaddr, |
cpu->invalidate_translation_caches(cpu, physaddr, |
614 |
JUST_MARK_AS_NON_WRITABLE); |
JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); |
615 |
|
|
616 |
cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; |
/* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */ |
617 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
618 |
|
|
619 |
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 + |
620 |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
621 |
|
|
651 |
#ifdef MODE32 |
#ifdef MODE32 |
652 |
int index; |
int index; |
653 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
654 |
index = cached_pc >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); |
655 |
ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index]; |
ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index]; |
656 |
if (ppp != NULL) |
if (ppp != NULL) |
657 |
goto have_it; |
goto have_it; |
689 |
|
|
690 |
/* Quick return path: */ |
/* Quick return path: */ |
691 |
have_it: |
have_it: |
692 |
cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; |
/* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */ |
693 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; |
694 |
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 + |
695 |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
DYNTRANS_PC_TO_IC_ENTRY(cached_pc); |
712 |
* 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 |
713 |
* NULL). Otherwise, the entire translation is removed. |
* NULL). Otherwise, the entire translation is removed. |
714 |
*/ |
*/ |
715 |
void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu, |
static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu, |
716 |
#ifdef MODE32 |
#ifdef MODE32 |
717 |
uint32_t |
uint32_t |
718 |
#else |
#else |
721 |
vaddr_page, int flags) |
vaddr_page, int flags) |
722 |
{ |
{ |
723 |
#ifdef MODE32 |
#ifdef MODE32 |
724 |
uint32_t index = vaddr_page >> 12; |
uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
725 |
|
|
726 |
|
#ifdef DYNTRANS_ARM |
727 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] &= ~(1 << (index & 7)); |
728 |
|
#endif |
729 |
|
|
730 |
if (flags & JUST_MARK_AS_NON_WRITABLE) { |
if (flags & JUST_MARK_AS_NON_WRITABLE) { |
731 |
/* printf("JUST MARKING NON-W: vaddr 0x%08x\n", |
/* printf("JUST MARKING NON-W: vaddr 0x%08x\n", |
736 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; |
737 |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0; |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0; |
738 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
739 |
|
cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0; |
740 |
} |
} |
741 |
#else |
#else |
742 |
/* 2-level: */ |
/* 2-level: */ |
793 |
#endif |
#endif |
794 |
|
|
795 |
|
|
796 |
#ifdef DYNTRANS_INVALIDATE_TC_PADDR |
#ifdef DYNTRANS_INVALIDATE_TC |
797 |
/* |
/* |
798 |
* XXX_invalidate_translation_caches_paddr(): |
* XXX_invalidate_translation_caches(): |
799 |
* |
* |
800 |
* Invalidate all entries matching a specific physical address, a specific |
* Invalidate all entries matching a specific physical address, a specific |
801 |
* virtual address, or ALL entries. |
* virtual address, or ALL entries. |
806 |
* In the case when all translations are invalidated, paddr doesn't need |
* In the case when all translations are invalidated, paddr doesn't need |
807 |
* to be supplied. |
* to be supplied. |
808 |
* |
* |
809 |
* NOTE/TODO: Poorly choosen name for this function, as it can |
* NOTE/TODO: When invalidating a virtual address, it is only cleared from |
810 |
* invalidate based on virtual address as well. |
* the quick translation array, not from the linear |
811 |
|
* vph_tlb_entry[] array. Hopefully this is enough anyway. |
812 |
*/ |
*/ |
813 |
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) |
814 |
{ |
{ |
815 |
int r; |
int r; |
816 |
#ifdef MODE32 |
#ifdef MODE32 |
820 |
#endif |
#endif |
821 |
addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1); |
addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1); |
822 |
|
|
823 |
|
/* Quick case for virtual addresses: see note above. */ |
824 |
|
if (flags & INVALIDATE_VADDR) { |
825 |
|
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags); |
826 |
|
return; |
827 |
|
} |
828 |
|
|
829 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
830 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && ( |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && ( |
831 |
(cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page == |
(cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page == |
832 |
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) || |
|
833 |
flags & INVALIDATE_ALL) ) { |
flags & INVALIDATE_ALL) ) { |
834 |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, |
835 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, |
843 |
} |
} |
844 |
} |
} |
845 |
} |
} |
846 |
#endif /* DYNTRANS_INVALIDATE_TC_PADDR */ |
#endif /* DYNTRANS_INVALIDATE_TC */ |
847 |
|
|
848 |
|
|
849 |
|
|
857 |
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) |
858 |
{ |
{ |
859 |
int r; |
int r; |
860 |
#ifdef MODE_32 |
#ifdef MODE32 |
861 |
uint32_t |
uint32_t |
862 |
#else |
#else |
863 |
uint64_t |
uint64_t |
872 |
if (flags & INVALIDATE_PADDR) { |
if (flags & INVALIDATE_PADDR) { |
873 |
int pagenr, table_index; |
int pagenr, table_index; |
874 |
uint32_t physpage_ofs, *physpage_entryp; |
uint32_t physpage_ofs, *physpage_entryp; |
875 |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp; |
876 |
|
|
877 |
pagenr = DYNTRANS_ADDR_TO_PAGENR(addr); |
pagenr = DYNTRANS_ADDR_TO_PAGENR(addr); |
878 |
|
|
879 |
|
#ifdef MODE32 |
880 |
|
/* If this page isn't marked as having any translations, |
881 |
|
then return immediately. */ |
882 |
|
if (!(cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] |
883 |
|
& 1 << (pagenr & 31))) |
884 |
|
return; |
885 |
|
/* Remove the mark: */ |
886 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &= |
887 |
|
~ (1 << (pagenr & 31)); |
888 |
|
#endif |
889 |
|
|
890 |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
891 |
|
|
892 |
physpage_entryp = &(((uint32_t *)cpu-> |
physpage_entryp = &(((uint32_t *)cpu-> |
893 |
translation_cache)[table_index]); |
translation_cache)[table_index]); |
894 |
physpage_ofs = *physpage_entryp; |
physpage_ofs = *physpage_entryp; |
895 |
ppp = NULL; |
prev_ppp = ppp = NULL; |
896 |
|
|
897 |
/* Traverse the physical page chain: */ |
/* Traverse the physical page chain: */ |
898 |
while (physpage_ofs != 0) { |
while (physpage_ofs != 0) { |
899 |
|
prev_ppp = ppp; |
900 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
901 |
(cpu->translation_cache + physpage_ofs); |
(cpu->translation_cache + physpage_ofs); |
902 |
/* If we found the page in the cache, |
/* If we found the page in the cache, |
907 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
908 |
} |
} |
909 |
|
|
910 |
/* If the page was found, then we should invalidate all |
if (physpage_ofs == 0) |
911 |
code translations: */ |
ppp = NULL; |
912 |
|
|
913 |
|
#if 1 |
914 |
|
/* |
915 |
|
* "Bypass" the page, removing it from the code cache. |
916 |
|
* |
917 |
|
* NOTE/TODO: This gives _TERRIBLE_ performance with self- |
918 |
|
* modifying code, or when a single page is used for both |
919 |
|
* code and (writable) data. |
920 |
|
*/ |
921 |
|
if (ppp != NULL) { |
922 |
|
if (prev_ppp != NULL) |
923 |
|
prev_ppp->next_ofs = ppp->next_ofs; |
924 |
|
else |
925 |
|
*physpage_entryp = ppp->next_ofs; |
926 |
|
} |
927 |
|
#else |
928 |
|
/* |
929 |
|
* Instead of removing the page from the code cache, each |
930 |
|
* entry can be set to "to_be_translated". This is slow in |
931 |
|
* the general case, but in the case of self-modifying code, |
932 |
|
* it might be faster since we don't risk wasting cache |
933 |
|
* memory as quickly (which would force unnecessary Restarts). |
934 |
|
*/ |
935 |
if (ppp != NULL) { |
if (ppp != NULL) { |
936 |
/* TODO: Is this faster than copying an entire |
/* TODO: Is this faster than copying an entire |
937 |
template page? */ |
template page? */ |
943 |
#endif |
#endif |
944 |
instr(to_be_translated); |
instr(to_be_translated); |
945 |
} |
} |
946 |
|
#endif |
947 |
} |
} |
948 |
|
|
949 |
/* Invalidate entries in the VPH table: */ |
/* Invalidate entries (NOTE: only code entries) in the VPH table: */ |
950 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2; |
951 |
|
r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) { |
952 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
953 |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
954 |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
959 |
(flags & INVALIDATE_PADDR && paddr_page == addr) || |
(flags & INVALIDATE_PADDR && paddr_page == addr) || |
960 |
(flags & INVALIDATE_VADDR && vaddr_page == addr)) { |
(flags & INVALIDATE_VADDR && vaddr_page == addr)) { |
961 |
#ifdef MODE32 |
#ifdef MODE32 |
962 |
uint32_t index = vaddr_page >> 12; |
uint32_t index = |
963 |
|
DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
964 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
965 |
|
/* Remove the mark: */ |
966 |
|
index = DYNTRANS_ADDR_TO_PAGENR(paddr_page); |
967 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[ |
968 |
|
index >> 5] &= ~ (1 << (index & 31)); |
969 |
#else |
#else |
970 |
/* 2-level: */ |
/* 2-level: */ |
971 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1012 |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
1013 |
{ |
{ |
1014 |
int64_t lowest, highest = -1; |
int64_t lowest, highest = -1; |
1015 |
int found, r, lowest_index; |
int found, r, lowest_index, start, end, useraccess = 0; |
1016 |
|
|
1017 |
#ifdef DYNTRANS_ALPHA |
#ifdef DYNTRANS_ALPHA |
1018 |
uint32_t a, b; |
uint32_t a, b; |
1039 |
#endif |
#endif |
1040 |
#endif |
#endif |
1041 |
|
|
1042 |
|
if (writeflag & MEMORY_USER_ACCESS) { |
1043 |
|
writeflag &= ~MEMORY_USER_ACCESS; |
1044 |
|
useraccess = 1; |
1045 |
|
} |
1046 |
|
|
1047 |
|
start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2; |
1048 |
|
#if 1 |
1049 |
|
/* Half of the TLB used for data, half for code: */ |
1050 |
|
if (writeflag & TLB_CODE) { |
1051 |
|
writeflag &= ~TLB_CODE; |
1052 |
|
start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
1053 |
|
} |
1054 |
|
#else |
1055 |
|
/* Data and code entries are mixed. */ |
1056 |
|
end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
1057 |
|
#endif |
1058 |
|
|
1059 |
/* Scan the current TLB entries: */ |
/* Scan the current TLB entries: */ |
1060 |
found = -1; lowest_index = 0; |
found = -1; lowest_index = start; |
1061 |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
1062 |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
|
1063 |
|
#ifdef MODE32 |
1064 |
|
/* NOTE: vaddr_to_tlbindex is one more than the index, so that |
1065 |
|
0 becomes -1, which means a miss. */ |
1066 |
|
found = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ |
1067 |
|
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
1068 |
|
if (found < 0) |
1069 |
|
lowest_index = (random() % (end-start)) + start; |
1070 |
|
if (0) |
1071 |
|
#endif |
1072 |
|
|
1073 |
|
for (r=start; r<end; r++) { |
1074 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
1075 |
lowest = cpu->cd.DYNTRANS_ARCH. |
lowest = cpu->cd.DYNTRANS_ARCH. |
1076 |
vph_tlb_entry[r].timestamp; |
vph_tlb_entry[r].timestamp; |
1142 |
vph_p->phys_page[b] = NULL; |
vph_p->phys_page[b] = NULL; |
1143 |
#else |
#else |
1144 |
#ifdef MODE32 |
#ifdef MODE32 |
1145 |
index = vaddr_page >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
1146 |
cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; |
cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; |
1147 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
1148 |
writeflag? host_page : NULL; |
writeflag? host_page : NULL; |
1149 |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; |
cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; |
1150 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
1151 |
|
cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1; |
1152 |
|
#ifdef DYNTRANS_ARM |
1153 |
|
if (useraccess) |
1154 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] |
1155 |
|
|= 1 << (index & 7); |
1156 |
|
#endif |
1157 |
#endif /* 32 */ |
#endif /* 32 */ |
1158 |
#endif /* !ALPHA */ |
#endif /* !ALPHA */ |
1159 |
} else { |
} else { |
1163 |
* Writeflag = 1: Make sure the page is writable. |
* Writeflag = 1: Make sure the page is writable. |
1164 |
* Writeflag = -1: Downgrade to readonly. |
* Writeflag = -1: Downgrade to readonly. |
1165 |
*/ |
*/ |
1166 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp = |
r = found; |
1167 |
highest + 1; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1; |
1168 |
if (writeflag == 1) |
if (writeflag == 1) |
1169 |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; |
1170 |
if (writeflag == -1) |
if (writeflag == -1) |
1191 |
} |
} |
1192 |
#else |
#else |
1193 |
#ifdef MODE32 |
#ifdef MODE32 |
1194 |
index = vaddr_page >> 12; |
index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); |
1195 |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; |
1196 |
|
#ifdef DYNTRANS_ARM |
1197 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3]&=~(1<<(index&7)); |
1198 |
|
if (useraccess) |
1199 |
|
cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] |
1200 |
|
|= 1 << (index & 7); |
1201 |
|
#endif |
1202 |
if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { |
if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { |
1203 |
if (writeflag == 1) |
if (writeflag == 1) |
1204 |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
cpu->cd.DYNTRANS_ARCH.host_store[index] = |
1262 |
#ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL |
#ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL |
1263 |
/* |
/* |
1264 |
* If we end up here, then an instruction was translated. |
* If we end up here, then an instruction was translated. |
1265 |
|
* Mark the page as containing a translation. |
1266 |
|
* |
1267 |
|
* (Special case for 32-bit mode: set the corresponding bit in the |
1268 |
|
* phystranslation[] array.) |
1269 |
*/ |
*/ |
1270 |
translated; |
#ifdef MODE32 |
1271 |
|
if (!(cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & TRANSLATIONS)) { |
1272 |
|
uint32_t index = DYNTRANS_ADDR_TO_PAGENR(addr); |
1273 |
|
cpu->cd.DYNTRANS_ARCH.phystranslation[index >> 5] |= |
1274 |
|
(1 << (index & 31)); |
1275 |
|
} |
1276 |
|
#endif |
1277 |
|
cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= TRANSLATIONS; |
1278 |
|
|
1279 |
|
|
1280 |
/* |
/* |
1281 |
* Now it is time to check for combinations of instructions that can |
* Now it is time to check for combinations of instructions that can |
1284 |
* Note: Single-stepping or instruction tracing doesn't work with |
* Note: Single-stepping or instruction tracing doesn't work with |
1285 |
* instruction combination. |
* instruction combination. |
1286 |
*/ |
*/ |
1287 |
if (!single_step && !cpu->machine->instruction_trace) |
if (!single_step && !cpu->machine->instruction_trace) { |
1288 |
COMBINE_INSTRUCTIONS(cpu, ic, addr); |
if (cpu->combination_check != NULL && |
1289 |
|
cpu->machine->speed_tricks) |
1290 |
|
cpu->combination_check(cpu, ic, |
1291 |
|
addr & (DYNTRANS_PAGESIZE - 1)); |
1292 |
|
cpu->combination_check = NULL; |
1293 |
|
} |
1294 |
|
|
1295 |
/* ... and finally execute the translated instruction: */ |
/* ... and finally execute the translated instruction: */ |
1296 |
if (single_step_breakpoint) { |
if (single_step_breakpoint) { |