25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: bintrans.c,v 1.169 2005/06/22 10:12:25 debug Exp $ |
* $Id: bintrans.c,v 1.177 2005/08/14 15:47:36 debug Exp $ |
29 |
* |
* |
30 |
* Dynamic binary translation. |
* Dynamic binary translation. |
31 |
* |
* |
81 |
* |
* |
82 |
* o) Load/stores: TODO: Comment. |
* o) Load/stores: TODO: Comment. |
83 |
* |
* |
|
* Testing: Running regression tests with and without the binary translator |
|
|
* enabled should obviously result in the exact same results, or something is |
|
|
* wrong. |
|
84 |
* |
* |
85 |
* The general idea is something like this: |
* The general idea is something like this: |
86 |
* |
* |
139 |
static void bintrans_write_pc_inc(unsigned char **addrp); |
static void bintrans_write_pc_inc(unsigned char **addrp); |
140 |
static void bintrans_write_quickjump(struct memory *mem, |
static void bintrans_write_quickjump(struct memory *mem, |
141 |
unsigned char *quickjump_code, uint32_t chunkoffset); |
unsigned char *quickjump_code, uint32_t chunkoffset); |
142 |
static int bintrans_write_instruction__addiu_etc(unsigned char **addrp, int rt, |
static int bintrans_write_instruction__addiu_etc(struct memory *mem, |
143 |
int rs, int imm, int instruction_type); |
unsigned char **addrp, int rt, int rs, int imm, |
144 |
static int bintrans_write_instruction__addu_etc(unsigned char **addrp, int rd, |
int instruction_type); |
145 |
int rs, int rt, int sa, int instruction_type); |
static int bintrans_write_instruction__addu_etc(struct memory *mem, |
146 |
|
unsigned char **addrp, int rd, int rs, int rt, int sa, |
147 |
|
int instruction_type); |
148 |
static int bintrans_write_instruction__branch(unsigned char **addrp, |
static int bintrans_write_instruction__branch(unsigned char **addrp, |
149 |
int instruction_type, int regimm_type, int rt, int rs, int imm); |
int instruction_type, int regimm_type, int rt, int rs, int imm); |
150 |
static int bintrans_write_instruction__jr(unsigned char **addrp, int rs, |
static int bintrans_write_instruction__jr(unsigned char **addrp, int rs, |
156 |
int only_care_about_chunk_p, int p, int forward); |
int only_care_about_chunk_p, int p, int forward); |
157 |
static int bintrans_write_instruction__loadstore(struct memory *mem, |
static int bintrans_write_instruction__loadstore(struct memory *mem, |
158 |
unsigned char **addrp, int rt, int imm, int rs, int instruction_type, |
unsigned char **addrp, int rt, int imm, int rs, int instruction_type, |
159 |
int bigendian); |
int bigendian, int do_alignment_check); |
160 |
static int bintrans_write_instruction__lui(unsigned char **addrp, int rt, |
static int bintrans_write_instruction__lui(unsigned char **addrp, int rt, |
161 |
int imm); |
int imm); |
162 |
static int bintrans_write_instruction__mfmthilo(unsigned char **addrp, int rd, |
static int bintrans_write_instruction__mfmthilo(unsigned char **addrp, int rd, |
201 |
#define BACKEND_NAME "i386" |
#define BACKEND_NAME "i386" |
202 |
#include "bintrans_i386.c" |
#include "bintrans_i386.c" |
203 |
#else |
#else |
|
#ifdef MIPS |
|
|
#define BACKEND_NAME "MIPS" |
|
|
#include "bintrans_mips.c" |
|
|
#else |
|
|
#ifdef SPARCV9 |
|
|
#define BACKEND_NAME "UltraSPARC" |
|
|
#include "bintrans_sparcv9.c" |
|
|
#else |
|
204 |
#error Unsupported host architecture for bintrans. |
#error Unsupported host architecture for bintrans. |
|
#endif /* SPARCV9 */ |
|
|
#endif /* MIPS */ |
|
205 |
#endif /* I386 */ |
#endif /* I386 */ |
206 |
#endif /* ALPHA */ |
#endif /* ALPHA */ |
207 |
|
|
276 |
{ |
{ |
277 |
int i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS; |
int i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS; |
278 |
|
|
279 |
|
if (cpu->machine->arch != ARCH_MIPS) |
280 |
|
return; |
281 |
|
|
282 |
for (i=0; i<n; i++) |
for (i=0; i<n; i++) |
283 |
cpu->mem->translation_page_entry_array[i] = NULL; |
cpu->mem->translation_page_entry_array[i] = NULL; |
284 |
|
|
285 |
cpu->mem->translation_code_chunk_space_head = 0; |
cpu->mem->translation_code_chunk_space_head = 0; |
286 |
cpu->mem->n_quick_jumps = 0; |
cpu->mem->n_quick_jumps = 0; |
287 |
|
|
288 |
/* debug("bintrans: Starting over!\n"); */ |
debug("[ bintrans: Starting over! ]\n"); |
289 |
clear_all_chunks_from_all_tables(cpu); |
clear_all_chunks_from_all_tables(cpu); |
290 |
} |
} |
291 |
|
|
340 |
int rs,rt,rd,sa,imm; |
int rs,rt,rd,sa,imm; |
341 |
uint32_t *potential_chunk_p; /* for branches */ |
uint32_t *potential_chunk_p; /* for branches */ |
342 |
int byte_order_cached_bigendian; |
int byte_order_cached_bigendian; |
343 |
int delayed_branch, stop_after_delayed_branch; |
int delayed_branch, stop_after_delayed_branch, return_code_written; |
344 |
uint64_t delayed_branch_new_p; |
uint64_t delayed_branch_new_p; |
345 |
int prev_p; |
int prev_p; |
346 |
|
|
412 |
|
|
413 |
/* ... and align again: */ |
/* ... and align again: */ |
414 |
cpu->mem->translation_code_chunk_space_head = |
cpu->mem->translation_code_chunk_space_head = |
415 |
((cpu->mem->translation_code_chunk_space_head - 1) | 63) |
((cpu->mem->translation_code_chunk_space_head - 1) | 31)+1; |
|
+ 1; |
|
416 |
|
|
417 |
/* Add the entry to the array: */ |
/* Add the entry to the array: */ |
418 |
memset(tep, 0, sizeof(struct translation_page_entry)); |
memset(tep, 0, sizeof(struct translation_page_entry)); |
444 |
try_to_translate = 1; |
try_to_translate = 1; |
445 |
n_translated = 0; |
n_translated = 0; |
446 |
res = 0; |
res = 0; |
447 |
|
return_code_written = 0; |
448 |
delayed_branch = 0; |
delayed_branch = 0; |
449 |
stop_after_delayed_branch = 0; |
stop_after_delayed_branch = 0; |
450 |
delayed_branch_new_p = 0; |
delayed_branch_new_p = 0; |
495 |
bintrans_write_chunkreturn_fail(&ca); |
bintrans_write_chunkreturn_fail(&ca); |
496 |
tep->flags[prev_p >> 3] |= mask; |
tep->flags[prev_p >> 3] |= mask; |
497 |
try_to_translate = 0; |
try_to_translate = 0; |
498 |
|
return_code_written = 1; |
499 |
} else { |
} else { |
500 |
translated = bintrans_write_instruction__tlb_rfe_etc(&ca, |
translated = bintrans_write_instruction__tlb_rfe_etc(&ca, |
501 |
special6 == SPECIAL_BREAK? CALL_BREAK : CALL_SYSCALL); |
special6 == SPECIAL_BREAK? CALL_BREAK : CALL_SYSCALL); |
537 |
rd = rt = rs = sa = 0; |
rd = rt = rs = sa = 0; |
538 |
special6 = SPECIAL_SLL; |
special6 = SPECIAL_SLL; |
539 |
} |
} |
540 |
translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, rd, rs, rt, sa, special6); |
translated = try_to_translate = bintrans_write_instruction__addu_etc(cpu->mem, &ca, rd, rs, rt, sa, special6); |
541 |
n_translated += translated; |
n_translated += translated; |
542 |
break; |
break; |
543 |
case SPECIAL_MFHI: |
case SPECIAL_MFHI: |
559 |
tep->flags[prev_p >> 3] |= mask; |
tep->flags[prev_p >> 3] |= mask; |
560 |
} |
} |
561 |
try_to_translate = 0; |
try_to_translate = 0; |
562 |
|
return_code_written = 1; |
563 |
} |
} |
564 |
break; |
break; |
565 |
|
|
578 |
delayed_branch_new_p = p + 4 + 4*imm; |
delayed_branch_new_p = p + 4 + 4*imm; |
579 |
break; |
break; |
580 |
default: |
default: |
|
try_to_translate = 0; |
|
581 |
/* Untranslatable: */ |
/* Untranslatable: */ |
582 |
/* TODO: this code should only be in one place */ |
/* TODO: this code should only be in one place */ |
583 |
bintrans_write_chunkreturn_fail(&ca); |
bintrans_write_chunkreturn_fail(&ca); |
586 |
tep->flags[prev_p >> 3] |= mask; |
tep->flags[prev_p >> 3] |= mask; |
587 |
} |
} |
588 |
try_to_translate = 0; |
try_to_translate = 0; |
589 |
|
return_code_written = 1; |
590 |
} |
} |
591 |
break; |
break; |
592 |
|
|
631 |
case HI6_DADDI: |
case HI6_DADDI: |
632 |
case HI6_DADDIU: |
case HI6_DADDIU: |
633 |
translated = try_to_translate = |
translated = try_to_translate = |
634 |
bintrans_write_instruction__addiu_etc(&ca, |
bintrans_write_instruction__addiu_etc(cpu->mem, |
635 |
instr[2] & 31, |
&ca, instr[2] & 31, |
636 |
((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7), |
((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7), |
637 |
(instr[1] << 8) + instr[0], hi6); |
(instr[1] << 8) + instr[0], hi6); |
638 |
n_translated += translated; |
n_translated += translated; |
674 |
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); |
675 |
n_translated += translated; |
n_translated += translated; |
676 |
} |
} |
677 |
} else |
} else { |
678 |
|
/* Untranslatable: */ |
679 |
|
/* TODO: this code should only be in one place */ |
680 |
|
bintrans_write_chunkreturn_fail(&ca); |
681 |
|
{ |
682 |
|
int mask = 1 << (prev_p & 7); |
683 |
|
tep->flags[prev_p >> 3] |= mask; |
684 |
|
} |
685 |
try_to_translate = 0; |
try_to_translate = 0; |
686 |
|
return_code_written = 1; |
687 |
|
} |
688 |
break; |
break; |
689 |
case 0x42: |
case 0x42: |
690 |
if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x10) { |
if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x10) { |
715 |
n_translated += translated; |
n_translated += translated; |
716 |
} else if (instr[2] == 0 && instr[1] == 0 && (instr[0] == 0x21 || instr[0] == 0x22)) { |
} else if (instr[2] == 0 && instr[1] == 0 && (instr[0] == 0x21 || instr[0] == 0x22)) { |
717 |
/* standby and suspend on VR41xx etc ==> NOP */ |
/* standby and suspend on VR41xx etc ==> NOP */ |
718 |
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(cpu->mem, &ca, 0, 0, 0, 0, SPECIAL_SLL); |
719 |
n_translated += translated; |
n_translated += translated; |
720 |
} else |
} else { |
721 |
|
/* Untranslatable: */ |
722 |
|
/* TODO: this code should only be in one place */ |
723 |
|
bintrans_write_chunkreturn_fail(&ca); |
724 |
|
{ |
725 |
|
int mask = 1 << (prev_p & 7); |
726 |
|
tep->flags[prev_p >> 3] |= mask; |
727 |
|
} |
728 |
try_to_translate = 0; |
try_to_translate = 0; |
729 |
|
return_code_written = 1; |
730 |
|
} |
731 |
break; |
break; |
732 |
default: |
default: |
733 |
|
/* Untranslatable: */ |
734 |
|
/* TODO: this code should only be in one place */ |
735 |
|
bintrans_write_chunkreturn_fail(&ca); |
736 |
|
{ |
737 |
|
int mask = 1 << (prev_p & 7); |
738 |
|
tep->flags[prev_p >> 3] |= mask; |
739 |
|
} |
740 |
try_to_translate = 0; |
try_to_translate = 0; |
741 |
|
return_code_written = 1; |
742 |
} |
} |
743 |
break; |
break; |
|
|
|
744 |
#if 0 |
#if 0 |
745 |
case HI6_LQ_MDMX: |
case HI6_LQ_MDMX: |
746 |
#endif |
#endif |
767 |
imm = (instr[1] << 8) + instr[0]; |
imm = (instr[1] << 8) + instr[0]; |
768 |
if (imm >= 32768) |
if (imm >= 32768) |
769 |
imm -= 65536; |
imm -= 65536; |
770 |
translated = try_to_translate = bintrans_write_instruction__loadstore(cpu->mem, &ca, rt, imm, rs, hi6, byte_order_cached_bigendian); |
translated = try_to_translate = bintrans_write_instruction__loadstore(cpu->mem, &ca, rt, imm, rs, hi6, |
771 |
|
byte_order_cached_bigendian, |
772 |
|
cpu->machine->dyntrans_alignment_check); |
773 |
n_translated += translated; |
n_translated += translated; |
774 |
break; |
break; |
775 |
|
|
776 |
case HI6_CACHE: |
case HI6_CACHE: |
777 |
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(cpu->mem, &ca, 0, 0, 0, 0, SPECIAL_SLL); |
778 |
n_translated += translated; |
n_translated += translated; |
779 |
break; |
break; |
780 |
|
|
787 |
tep->flags[prev_p >> 3] |= mask; |
tep->flags[prev_p >> 3] |= mask; |
788 |
} |
} |
789 |
try_to_translate = 0; |
try_to_translate = 0; |
790 |
|
return_code_written = 1; |
791 |
} |
} |
792 |
|
|
793 |
if (translated && delayed_branch) { |
if (translated && delayed_branch) { |
813 |
cpu->mem, &ca, |
cpu->mem, &ca, |
814 |
potential_chunk_p, &tep->chunk[0], 0, |
potential_chunk_p, &tep->chunk[0], 0, |
815 |
delayed_branch_new_p & 0xfff, forward); |
delayed_branch_new_p & 0xfff, forward); |
816 |
#if 0 |
|
817 |
if (stop_after_delayed_branch) |
if (stop_after_delayed_branch) |
818 |
try_to_translate = 0; |
try_to_translate = 0; |
|
#endif |
|
819 |
} |
} |
820 |
} |
} |
821 |
|
|
842 |
if (tep->flags[(prev_p+1) >> 3] & mask |
if (tep->flags[(prev_p+1) >> 3] & mask |
843 |
&& !delayed_branch) { |
&& !delayed_branch) { |
844 |
bintrans_write_chunkreturn_fail(&ca); |
bintrans_write_chunkreturn_fail(&ca); |
845 |
/* try_to_translate = 0; */ |
try_to_translate = 0; |
846 |
|
return_code_written = 1; |
847 |
break; |
break; |
848 |
} |
} |
849 |
|
|
852 |
if (tep->chunk[prev_p+1] != 0 && !delayed_branch) { |
if (tep->chunk[prev_p+1] != 0 && !delayed_branch) { |
853 |
bintrans_write_instruction__delayedbranch(cpu->mem, |
bintrans_write_instruction__delayedbranch(cpu->mem, |
854 |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
855 |
|
try_to_translate = 0; |
856 |
|
return_code_written = 1; |
857 |
/* try_to_translate = 0; */ |
/* try_to_translate = 0; */ |
858 |
break; |
break; |
859 |
} |
} |
860 |
|
|
861 |
if (n_translated > 80 && !delayed_branch) { |
if (n_translated > 120 && !delayed_branch) { |
862 |
bintrans_write_instruction__delayedbranch(cpu->mem, |
bintrans_write_instruction__delayedbranch(cpu->mem, |
863 |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
864 |
/* try_to_translate = 0; */ |
try_to_translate = 0; |
865 |
|
return_code_written = 1; |
866 |
break; |
break; |
867 |
} |
} |
868 |
} |
} |
889 |
cpu->mem->translation_code_chunk_space_head; |
cpu->mem->translation_code_chunk_space_head; |
890 |
|
|
891 |
/* Add return code: */ |
/* Add return code: */ |
892 |
bintrans_write_chunkreturn(&ca); |
if (!return_code_written) |
893 |
|
bintrans_write_chunkreturn(&ca); |
894 |
|
|
895 |
/* chunk_len = nr of bytes occupied by the new code chunk */ |
/* chunk_len = nr of bytes occupied by the new code chunk */ |
896 |
chunk_len = (size_t)ca - (size_t)ca2; |
chunk_len = (size_t)ca - (size_t)ca2; |
902 |
|
|
903 |
/* Align the code chunk space: */ |
/* Align the code chunk space: */ |
904 |
cpu->mem->translation_code_chunk_space_head = |
cpu->mem->translation_code_chunk_space_head = |
905 |
((cpu->mem->translation_code_chunk_space_head - 1) | 63) + 1; |
((cpu->mem->translation_code_chunk_space_head - 1) | 31) + 1; |
906 |
|
|
907 |
|
|
908 |
/* RUN the code chunk: */ |
/* RUN the code chunk: */ |
1093 |
} |
} |
1094 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->refcount = 1024; |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->refcount = 1024; |
1095 |
|
|
1096 |
|
/* 1M entry cache stuff for R2K/3K: */ |
1097 |
|
if (cpu->cd.mips.cpu_type.isa_level == 1) { |
1098 |
|
cpu->cd.mips.huge_r2k3k_cache_table = |
1099 |
|
zeroed_alloc(1048576 * sizeof(unsigned char *)); |
1100 |
|
#if 1 |
1101 |
|
for (i=0; i<1048576; i++) { |
1102 |
|
unsigned char *ptr = NULL; |
1103 |
|
if (i < (0xa0000000ULL >> 12) || |
1104 |
|
i >= (0xc0000000ULL >> 12)) |
1105 |
|
ptr = cpu->cd.mips. |
1106 |
|
vaddr_to_hostaddr_r2k3k_dcachetable |
1107 |
|
->haddr_entry[(i & 1023) * 2]; |
1108 |
|
cpu->cd.mips.huge_r2k3k_cache_table[i] = ptr; |
1109 |
|
} |
1110 |
|
#endif |
1111 |
|
} |
1112 |
|
|
1113 |
/* Instruction cache: */ |
/* Instruction cache: */ |
1114 |
offset = 0; |
offset = 0; |
1115 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable = |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable = |