25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_dyntrans.c,v 1.145 2007/04/10 17:26:20 debug Exp $ |
* $Id: cpu_dyntrans.c,v 1.186 2007/07/20 09:03:33 debug Exp $ |
29 |
* |
* |
30 |
* Common dyntrans routines. Included from cpu_*.c. |
* Common dyntrans routines. Included from cpu_*.c. |
31 |
|
* |
32 |
|
* Note: This might be a bit hard to follow, if you are reading this source |
33 |
|
* code for the first time. It is basically a hack to implement "templates" |
34 |
|
* with normal C code, by using suitable defines/macros, and then including |
35 |
|
* this file. |
36 |
*/ |
*/ |
37 |
|
|
38 |
|
|
50 |
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) |
51 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); |
52 |
|
|
53 |
if (cpu->machine->statistics_file == NULL) { |
if (cpu->machine->statistics.file == NULL) { |
54 |
fatal("statistics gathering with no filename set is" |
fatal("statistics gathering with no filename set is" |
55 |
" meaningless\n"); |
" meaningless\n"); |
56 |
return; |
return; |
57 |
} |
} |
58 |
|
|
59 |
|
/* low_pc must be within the page! */ |
60 |
|
if (low_pc < 0 || low_pc > DYNTRANS_IC_ENTRIES_PER_PAGE) |
61 |
|
return; |
62 |
|
|
63 |
buf[0] = '\0'; |
buf[0] = '\0'; |
64 |
|
|
65 |
while ((ch = cpu->machine->statistics_fields[i]) != '\0') { |
while ((ch = cpu->machine->statistics.fields[i]) != '\0') { |
66 |
if (i != 0) |
if (i != 0) |
67 |
strlcat(buf, " ", sizeof(buf)); |
strlcat(buf, " ", sizeof(buf)); |
68 |
|
|
73 |
break; |
break; |
74 |
case 'p': |
case 'p': |
75 |
/* Physical program counter address: */ |
/* Physical program counter address: */ |
|
/* (low_pc must be within the page!) */ |
|
|
if (low_pc < 0 || |
|
|
low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE) |
|
|
strlcat(buf, "-", sizeof(buf)); |
|
76 |
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *) |
77 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
cpu->cd.DYNTRANS_ARCH.cur_ic_page; |
78 |
a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr; |
a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr; |
81 |
a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
82 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
83 |
snprintf(buf + strlen(buf), sizeof(buf), |
snprintf(buf + strlen(buf), sizeof(buf), |
84 |
"0x%016"PRIx32, (uint32_t)a); |
"0x%08"PRIx32, (uint32_t)a); |
85 |
else |
else |
86 |
snprintf(buf + strlen(buf), sizeof(buf), |
snprintf(buf + strlen(buf), sizeof(buf), |
87 |
"0x%016"PRIx64, (uint64_t)a); |
"0x%016"PRIx64, (uint64_t)a); |
88 |
break; |
break; |
89 |
case 'v': |
case 'v': |
90 |
/* Virtual program counter address: */ |
/* Virtual program counter address: */ |
|
/* (low_pc inside the page, or in a delay slot) */ |
|
|
if (low_pc < 0 || |
|
|
low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE + 2) |
|
|
strlcat(buf, "-", sizeof(buf)); |
|
91 |
a = cpu->pc; |
a = cpu->pc; |
92 |
a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << |
93 |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
DYNTRANS_INSTR_ALIGNMENT_SHIFT); |
94 |
a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; |
95 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
96 |
snprintf(buf + strlen(buf), sizeof(buf), |
snprintf(buf + strlen(buf), sizeof(buf), |
97 |
"0x%016"PRIx32, (uint32_t)a); |
"0x%08"PRIx32, (uint32_t)a); |
98 |
else |
else |
99 |
snprintf(buf + strlen(buf), sizeof(buf), |
snprintf(buf + strlen(buf), sizeof(buf), |
100 |
"0x%016"PRIx64, (uint64_t)a); |
"0x%016"PRIx64, (uint64_t)a); |
103 |
i++; |
i++; |
104 |
} |
} |
105 |
|
|
106 |
fprintf(cpu->machine->statistics_file, "%s\n", buf); |
fprintf(cpu->machine->statistics.file, "%s\n", buf); |
107 |
} |
} |
108 |
|
|
109 |
|
|
110 |
#define S gather_statistics(cpu) |
#define S gather_statistics(cpu) |
111 |
|
|
112 |
|
|
113 |
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
#if 1 |
|
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \ |
|
|
cpu->cd.DYNTRANS_ARCH.next_ic += ic->arg[0]; \ |
|
|
ic->f(cpu, ic); |
|
|
#else |
|
114 |
|
|
115 |
/* The normal instruction execution core: */ |
/* The normal instruction execution core: */ |
116 |
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); |
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); |
117 |
|
|
118 |
|
#else |
119 |
|
|
120 |
/* For heavy debugging: */ |
/* For heavy debugging: */ |
121 |
/* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \ |
#define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \ |
122 |
{ \ |
{ \ |
123 |
int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \ |
int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \ |
124 |
(size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \ |
(size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \ |
127 |
cpu->cd.DYNTRANS_ARCH.cur_ic_page, \ |
cpu->cd.DYNTRANS_ARCH.cur_ic_page, \ |
128 |
ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \ |
ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \ |
129 |
} \ |
} \ |
130 |
ic->f(cpu, ic); */ |
ic->f(cpu, ic); |
131 |
|
|
132 |
|
#endif |
133 |
|
|
134 |
/* static long long nr_of_I_calls = 0; */ |
/* static long long nr_of_I_calls = 0; */ |
135 |
|
|
162 |
} \ |
} \ |
163 |
ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); } |
ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); } |
164 |
*/ |
*/ |
|
#endif |
|
165 |
#endif /* STATIC STUFF */ |
#endif /* STATIC STUFF */ |
166 |
|
|
167 |
|
|
168 |
|
|
169 |
#ifdef DYNTRANS_RUN_INSTR |
#ifdef DYNTRANS_RUN_INSTR_DEF |
170 |
/* |
/* |
171 |
* XXX_run_instr(): |
* XXX_run_instr(): |
172 |
* |
* |
176 |
* Return value is the number of instructions executed during this call, |
* Return value is the number of instructions executed during this call, |
177 |
* 0 if no instructions were executed. |
* 0 if no instructions were executed. |
178 |
*/ |
*/ |
179 |
int DYNTRANS_RUN_INSTR(struct cpu *cpu) |
int DYNTRANS_RUN_INSTR_DEF(struct cpu *cpu) |
180 |
{ |
{ |
181 |
MODE_uint_t cached_pc; |
MODE_uint_t cached_pc; |
182 |
int low_pc, n_instrs; |
int low_pc, n_instrs; |
204 |
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)) |
205 |
arm_exception(cpu, ARM_EXCEPTION_IRQ); |
arm_exception(cpu, ARM_EXCEPTION_IRQ); |
206 |
#endif |
#endif |
207 |
|
#ifdef DYNTRANS_M88K |
208 |
|
if (cpu->cd.m88k.irq_asserted && |
209 |
|
!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_IND)) |
210 |
|
m88k_exception(cpu, M88K_EXCEPTION_INTERRUPT, 0); |
211 |
|
#endif |
212 |
#ifdef DYNTRANS_MIPS |
#ifdef DYNTRANS_MIPS |
213 |
{ |
{ |
214 |
int enabled, mask; |
int enabled, mask; |
304 |
} |
} |
305 |
} |
} |
306 |
|
|
307 |
if (cpu->machine->statistics_enabled) |
if (cpu->machine->statistics.enabled) |
308 |
S; |
S; |
309 |
|
|
310 |
/* Execute just one instruction: */ |
/* Execute just one instruction: */ |
311 |
I; |
I; |
312 |
|
|
313 |
n_instrs = 1; |
n_instrs = 1; |
314 |
} else if (cpu->machine->cycle_accurate) { |
} else if (cpu->machine->statistics.enabled) { |
|
/* Executing multiple instructions, and call devices' |
|
|
tick functions: */ |
|
|
n_instrs = 0; |
|
|
for (;;) { |
|
|
struct DYNTRANS_IC *ic; |
|
|
/* TODO: continue here */ |
|
|
int64_t cycles = cpu->cd.avr.extra_cycles; |
|
|
I; |
|
|
n_instrs += 1; |
|
|
cycles = cpu->cd.avr.extra_cycles - cycles + 1; |
|
|
/* The instruction took 'cycles' cycles. */ |
|
|
/* printf("A\n"); */ |
|
|
while (cycles-- > 0) |
|
|
cpu->machine->tick_func[1](cpu, cpu->machine->tick_extra[1]); |
|
|
/* printf("B\n"); */ |
|
|
|
|
|
if (n_instrs + cpu->n_translated_instrs >= |
|
|
N_SAFE_DYNTRANS_LIMIT) |
|
|
break; |
|
|
} |
|
|
} else if (cpu->machine->statistics_enabled) { |
|
315 |
/* Gather statistics while executing multiple instructions: */ |
/* Gather statistics while executing multiple instructions: */ |
316 |
n_instrs = 0; |
n_instrs = 0; |
317 |
for (;;) { |
for (;;) { |
329 |
break; |
break; |
330 |
} |
} |
331 |
} else { |
} else { |
332 |
/* Execute multiple instructions: */ |
/* |
333 |
|
* Execute multiple instructions: |
334 |
|
* |
335 |
|
* (This is the core dyntrans loop.) |
336 |
|
*/ |
337 |
n_instrs = 0; |
n_instrs = 0; |
338 |
|
|
339 |
for (;;) { |
for (;;) { |
340 |
struct DYNTRANS_IC *ic; |
struct DYNTRANS_IC *ic; |
341 |
|
|
428 |
} |
} |
429 |
#endif |
#endif |
430 |
|
|
431 |
|
cpu->ninstrs += n_instrs; |
432 |
|
|
433 |
/* Return the nr of instructions executed: */ |
/* Return the nr of instructions executed: */ |
434 |
return n_instrs; |
return n_instrs; |
435 |
} |
} |
437 |
|
|
438 |
|
|
439 |
|
|
440 |
#ifdef DYNTRANS_FUNCTION_TRACE |
#ifdef DYNTRANS_FUNCTION_TRACE_DEF |
441 |
/* |
/* |
442 |
* XXX_cpu_functioncall_trace(): |
* XXX_cpu_functioncall_trace(): |
443 |
* |
* |
445 |
* like <f()> or <0x1234()> on a function call. It is up to this |
* like <f()> or <0x1234()> on a function call. It is up to this |
446 |
* function to print the arguments passed. |
* function to print the arguments passed. |
447 |
*/ |
*/ |
448 |
void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args) |
void DYNTRANS_FUNCTION_TRACE_DEF(struct cpu *cpu, uint64_t f, int n_args) |
449 |
{ |
{ |
450 |
|
int show_symbolic_function_name = 1; |
451 |
char strbuf[50]; |
char strbuf[50]; |
452 |
char *symbol; |
char *symbol; |
453 |
uint64_t ot; |
uint64_t ot; |
455 |
#if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC) |
#if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC) |
456 |
6 |
6 |
457 |
#else |
#else |
458 |
#ifdef DYNTRANS_SH |
#if defined(DYNTRANS_SH) || defined(DYNTRANS_M88K) |
459 |
8 /* Both for 32-bit and 64-bit SuperH */ |
8 /* Both for 32-bit and 64-bit SuperH, and M88K */ |
460 |
#else |
#else |
461 |
4 /* Default value for most archs */ |
4 /* Default value for most archs */ |
462 |
#endif |
#endif |
468 |
n_args_to_print = n_args; |
n_args_to_print = n_args; |
469 |
} |
} |
470 |
|
|
471 |
|
#ifdef DYNTRANS_M88K |
472 |
|
/* Special hack for M88K userspace: */ |
473 |
|
if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) |
474 |
|
show_symbolic_function_name = 0; |
475 |
|
#endif |
476 |
|
|
477 |
/* |
/* |
478 |
* TODO: The type of each argument should be taken from the symbol |
* TODO: The type of each argument should be taken from the symbol |
479 |
* table, in some way. |
* table, in some way. |
498 |
they go downwards, ie. 22,23 and so on */ |
they go downwards, ie. 22,23 and so on */ |
499 |
r[24 |
r[24 |
500 |
#endif |
#endif |
|
#ifdef DYNTRANS_M68K |
|
|
d[0 /* TODO */ |
|
|
#endif |
|
501 |
#ifdef DYNTRANS_MIPS |
#ifdef DYNTRANS_MIPS |
502 |
gpr[MIPS_GPR_A0 |
gpr[MIPS_GPR_A0 |
503 |
#endif |
#endif |
504 |
|
#ifdef DYNTRANS_M32R |
505 |
|
r[0 /* r0..r3? */ |
506 |
|
#endif |
507 |
|
#ifdef DYNTRANS_M88K |
508 |
|
r[2 /* r2..r9 */ |
509 |
|
#endif |
510 |
#ifdef DYNTRANS_PPC |
#ifdef DYNTRANS_PPC |
511 |
gpr[3 |
gpr[3 |
512 |
#endif |
#endif |
526 |
else if (memory_points_to_string(cpu, cpu->mem, d, 1)) |
else if (memory_points_to_string(cpu, cpu->mem, d, 1)) |
527 |
fatal("\"%s\"", memory_conv_to_string(cpu, |
fatal("\"%s\"", memory_conv_to_string(cpu, |
528 |
cpu->mem, d, strbuf, sizeof(strbuf))); |
cpu->mem, d, strbuf, sizeof(strbuf))); |
529 |
else if (symbol != NULL && ot == 0) |
else if (symbol != NULL && ot == 0 && |
530 |
|
show_symbolic_function_name) |
531 |
fatal("&%s", symbol); |
fatal("&%s", symbol); |
532 |
else { |
else { |
533 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
543 |
if (print_dots) |
if (print_dots) |
544 |
fatal(",.."); |
fatal(",.."); |
545 |
} |
} |
546 |
#endif |
#endif /* DYNTRANS_FUNCTION_TRACE_DEF */ |
547 |
|
|
548 |
|
|
549 |
|
|
550 |
#ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE |
#ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF |
551 |
/* |
/* |
552 |
* XXX_tc_allocate_default_page(): |
* XXX_tc_allocate_default_page(): |
553 |
* |
* |
554 |
* Create a default page (with just pointers to instr(to_be_translated) |
* Create a default page (with just pointers to instr(to_be_translated) |
555 |
* at cpu->translation_cache_cur_ofs. |
* at cpu->translation_cache_cur_ofs. |
556 |
*/ |
*/ |
557 |
static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu, |
static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF(struct cpu *cpu, |
558 |
uint64_t physaddr) |
uint64_t physaddr) |
559 |
{ |
{ |
560 |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
571 |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
572 |
|
|
573 |
cpu->translation_cache_cur_ofs --; |
cpu->translation_cache_cur_ofs --; |
574 |
cpu->translation_cache_cur_ofs |= 127; |
cpu->translation_cache_cur_ofs |= 63; |
575 |
cpu->translation_cache_cur_ofs ++; |
cpu->translation_cache_cur_ofs ++; |
576 |
} |
} |
577 |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF */ |
578 |
|
|
579 |
|
|
580 |
|
|
787 |
* as non-writable. If there are already translations, then it |
* as non-writable. If there are already translations, then it |
788 |
* should already have been marked as non-writable. |
* should already have been marked as non-writable. |
789 |
*/ |
*/ |
790 |
if (ppp->translations == 0) { |
if (ppp->translations_bitmap == 0) { |
791 |
cpu->invalidate_translation_caches(cpu, physaddr, |
cpu->invalidate_translation_caches(cpu, physaddr, |
792 |
JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); |
JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); |
793 |
} |
} |
877 |
static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
878 |
#endif |
#endif |
879 |
|
|
880 |
|
#ifdef DYNTRANS_DUALMODE_32 |
881 |
|
#define TO_BE_TRANSLATED ( cpu->is_32bit? instr32(to_be_translated) : \ |
882 |
|
instr(to_be_translated) ) |
883 |
|
#else |
884 |
|
#define TO_BE_TRANSLATED ( instr(to_be_translated) ) |
885 |
|
#endif |
886 |
|
|
887 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
888 |
static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
889 |
#ifdef DYNTRANS_DUALMODE_32 |
#ifdef DYNTRANS_DUALMODE_32 |
905 |
int x1, x2; |
int x1, x2; |
906 |
#endif |
#endif |
907 |
int i; |
int i; |
908 |
struct DYNTRANS_TC_PHYSPAGE *ppp = malloc(sizeof( |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
|
struct DYNTRANS_TC_PHYSPAGE)); |
|
909 |
|
|
910 |
if (ppp == NULL) { |
CHECK_ALLOCATION(ppp = malloc(sizeof(struct DYNTRANS_TC_PHYSPAGE))); |
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
911 |
|
|
912 |
ppp->next_ofs = 0; |
ppp->next_ofs = 0; |
913 |
ppp->translations = 0; |
ppp->translations_bitmap = 0; |
914 |
|
ppp->translation_ranges_ofs = 0; |
915 |
/* ppp->physaddr is filled in by the page allocator */ |
/* ppp->physaddr is filled in by the page allocator */ |
916 |
|
|
917 |
for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) { |
for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) |
918 |
ppp->ics[i].f = |
ppp->ics[i].f = TO_BE_TRANSLATED; |
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
cpu->is_32bit? instr32(to_be_translated) : |
|
|
#endif |
|
|
instr(to_be_translated); |
|
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
ppp->ics[i].arg[0] = 0; |
|
|
#endif |
|
|
} |
|
919 |
|
|
920 |
/* End-of-page: */ |
/* End-of-page: */ |
921 |
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f = |
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f = |
924 |
#endif |
#endif |
925 |
instr(end_of_page); |
instr(end_of_page); |
926 |
|
|
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].arg[0] = 0; |
|
|
#endif |
|
|
|
|
927 |
/* End-of-page-2, for delay-slot architectures: */ |
/* End-of-page-2, for delay-slot architectures: */ |
928 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
929 |
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f = |
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f = |
1295 |
* it might be faster since we don't risk wasting cache |
* it might be faster since we don't risk wasting cache |
1296 |
* memory as quickly (which would force unnecessary Restarts). |
* memory as quickly (which would force unnecessary Restarts). |
1297 |
*/ |
*/ |
1298 |
if (ppp != NULL && ppp->translations != 0) { |
if (ppp != NULL && ppp->translations_bitmap != 0) { |
1299 |
uint32_t x = ppp->translations; /* TODO: |
uint32_t x = ppp->translations_bitmap; /* TODO: |
1300 |
urk Should be same type as ppp->translations */ |
urk Should be same type as the bitmap */ |
1301 |
int i, j, n, m; |
int i, j, n, m; |
1302 |
n = 8 * sizeof(x); |
n = 8 * sizeof(x); |
1303 |
m = DYNTRANS_IC_ENTRIES_PER_PAGE / n; |
m = DYNTRANS_IC_ENTRIES_PER_PAGE / n; |
1306 |
if (x & 1) { |
if (x & 1) { |
1307 |
for (j=0; j<m; j++) |
for (j=0; j<m; j++) |
1308 |
ppp->ics[i*m + j].f = |
ppp->ics[i*m + j].f = |
1309 |
#ifdef DYNTRANS_DUALMODE_32 |
TO_BE_TRANSLATED; |
|
cpu->is_32bit? |
|
|
instr32(to_be_translated) : |
|
|
#endif |
|
|
instr(to_be_translated); |
|
1310 |
} |
} |
1311 |
|
|
1312 |
x >>= 1; |
x >>= 1; |
1313 |
} |
} |
1314 |
|
|
1315 |
ppp->translations = 0; |
ppp->translations_bitmap = 0; |
1316 |
|
|
1317 |
|
/* Clear the list of translatable ranges: */ |
1318 |
|
if (ppp->translation_ranges_ofs != 0) { |
1319 |
|
struct physpage_ranges *physpage_ranges = |
1320 |
|
(struct physpage_ranges *) |
1321 |
|
(cpu->translation_cache + |
1322 |
|
ppp->translation_ranges_ofs); |
1323 |
|
physpage_ranges->next_ofs = 0; |
1324 |
|
physpage_ranges->n_entries_used = 0; |
1325 |
|
} |
1326 |
} |
} |
1327 |
#endif |
#endif |
1328 |
} |
} |
1381 |
#ifdef MODE32 |
#ifdef MODE32 |
1382 |
uint32_t index; |
uint32_t index; |
1383 |
vaddr_page &= 0xffffffffULL; |
vaddr_page &= 0xffffffffULL; |
1384 |
paddr_page &= 0xffffffffULL; |
|
1385 |
|
if (paddr_page > 0xffffffffULL) { |
1386 |
|
fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i" |
1387 |
|
" p=0x%016"PRIx64"\n", vaddr_page, host_page, writeflag, |
1388 |
|
paddr_page); |
1389 |
|
exit(1); |
1390 |
|
} |
1391 |
|
|
1392 |
/* fatal("update_translation_table(): v=0x%x, h=%p w=%i" |
/* fatal("update_translation_table(): v=0x%x, h=%p w=%i" |
1393 |
" p=0x%x\n", (int)vaddr_page, host_page, writeflag, |
" p=0x%x\n", (int)vaddr_page, host_page, writeflag, |
1394 |
(int)paddr_page); */ |
(int)paddr_page); */ |
1413 |
useraccess = 1; |
useraccess = 1; |
1414 |
} |
} |
1415 |
|
|
1416 |
|
#ifdef DYNTRANS_M88K |
1417 |
|
/* TODO */ |
1418 |
|
if (useraccess) |
1419 |
|
return; |
1420 |
|
#endif |
1421 |
|
|
1422 |
/* Scan the current TLB entries: */ |
/* Scan the current TLB entries: */ |
1423 |
|
|
1424 |
#ifdef MODE32 |
#ifdef MODE32 |
1492 |
cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next; |
cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next; |
1493 |
} else { |
} else { |
1494 |
int i; |
int i; |
1495 |
l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] = |
CHECK_ALLOCATION(l2 = |
1496 |
malloc(sizeof(struct DYNTRANS_L2_64_TABLE)); |
cpu->cd.DYNTRANS_ARCH.l1_64[x1] = malloc( |
1497 |
|
sizeof(struct DYNTRANS_L2_64_TABLE))); |
1498 |
l2->refcount = 0; |
l2->refcount = 0; |
1499 |
for (i=0; i<(1 << DYNTRANS_L2N); i++) |
for (i=0; i<(1 << DYNTRANS_L2N); i++) |
1500 |
l2->l3[i] = cpu->cd.DYNTRANS_ARCH. |
l2->l3[i] = cpu->cd.DYNTRANS_ARCH. |
1654 |
/* |
/* |
1655 |
* Check for breakpoints. |
* Check for breakpoints. |
1656 |
*/ |
*/ |
1657 |
if (!single_step_breakpoint) { |
if (!single_step_breakpoint && !cpu->translation_readahead) { |
1658 |
MODE_uint_t curpc = cpu->pc; |
MODE_uint_t curpc = cpu->pc; |
1659 |
int i; |
int i; |
1660 |
for (i=0; i<cpu->machine->n_breakpoints; i++) |
for (i=0; i<cpu->machine->breakpoints.n; i++) |
1661 |
if (curpc == (MODE_uint_t) |
if (curpc == (MODE_uint_t) |
1662 |
cpu->machine->breakpoint_addr[i]) { |
cpu->machine->breakpoints.addr[i]) { |
1663 |
if (!cpu->machine->instruction_trace) { |
if (!cpu->machine->instruction_trace) { |
1664 |
int old_quiet_mode = quiet_mode; |
int old_quiet_mode = quiet_mode; |
1665 |
quiet_mode = 0; |
quiet_mode = 0; |
1666 |
DISASSEMBLE(cpu, ib, 1, 0); |
DISASSEMBLE(cpu, ib, 1, 0); |
1667 |
quiet_mode = old_quiet_mode; |
quiet_mode = old_quiet_mode; |
1668 |
} |
} |
1669 |
|
#ifdef MODE32 |
1670 |
|
fatal("BREAKPOINT: pc = 0x%"PRIx32"\n(The " |
1671 |
|
"instruction has not yet executed.)\n", |
1672 |
|
(uint32_t)cpu->pc); |
1673 |
|
#else |
1674 |
fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The " |
fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The " |
1675 |
"instruction has not yet executed.)\n", |
"instruction has not yet executed.)\n", |
1676 |
(uint64_t)cpu->pc); |
(uint64_t)cpu->pc); |
1677 |
|
#endif |
1678 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
1679 |
if (cpu->delay_slot != NOT_DELAYED) |
if (cpu->delay_slot != NOT_DELAYED) |
1680 |
fatal("ERROR! Breakpoint in a delay" |
fatal("ERROR! Breakpoint in a delay" |
1704 |
{ |
{ |
1705 |
int x = addr & (DYNTRANS_PAGESIZE - 1); |
int x = addr & (DYNTRANS_PAGESIZE - 1); |
1706 |
int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 * |
int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 * |
1707 |
sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage->translations)); |
sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage-> |
1708 |
|
translations_bitmap)); |
1709 |
x /= addr_per_translation_range; |
x /= addr_per_translation_range; |
1710 |
|
|
1711 |
cpu->cd.DYNTRANS_ARCH.cur_physpage->translations |= (1 << x); |
cpu->cd.DYNTRANS_ARCH.cur_physpage-> |
1712 |
|
translations_bitmap |= (1 << x); |
1713 |
} |
} |
1714 |
|
|
1715 |
|
|
1716 |
/* |
/* |
1717 |
* Now it is time to check for combinations of instructions that can |
* Now it is time to check for combinations of instructions that can |
1718 |
* be converted into a single function call. |
* be converted into a single function call. |
1719 |
* |
* |
1720 |
* Note: Single-stepping or instruction tracing doesn't work with |
* Note: Single-stepping or instruction tracing doesn't work with |
1721 |
* instruction combination. For architectures with delay slots, |
* instruction combinations. For architectures with delay slots, |
1722 |
* we also ignore combinations if the delay slot is across a page |
* we also ignore combinations if the delay slot is across a page |
1723 |
* boundary. |
* boundary. |
1724 |
*/ |
*/ |
1735 |
cpu->cd.DYNTRANS_ARCH.combination_check = NULL; |
cpu->cd.DYNTRANS_ARCH.combination_check = NULL; |
1736 |
|
|
1737 |
/* An additional check, to catch some bugs: */ |
/* An additional check, to catch some bugs: */ |
1738 |
if (ic->f == ( |
if (ic->f == TO_BE_TRANSLATED) { |
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
cpu->is_32bit? instr32(to_be_translated) : |
|
|
#endif |
|
|
instr(to_be_translated))) { |
|
1739 |
fatal("INTERNAL ERROR: ic->f not set!\n"); |
fatal("INTERNAL ERROR: ic->f not set!\n"); |
1740 |
goto bad; |
goto bad; |
1741 |
} |
} |
1744 |
goto bad; |
goto bad; |
1745 |
} |
} |
1746 |
|
|
1747 |
/* ... and finally execute the translated instruction: */ |
|
1748 |
|
/* |
1749 |
|
* ... and finally execute the translated instruction: |
1750 |
|
*/ |
1751 |
|
|
1752 |
|
/* (Except when doing read-ahead!) */ |
1753 |
|
if (cpu->translation_readahead) |
1754 |
|
return; |
1755 |
|
|
1756 |
|
/* |
1757 |
|
* Special case when single-stepping: Execute the translated |
1758 |
|
* instruction, but then replace it with a "to be translated" |
1759 |
|
* directly afterwards. |
1760 |
|
*/ |
1761 |
if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED) |
if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED) |
1762 |
#ifdef DYNTRANS_DELAYSLOT |
#ifdef DYNTRANS_DELAYSLOT |
1763 |
|| in_crosspage_delayslot |
|| in_crosspage_delayslot |
1764 |
#endif |
#endif |
1765 |
) { |
) { |
|
/* |
|
|
* Special case when single-stepping: Execute the translated |
|
|
* instruction, but then replace it with a "to be translated" |
|
|
* directly afterwards. |
|
|
*/ |
|
1766 |
single_step_breakpoint = 0; |
single_step_breakpoint = 0; |
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0]; |
|
|
#endif |
|
1767 |
ic->f(cpu, ic); |
ic->f(cpu, ic); |
1768 |
ic->f = |
ic->f = TO_BE_TRANSLATED; |
1769 |
#ifdef DYNTRANS_DUALMODE_32 |
return; |
1770 |
cpu->is_32bit? instr32(to_be_translated) : |
} |
|
#endif |
|
|
instr(to_be_translated); |
|
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
ic->arg[0] = 0; |
|
|
#endif |
|
|
} else { |
|
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0]; |
|
1771 |
|
|
1772 |
/* Additional check, for variable length ISAs: */ |
/* Translation read-ahead: */ |
1773 |
if (ic->arg[0] == 0) { |
if (!single_step && !cpu->machine->instruction_trace) { |
1774 |
fatal("INTERNAL ERROR: instr len = 0!\n"); |
uint64_t baseaddr = cpu->pc; |
1775 |
goto bad; |
uint64_t pagenr = DYNTRANS_ADDR_TO_PAGENR(baseaddr); |
1776 |
|
int i = 1; |
1777 |
|
|
1778 |
|
cpu->translation_readahead = MAX_DYNTRANS_READAHEAD; |
1779 |
|
|
1780 |
|
while (DYNTRANS_ADDR_TO_PAGENR(baseaddr + |
1781 |
|
(i << DYNTRANS_INSTR_ALIGNMENT_SHIFT)) == pagenr && |
1782 |
|
cpu->translation_readahead > 0) { |
1783 |
|
void (*old_f)(struct cpu *, |
1784 |
|
struct DYNTRANS_IC *) = ic[i].f; |
1785 |
|
|
1786 |
|
/* Already translated? Then abort: */ |
1787 |
|
if (old_f != TO_BE_TRANSLATED) |
1788 |
|
break; |
1789 |
|
|
1790 |
|
/* Translate the instruction: */ |
1791 |
|
ic[i].f(cpu, ic+i); |
1792 |
|
|
1793 |
|
/* Translation failed? Then abort. */ |
1794 |
|
if (ic[i].f == old_f) |
1795 |
|
break; |
1796 |
|
|
1797 |
|
cpu->translation_readahead --; |
1798 |
|
++i; |
1799 |
} |
} |
|
#endif |
|
1800 |
|
|
1801 |
/* Finally finally :-), execute the instruction: */ |
cpu->translation_readahead = 0; |
|
ic->f(cpu, ic); |
|
1802 |
} |
} |
1803 |
|
|
1804 |
|
|
1805 |
|
/* |
1806 |
|
* Finally finally :-), execute the instruction. |
1807 |
|
* |
1808 |
|
* Note: The instruction might have changed during read-ahead, if |
1809 |
|
* instruction combinations are used. |
1810 |
|
*/ |
1811 |
|
|
1812 |
|
ic->f(cpu, ic); |
1813 |
|
|
1814 |
return; |
return; |
1815 |
|
|
1816 |
|
|
1818 |
* Nothing was translated. (Unimplemented or illegal instruction.) |
* Nothing was translated. (Unimplemented or illegal instruction.) |
1819 |
*/ |
*/ |
1820 |
|
|
1821 |
|
/* Clear the translation, in case it was "half-way" done: */ |
1822 |
|
ic->f = TO_BE_TRANSLATED; |
1823 |
|
|
1824 |
|
if (cpu->translation_readahead) |
1825 |
|
return; |
1826 |
|
|
1827 |
quiet_mode = 0; |
quiet_mode = 0; |
1828 |
fatal("to_be_translated(): TODO: unimplemented instruction"); |
fatal("to_be_translated(): TODO: unimplemented instruction"); |
1829 |
|
|
1830 |
if (cpu->machine->instruction_trace) |
if (cpu->machine->instruction_trace) { |
1831 |
#ifdef MODE32 |
if (cpu->is_32bit) |
1832 |
fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc); |
fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc); |
1833 |
#else |
else |
1834 |
fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc); |
fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc); |
1835 |
#endif |
} else { |
|
else { |
|
1836 |
fatal(":\n"); |
fatal(":\n"); |
1837 |
DISASSEMBLE(cpu, ib, 1, 0); |
DISASSEMBLE(cpu, ib, 1, 0); |
1838 |
} |
} |
1847 |
ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; |
ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; |
1848 |
cpu->cd.DYNTRANS_ARCH.next_ic ++; |
cpu->cd.DYNTRANS_ARCH.next_ic ++; |
1849 |
|
|
1850 |
|
#ifdef DYNTRANS_DELAYSLOT |
1851 |
|
/* Special hack: If the bad instruction was in a delay slot, |
1852 |
|
make sure that execution does not continue anyway: */ |
1853 |
|
if (cpu->delay_slot) |
1854 |
|
cpu->delay_slot |= EXCEPTION_IN_DELAY_SLOT; |
1855 |
|
#endif |
1856 |
|
|
1857 |
/* Execute the "nothing" instruction: */ |
/* Execute the "nothing" instruction: */ |
1858 |
ic->f(cpu, ic); |
ic->f(cpu, ic); |
1859 |
|
|