25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: bintrans.c,v 1.160 2005/04/06 21:16:45 debug Exp $ |
* $Id: bintrans.c,v 1.165 2005/04/27 16:37:34 debug Exp $ |
29 |
* |
* |
30 |
* Dynamic binary translation. |
* Dynamic binary translation. |
31 |
* |
* |
123 |
int bintrans_pc_is_in_cache(struct cpu *cpu, uint64_t pc) { return 0; } |
int bintrans_pc_is_in_cache(struct cpu *cpu, uint64_t pc) { return 0; } |
124 |
void bintrans_invalidate(struct cpu *cpu, uint64_t paddr) { } |
void bintrans_invalidate(struct cpu *cpu, uint64_t paddr) { } |
125 |
int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr) { return 0; } |
int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr) { return 0; } |
126 |
|
void bintrans_restart(struct cpu *cpu) { } |
127 |
void bintrans_init_cpu(struct cpu *cpu) { } |
void bintrans_init_cpu(struct cpu *cpu) { } |
128 |
void bintrans_init(struct machine *machine, struct memory *mem) |
void bintrans_init(struct machine *machine, struct memory *mem) |
129 |
{ |
{ |
279 |
|
|
280 |
|
|
281 |
/* |
/* |
282 |
|
* bintrans_restart(): |
283 |
|
* |
284 |
|
* Starts over by throwing away the bintrans cache contents. |
285 |
|
*/ |
286 |
|
void bintrans_restart(struct cpu *cpu) |
287 |
|
{ |
288 |
|
int i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS; |
289 |
|
|
290 |
|
for (i=0; i<n; i++) |
291 |
|
cpu->mem->translation_page_entry_array[i] = NULL; |
292 |
|
|
293 |
|
cpu->mem->translation_code_chunk_space_head = 0; |
294 |
|
cpu->mem->n_quick_jumps = 0; |
295 |
|
|
296 |
|
/* debug("bintrans: Starting over!\n"); */ |
297 |
|
clear_all_chunks_from_all_tables(cpu); |
298 |
|
} |
299 |
|
|
300 |
|
|
301 |
|
/* |
302 |
* enter_chunks_into_tables(): |
* enter_chunks_into_tables(): |
303 |
*/ |
*/ |
304 |
static void enter_chunks_into_tables(struct cpu *cpu, uint64_t vaddr, |
static void enter_chunks_into_tables(struct cpu *cpu, uint64_t vaddr, |
358 |
(paddr & 3) != 0) |
(paddr & 3) != 0) |
359 |
return cpu->cd.mips.bintrans_instructions_executed; |
return cpu->cd.mips.bintrans_instructions_executed; |
360 |
|
|
|
cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2 |
|
|
|| cpu->cd.mips.cpu_type.isa_level == 32); |
|
361 |
byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN); |
byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN); |
362 |
|
|
363 |
/* Is this a part of something that is already translated? */ |
/* Is this a part of something that is already translated? */ |
364 |
paddr_page = paddr & ~0xfff; |
paddr_page = paddr & ~0xfff; |
365 |
offset_within_page = (paddr & 0xfff) / 4; |
offset_within_page = (paddr & 0xfff) >> 2; |
366 |
entry_index = PADDR_TO_INDEX(paddr); |
entry_index = PADDR_TO_INDEX(paddr); |
367 |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
368 |
while (tep != NULL) { |
while (tep != NULL) { |
369 |
if (tep->paddr == paddr_page) { |
if (tep->paddr == paddr_page) { |
370 |
int mask = 1 << (offset_within_page & 7); |
int mask; |
371 |
|
|
372 |
if (tep->chunk[offset_within_page] != 0) { |
if (tep->chunk[offset_within_page] != 0) { |
373 |
f = (size_t)tep->chunk[offset_within_page] + |
f = (size_t)tep->chunk[offset_within_page] + |
374 |
cpu->mem->translation_code_chunk_space; |
cpu->mem->translation_code_chunk_space; |
375 |
goto run_it; /* see further down */ |
goto run_it; /* see further down */ |
376 |
} |
} |
377 |
|
|
378 |
|
mask = 1 << (offset_within_page & 7); |
379 |
if (tep->flags[offset_within_page >> 3] & mask) |
if (tep->flags[offset_within_page >> 3] & mask) |
380 |
return cpu->cd.mips. |
return cpu->cd.mips. |
381 |
bintrans_instructions_executed; |
bintrans_instructions_executed; |
401 |
*/ |
*/ |
402 |
if (cpu->mem->translation_code_chunk_space_head >= |
if (cpu->mem->translation_code_chunk_space_head >= |
403 |
cpu->machine->bintrans_size) { |
cpu->machine->bintrans_size) { |
404 |
int i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS; |
bintrans_restart(cpu); |
|
for (i=0; i<n; i++) |
|
|
cpu->mem->translation_page_entry_array[i] = NULL; |
|
|
cpu->mem->translation_code_chunk_space_head = 0; |
|
|
cpu->mem->n_quick_jumps = 0; |
|
405 |
tep = NULL; |
tep = NULL; |
|
debug("bintrans: Starting over!\n"); |
|
|
clear_all_chunks_from_all_tables(cpu); |
|
406 |
} |
} |
407 |
|
|
408 |
|
|
449 |
* Try to translate a chunk of code: |
* Try to translate a chunk of code: |
450 |
*/ |
*/ |
451 |
p = paddr & 0xfff; |
p = paddr & 0xfff; |
452 |
|
prev_p = p >> 2; |
453 |
try_to_translate = 1; |
try_to_translate = 1; |
454 |
n_translated = 0; |
n_translated = 0; |
455 |
res = 0; |
res = 0; |
461 |
|
|
462 |
while (try_to_translate) { |
while (try_to_translate) { |
463 |
ca_justdid = ca; |
ca_justdid = ca; |
|
prev_p = p/4; |
|
464 |
translated = 0; |
translated = 0; |
465 |
|
|
466 |
/* Read an instruction word from host memory: */ |
/* Read an instruction word from host memory: */ |
636 |
case HI6_XORI: |
case HI6_XORI: |
637 |
case HI6_DADDI: |
case HI6_DADDI: |
638 |
case HI6_DADDIU: |
case HI6_DADDIU: |
639 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
translated = try_to_translate = |
640 |
rt = instr[2] & 31; |
bintrans_write_instruction__addiu_etc(&ca, |
641 |
imm = (instr[1] << 8) + instr[0]; |
instr[2] & 31, |
642 |
translated = try_to_translate = bintrans_write_instruction__addiu_etc(&ca, rt, rs, imm, hi6); |
((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7), |
643 |
|
(instr[1] << 8) + instr[0], hi6); |
644 |
n_translated += translated; |
n_translated += translated; |
645 |
break; |
break; |
646 |
|
|
647 |
case HI6_LUI: |
case HI6_LUI: |
648 |
rt = instr[2] & 31; |
translated = try_to_translate = |
649 |
imm = (instr[1] << 8) + instr[0]; |
bintrans_write_instruction__lui(&ca, |
650 |
translated = try_to_translate = bintrans_write_instruction__lui(&ca, rt, imm); |
instr[2] & 31, (instr[1] << 8) + instr[0]); |
651 |
n_translated += translated; |
n_translated += translated; |
652 |
break; |
break; |
653 |
|
|
680 |
translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 1, rt, rd, 1); |
translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 1, rt, rd, 1); |
681 |
n_translated += translated; |
n_translated += translated; |
682 |
} |
} |
683 |
} |
} else |
684 |
|
try_to_translate = 0; |
685 |
break; |
break; |
686 |
case 0x42: |
case 0x42: |
687 |
if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x10) { |
if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x10) { |
714 |
/* standby and suspend on VR41xx etc ==> NOP */ |
/* standby and suspend on VR41xx etc ==> NOP */ |
715 |
translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, 0, 0, 0, 0, SPECIAL_SLL); |
translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, 0, 0, 0, 0, SPECIAL_SLL); |
716 |
n_translated += translated; |
n_translated += translated; |
717 |
} |
} else |
718 |
|
try_to_translate = 0; |
719 |
break; |
break; |
720 |
default: |
default: |
721 |
try_to_translate = 0; |
try_to_translate = 0; |
791 |
cpu->mem, &ca, |
cpu->mem, &ca, |
792 |
potential_chunk_p, &tep->chunk[0], 0, |
potential_chunk_p, &tep->chunk[0], 0, |
793 |
delayed_branch_new_p & 0xfff, forward); |
delayed_branch_new_p & 0xfff, forward); |
794 |
|
#if 0 |
795 |
if (stop_after_delayed_branch) |
if (stop_after_delayed_branch) |
796 |
try_to_translate = 0; |
try_to_translate = 0; |
797 |
|
#endif |
798 |
} |
} |
799 |
} |
} |
800 |
|
|
815 |
tep->chunk[prev_p]); |
tep->chunk[prev_p]); |
816 |
} |
} |
817 |
|
|
818 |
/* Glue together with previously translated code, if any: */ |
if (translated && try_to_translate && prev_p < 1023) { |
819 |
if (translated && try_to_translate && |
int mask = 1 << ((prev_p+1) & 7); |
|
prev_p < 1023 && tep->chunk[prev_p+1] != 0 |
|
|
&& !delayed_branch) { |
|
|
bintrans_write_instruction__delayedbranch(cpu->mem, |
|
|
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
|
|
try_to_translate = 0; |
|
|
} |
|
820 |
|
|
821 |
if (translated && try_to_translate && n_translated > 80 |
if (tep->flags[(prev_p+1) >> 3] & mask |
822 |
&& prev_p < 1023 && !delayed_branch) { |
&& !delayed_branch) { |
823 |
bintrans_write_instruction__delayedbranch(cpu->mem, |
bintrans_write_chunkreturn_fail(&ca); |
824 |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
/* try_to_translate = 0; */ |
825 |
try_to_translate = 0; |
break; |
826 |
} |
} |
827 |
|
|
828 |
{ |
/* Glue together with previously translated code, |
829 |
int mask = 1 << ((prev_p+1) & 7); |
if any: */ |
830 |
|
if (tep->chunk[prev_p+1] != 0 && !delayed_branch) { |
831 |
|
bintrans_write_instruction__delayedbranch(cpu->mem, |
832 |
|
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
833 |
|
/* try_to_translate = 0; */ |
834 |
|
break; |
835 |
|
} |
836 |
|
|
837 |
if (translated && try_to_translate && |
if (n_translated > 80 && !delayed_branch) { |
838 |
tep->flags[(prev_p+1) >> 3] & mask |
bintrans_write_instruction__delayedbranch(cpu->mem, |
839 |
&& prev_p < 1023 && !delayed_branch) { |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
840 |
bintrans_write_chunkreturn_fail(&ca); |
/* try_to_translate = 0; */ |
841 |
|
break; |
842 |
|
} |
843 |
} |
} |
|
} |
|
844 |
|
|
845 |
p += sizeof(instr); |
p += sizeof(instr); |
846 |
|
prev_p ++; |
847 |
|
|
848 |
/* If we have reached a different (MIPS) page, then stop translating. */ |
/* If we have reached a different (MIPS) page, then stop translating. */ |
849 |
if (p == 0x1000) |
if (p == 0x1000) |
942 |
|
|
943 |
if (ok) { |
if (ok) { |
944 |
paddr_page = paddr & ~0xfff; |
paddr_page = paddr & ~0xfff; |
945 |
offset_within_page = (paddr & 0xfff) / 4; |
offset_within_page = (paddr & 0xfff) >> 2; |
946 |
entry_index = PADDR_TO_INDEX(paddr); |
entry_index = PADDR_TO_INDEX(paddr); |
947 |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
948 |
while (tep != NULL) { |
while (tep != NULL) { |
949 |
if (tep->paddr == paddr_page) { |
if (tep->paddr == paddr_page) { |
950 |
int mask = 1 << (offset_within_page & 7); |
int mask; |
951 |
if (tep->chunk[offset_within_page] != 0) { |
if (tep->chunk[offset_within_page] != 0) { |
952 |
f = (size_t)tep->chunk[offset_within_page] + |
f = (size_t)tep->chunk[offset_within_page] + |
953 |
cpu->mem->translation_code_chunk_space; |
cpu->mem->translation_code_chunk_space; |
954 |
goto run_it; |
goto run_it; |
955 |
} |
} |
956 |
|
mask = 1 << (offset_within_page & 7); |
957 |
if (tep->flags[offset_within_page >> 3] & mask) |
if (tep->flags[offset_within_page >> 3] & mask) |
958 |
return cpu->cd.mips.bintrans_instructions_executed; |
return cpu->cd.mips.bintrans_instructions_executed; |
959 |
break; |
break; |
1093 |
} |
} |
1094 |
|
|
1095 |
cpu->cd.mips.vaddr_to_hostaddr_table0 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel; |
cpu->cd.mips.vaddr_to_hostaddr_table0 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel; |
1096 |
|
|
1097 |
|
cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2 |
1098 |
|
|| cpu->cd.mips.cpu_type.isa_level == 32); |
1099 |
} |
} |
1100 |
|
|
1101 |
|
|