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.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 |
* |
* |
120 |
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; } |
121 |
void bintrans_invalidate(struct cpu *cpu, uint64_t paddr) { } |
void bintrans_invalidate(struct cpu *cpu, uint64_t paddr) { } |
122 |
int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr) { return 0; } |
int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr) { return 0; } |
123 |
|
void bintrans_restart(struct cpu *cpu) { } |
124 |
void bintrans_init_cpu(struct cpu *cpu) { } |
void bintrans_init_cpu(struct cpu *cpu) { } |
125 |
void bintrans_init(struct machine *machine, struct memory *mem) |
void bintrans_init(struct machine *machine, struct memory *mem) |
126 |
{ |
{ |
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 |
|
|
268 |
|
|
269 |
|
|
270 |
/* |
/* |
271 |
|
* bintrans_restart(): |
272 |
|
* |
273 |
|
* Starts over by throwing away the bintrans cache contents. |
274 |
|
*/ |
275 |
|
void bintrans_restart(struct cpu *cpu) |
276 |
|
{ |
277 |
|
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++) |
283 |
|
cpu->mem->translation_page_entry_array[i] = NULL; |
284 |
|
|
285 |
|
cpu->mem->translation_code_chunk_space_head = 0; |
286 |
|
cpu->mem->n_quick_jumps = 0; |
287 |
|
|
288 |
|
debug("[ bintrans: Starting over! ]\n"); |
289 |
|
clear_all_chunks_from_all_tables(cpu); |
290 |
|
} |
291 |
|
|
292 |
|
|
293 |
|
/* |
294 |
* enter_chunks_into_tables(): |
* enter_chunks_into_tables(): |
295 |
*/ |
*/ |
296 |
static void enter_chunks_into_tables(struct cpu *cpu, uint64_t vaddr, |
static void enter_chunks_into_tables(struct cpu *cpu, uint64_t vaddr, |
304 |
a = (vaddr >> 22) & 0x3ff; |
a = (vaddr >> 22) & 0x3ff; |
305 |
b = (vaddr >> 12) & 0x3ff; |
b = (vaddr >> 12) & 0x3ff; |
306 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
307 |
if (tbl1->haddr_entry[b] != NULL) |
if (tbl1->haddr_entry[b*2] != NULL) |
308 |
tbl1->bintrans_chunks[b] = chunk0; |
tbl1->bintrans_chunks[b] = chunk0; |
309 |
break; |
break; |
310 |
default: |
default: |
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 |
|
|
350 |
(paddr & 3) != 0) |
(paddr & 3) != 0) |
351 |
return cpu->cd.mips.bintrans_instructions_executed; |
return cpu->cd.mips.bintrans_instructions_executed; |
352 |
|
|
|
cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2 |
|
|
|| cpu->cd.mips.cpu_type.isa_level == 32); |
|
353 |
byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN); |
byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN); |
354 |
|
|
355 |
/* Is this a part of something that is already translated? */ |
/* Is this a part of something that is already translated? */ |
356 |
paddr_page = paddr & ~0xfff; |
paddr_page = paddr & ~0xfff; |
357 |
offset_within_page = (paddr & 0xfff) / 4; |
offset_within_page = (paddr & 0xfff) >> 2; |
358 |
entry_index = PADDR_TO_INDEX(paddr); |
entry_index = PADDR_TO_INDEX(paddr); |
359 |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
360 |
while (tep != NULL) { |
while (tep != NULL) { |
361 |
if (tep->paddr == paddr_page) { |
if (tep->paddr == paddr_page) { |
362 |
int mask = 1 << (offset_within_page & 7); |
int mask; |
363 |
|
|
364 |
if (tep->chunk[offset_within_page] != 0) { |
if (tep->chunk[offset_within_page] != 0) { |
365 |
f = (size_t)tep->chunk[offset_within_page] + |
f = (size_t)tep->chunk[offset_within_page] + |
366 |
cpu->mem->translation_code_chunk_space; |
cpu->mem->translation_code_chunk_space; |
367 |
goto run_it; /* see further down */ |
goto run_it; /* see further down */ |
368 |
} |
} |
369 |
|
|
370 |
|
mask = 1 << (offset_within_page & 7); |
371 |
if (tep->flags[offset_within_page >> 3] & mask) |
if (tep->flags[offset_within_page >> 3] & mask) |
372 |
return cpu->cd.mips. |
return cpu->cd.mips. |
373 |
bintrans_instructions_executed; |
bintrans_instructions_executed; |
393 |
*/ |
*/ |
394 |
if (cpu->mem->translation_code_chunk_space_head >= |
if (cpu->mem->translation_code_chunk_space_head >= |
395 |
cpu->machine->bintrans_size) { |
cpu->machine->bintrans_size) { |
396 |
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; |
|
397 |
tep = NULL; |
tep = NULL; |
|
debug("bintrans: Starting over!\n"); |
|
|
clear_all_chunks_from_all_tables(cpu); |
|
398 |
} |
} |
399 |
|
|
400 |
|
|
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)); |
440 |
* Try to translate a chunk of code: |
* Try to translate a chunk of code: |
441 |
*/ |
*/ |
442 |
p = paddr & 0xfff; |
p = paddr & 0xfff; |
443 |
|
prev_p = p >> 2; |
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; |
453 |
|
|
454 |
while (try_to_translate) { |
while (try_to_translate) { |
455 |
ca_justdid = ca; |
ca_justdid = ca; |
|
prev_p = p/4; |
|
456 |
translated = 0; |
translated = 0; |
457 |
|
|
458 |
/* Read an instruction word from host memory: */ |
/* Read an instruction word from host memory: */ |
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 |
|
|
630 |
case HI6_XORI: |
case HI6_XORI: |
631 |
case HI6_DADDI: |
case HI6_DADDI: |
632 |
case HI6_DADDIU: |
case HI6_DADDIU: |
633 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
translated = try_to_translate = |
634 |
rt = instr[2] & 31; |
bintrans_write_instruction__addiu_etc(cpu->mem, |
635 |
imm = (instr[1] << 8) + instr[0]; |
&ca, instr[2] & 31, |
636 |
translated = try_to_translate = bintrans_write_instruction__addiu_etc(&ca, rt, rs, imm, hi6); |
((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7), |
637 |
|
(instr[1] << 8) + instr[0], hi6); |
638 |
n_translated += translated; |
n_translated += translated; |
639 |
break; |
break; |
640 |
|
|
641 |
case HI6_LUI: |
case HI6_LUI: |
642 |
rt = instr[2] & 31; |
translated = try_to_translate = |
643 |
imm = (instr[1] << 8) + instr[0]; |
bintrans_write_instruction__lui(&ca, |
644 |
translated = try_to_translate = bintrans_write_instruction__lui(&ca, rt, imm); |
instr[2] & 31, (instr[1] << 8) + instr[0]); |
645 |
n_translated += translated; |
n_translated += translated; |
646 |
break; |
break; |
647 |
|
|
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 { |
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; |
686 |
|
return_code_written = 1; |
687 |
} |
} |
688 |
break; |
break; |
689 |
case 0x42: |
case 0x42: |
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 { |
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; |
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) { |
836 |
tep->chunk[prev_p]); |
tep->chunk[prev_p]); |
837 |
} |
} |
838 |
|
|
839 |
/* Glue together with previously translated code, if any: */ |
if (translated && try_to_translate && prev_p < 1023) { |
840 |
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; |
|
|
} |
|
841 |
|
|
842 |
if (translated && try_to_translate && n_translated > 80 |
if (tep->flags[(prev_p+1) >> 3] & mask |
843 |
&& prev_p < 1023 && !delayed_branch) { |
&& !delayed_branch) { |
844 |
bintrans_write_instruction__delayedbranch(cpu->mem, |
bintrans_write_chunkreturn_fail(&ca); |
845 |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
try_to_translate = 0; |
846 |
try_to_translate = 0; |
return_code_written = 1; |
847 |
} |
break; |
848 |
|
} |
849 |
|
|
850 |
{ |
/* Glue together with previously translated code, |
851 |
int mask = 1 << ((prev_p+1) & 7); |
if any: */ |
852 |
|
if (tep->chunk[prev_p+1] != 0 && !delayed_branch) { |
853 |
|
bintrans_write_instruction__delayedbranch(cpu->mem, |
854 |
|
&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; */ |
858 |
|
break; |
859 |
|
} |
860 |
|
|
861 |
if (translated && try_to_translate && |
if (n_translated > 120 && !delayed_branch) { |
862 |
tep->flags[(prev_p+1) >> 3] & mask |
bintrans_write_instruction__delayedbranch(cpu->mem, |
863 |
&& prev_p < 1023 && !delayed_branch) { |
&ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1); |
864 |
bintrans_write_chunkreturn_fail(&ca); |
try_to_translate = 0; |
865 |
|
return_code_written = 1; |
866 |
|
break; |
867 |
|
} |
868 |
} |
} |
|
} |
|
869 |
|
|
870 |
p += sizeof(instr); |
p += sizeof(instr); |
871 |
|
prev_p ++; |
872 |
|
|
873 |
/* If we have reached a different (MIPS) page, then stop translating. */ |
/* If we have reached a different (MIPS) page, then stop translating. */ |
874 |
if (p == 0x1000) |
if (p == 0x1000) |
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: */ |
944 |
/* tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; */ |
/* tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; */ |
945 |
|
|
946 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0[a]; |
947 |
if (tbl1->haddr_entry[b] != NULL) { |
if (tbl1->haddr_entry[b*2] != NULL) { |
948 |
paddr = tbl1->paddr_entry[b] | (cpu->pc & 0xfff); |
paddr = tbl1->paddr_entry[b] | (cpu->pc & 0xfff); |
949 |
ok = 1; |
ok = 1; |
950 |
} |
} |
968 |
|
|
969 |
if (ok) { |
if (ok) { |
970 |
paddr_page = paddr & ~0xfff; |
paddr_page = paddr & ~0xfff; |
971 |
offset_within_page = (paddr & 0xfff) / 4; |
offset_within_page = (paddr & 0xfff) >> 2; |
972 |
entry_index = PADDR_TO_INDEX(paddr); |
entry_index = PADDR_TO_INDEX(paddr); |
973 |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
tep = cpu->mem->translation_page_entry_array[entry_index]; |
974 |
while (tep != NULL) { |
while (tep != NULL) { |
975 |
if (tep->paddr == paddr_page) { |
if (tep->paddr == paddr_page) { |
976 |
int mask = 1 << (offset_within_page & 7); |
int mask; |
977 |
if (tep->chunk[offset_within_page] != 0) { |
if (tep->chunk[offset_within_page] != 0) { |
978 |
f = (size_t)tep->chunk[offset_within_page] + |
f = (size_t)tep->chunk[offset_within_page] + |
979 |
cpu->mem->translation_code_chunk_space; |
cpu->mem->translation_code_chunk_space; |
980 |
goto run_it; |
goto run_it; |
981 |
} |
} |
982 |
|
mask = 1 << (offset_within_page & 7); |
983 |
if (tep->flags[offset_within_page >> 3] & mask) |
if (tep->flags[offset_within_page >> 3] & mask) |
984 |
return cpu->cd.mips.bintrans_instructions_executed; |
return cpu->cd.mips.bintrans_instructions_executed; |
985 |
break; |
break; |
989 |
|
|
990 |
#if 1 |
#if 1 |
991 |
/* We have no translation. */ |
/* We have no translation. */ |
992 |
if ((cpu->pc & 0xfff00000) == 0xbfc00000 && |
if ((cpu->pc & 0xdff00000) == 0x9fc00000 && |
993 |
cpu->machine->prom_emulation) |
cpu->machine->prom_emulation) |
994 |
return cpu->cd.mips.bintrans_instructions_executed; |
return cpu->cd.mips.bintrans_instructions_executed; |
995 |
|
|
1007 |
cpu->cd.mips.vaddr_to_hostaddr_table0_kernel) |
cpu->cd.mips.vaddr_to_hostaddr_table0_kernel) |
1008 |
ok = 0; |
ok = 0; |
1009 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
1010 |
if (ok && tbl1->haddr_entry[b] != NULL) { |
if (ok && tbl1->haddr_entry[b*2] != NULL) { |
1011 |
cpu->cd.mips.pc_last_virtual_page = cpu->pc & ~0xfff; |
cpu->cd.mips.pc_last_virtual_page = cpu->pc & ~0xfff; |
1012 |
cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff; |
cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff; |
1013 |
cpu->cd.mips.pc_last_host_4k_page = (unsigned char *) |
cpu->cd.mips.pc_last_host_4k_page = (unsigned char *)tbl1->haddr_entry[b*2]; |
|
(((size_t)tbl1->haddr_entry[b]) & ~1); |
|
1014 |
cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page; |
cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page; |
1015 |
cpu->cd.mips.pc_bintrans_paddr = paddr; |
cpu->cd.mips.pc_bintrans_paddr = paddr; |
1016 |
|
|
1066 |
int i, offset; |
int i, offset; |
1067 |
|
|
1068 |
cpu->cd.mips.chunk_base_address = cpu->mem->translation_code_chunk_space; |
cpu->cd.mips.chunk_base_address = cpu->mem->translation_code_chunk_space; |
1069 |
cpu->cd.mips.bintrans_loadstore_32bit = bintrans_loadstore_32bit; |
cpu->cd.mips.bintrans_load_32bit = bintrans_load_32bit; |
1070 |
|
cpu->cd.mips.bintrans_store_32bit = bintrans_store_32bit; |
1071 |
cpu->cd.mips.bintrans_jump_to_32bit_pc = bintrans_jump_to_32bit_pc; |
cpu->cd.mips.bintrans_jump_to_32bit_pc = bintrans_jump_to_32bit_pc; |
1072 |
cpu->cd.mips.bintrans_fast_tlbwri = coproc_tlbwri; |
cpu->cd.mips.bintrans_fast_tlbwri = coproc_tlbwri; |
1073 |
cpu->cd.mips.bintrans_fast_tlbpr = coproc_tlbpr; |
cpu->cd.mips.bintrans_fast_tlbpr = coproc_tlbpr; |
1085 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable = |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable = |
1086 |
zeroed_alloc(sizeof(struct vth32_table)); |
zeroed_alloc(sizeof(struct vth32_table)); |
1087 |
for (i=0; i<1024; i++) { |
for (i=0; i<1024; i++) { |
1088 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->haddr_entry[i] = |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable-> |
1089 |
(void *)(((size_t)cpu->cd.mips.cache[0]+offset) | 1); |
haddr_entry[i*2] = (void *)((size_t)cpu->cd.mips.cache[0]+offset); |
1090 |
|
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable-> |
1091 |
|
haddr_entry[i*2+1] = (void *)((size_t)cpu->cd.mips.cache[0]+offset); |
1092 |
offset = (offset + 4096) % cpu->cd.mips.cache_size[0]; |
offset = (offset + 4096) % cpu->cd.mips.cache_size[0]; |
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 = |
1116 |
zeroed_alloc(sizeof(struct vth32_table)); |
zeroed_alloc(sizeof(struct vth32_table)); |
1117 |
for (i=0; i<1024; i++) { |
for (i=0; i<1024; i++) { |
1118 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->haddr_entry[i] = |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable-> |
1119 |
(void *)(((size_t)cpu->cd.mips.cache[1]+offset) | 1); |
haddr_entry[i*2] = |
1120 |
|
(void *)((size_t)cpu->cd.mips.cache[1]+offset); |
1121 |
|
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable-> |
1122 |
|
haddr_entry[i*2+1] = |
1123 |
|
(void *)((size_t)cpu->cd.mips.cache[1]+offset); |
1124 |
offset = (offset + 4096) % cpu->cd.mips.cache_size[1]; |
offset = (offset + 4096) % cpu->cd.mips.cache_size[1]; |
1125 |
} |
} |
1126 |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->refcount = 1024; |
cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->refcount = 1024; |
1142 |
} |
} |
1143 |
|
|
1144 |
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; |
1145 |
|
|
1146 |
|
cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2 |
1147 |
|
|| cpu->cd.mips.cpu_type.isa_level == 32); |
1148 |
} |
} |
1149 |
|
|
1150 |
|
|