25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips.c,v 1.63 2006/08/12 11:43:13 debug Exp $ |
* $Id: cpu_mips.c,v 1.69 2006/10/07 02:05:21 debug Exp $ |
29 |
* |
* |
30 |
* MIPS core CPU emulation. |
* MIPS core CPU emulation. |
31 |
*/ |
*/ |
50 |
#include "memory.h" |
#include "memory.h" |
51 |
#include "mips_cpu_types.h" |
#include "mips_cpu_types.h" |
52 |
#include "opcodes_mips.h" |
#include "opcodes_mips.h" |
53 |
|
#include "settings.h" |
54 |
#include "symbol.h" |
#include "symbol.h" |
55 |
|
|
56 |
|
|
61 |
static char *hi6_names[] = HI6_NAMES; |
static char *hi6_names[] = HI6_NAMES; |
62 |
static char *regimm_names[] = REGIMM_NAMES; |
static char *regimm_names[] = REGIMM_NAMES; |
63 |
static char *special_names[] = SPECIAL_NAMES; |
static char *special_names[] = SPECIAL_NAMES; |
64 |
|
static char *special_rot_names[] = SPECIAL_ROT_NAMES; |
65 |
static char *special2_names[] = SPECIAL2_NAMES; |
static char *special2_names[] = SPECIAL2_NAMES; |
66 |
static char *mmi_names[] = MMI_NAMES; |
static char *mmi_names[] = MMI_NAMES; |
67 |
static char *mmi0_names[] = MMI0_NAMES; |
static char *mmi0_names[] = MMI0_NAMES; |
325 |
cpu->translate_v2p = translate_v2p_generic; |
cpu->translate_v2p = translate_v2p_generic; |
326 |
} |
} |
327 |
|
|
328 |
|
if (cpu->machine->prom_emulation) { |
329 |
|
/* |
330 |
|
* Default behaviour of jumping to 0xbfc00000 should be |
331 |
|
* a reboot, unless machine-specific initialization code |
332 |
|
* overrides this. |
333 |
|
* |
334 |
|
* Note: Specifically big-endian machines should override |
335 |
|
* this, since the default MIPS CPU is little-endian! |
336 |
|
*/ |
337 |
|
store_32bit_word(cpu, 0xffffffff9fc00000ULL, 0x00c0de0d); |
338 |
|
} |
339 |
|
|
340 |
|
/* Add all register names to the settings: */ |
341 |
|
CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); |
342 |
|
CPU_SETTINGS_ADD_REGISTER64("hi", cpu->cd.mips.hi); |
343 |
|
CPU_SETTINGS_ADD_REGISTER64("lo", cpu->cd.mips.lo); |
344 |
|
for (i=0; i<N_MIPS_GPRS; i++) |
345 |
|
CPU_SETTINGS_ADD_REGISTER64(regnames[i], cpu->cd.mips.gpr[i]); |
346 |
|
/* TODO: Write via special handler function! */ |
347 |
|
for (i=0; i<N_MIPS_COPROC_REGS; i++) |
348 |
|
CPU_SETTINGS_ADD_REGISTER64(cop0_names[i], |
349 |
|
cpu->cd.mips.coproc[0]->reg[i]); |
350 |
|
|
351 |
return 1; |
return 1; |
352 |
} |
} |
353 |
|
|
631 |
printf("\n"); |
printf("\n"); |
632 |
break; |
break; |
633 |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
|
case MMU10K: |
|
|
printf("vaddr=0x%1x..%011"PRIx64" ", |
|
|
(int) (hi >> 60), (uint64_t) |
|
|
(hi&ENTRYHI_VPN2_MASK_R10K)); |
|
|
break; |
|
634 |
case MMU32: |
case MMU32: |
635 |
printf("vaddr=0x%08"PRIx32" ", |
printf("vaddr=0x%08"PRIx32" ", |
636 |
(uint32_t)(hi&ENTRYHI_VPN2_MASK)); |
(uint32_t) hi); |
637 |
break; |
break; |
638 |
|
case MMU10K: |
639 |
default:/* R4000 etc. */ |
default:/* R4000 etc. */ |
640 |
printf("vaddr=0x%1x..%010"PRIx64" ", |
printf("vaddr=%016"PRIx64" ", |
641 |
(int) (hi >> 60), |
(uint64_t) hi); |
|
(uint64_t) (hi&ENTRYHI_VPN2_MASK)); |
|
642 |
} |
} |
643 |
if (hi & TLB_G) |
if (hi & TLB_G) |
644 |
printf("(global): "); |
printf("(global): "); |
684 |
|
|
685 |
|
|
686 |
/* |
/* |
|
* mips_cpu_register_match(): |
|
|
*/ |
|
|
void mips_cpu_register_match(struct machine *m, char *name, |
|
|
int writeflag, uint64_t *valuep, int *match_register) |
|
|
{ |
|
|
int cpunr = 0; |
|
|
|
|
|
/* CPU number: */ |
|
|
|
|
|
/* TODO */ |
|
|
|
|
|
/* Register name: */ |
|
|
if (strcasecmp(name, "pc") == 0) { |
|
|
if (writeflag) { |
|
|
m->cpus[cpunr]->pc = *valuep; |
|
|
if (m->cpus[cpunr]->delay_slot) { |
|
|
printf("NOTE: Clearing the delay slot" |
|
|
" flag! (It was set before.)\n"); |
|
|
m->cpus[cpunr]->delay_slot = 0; |
|
|
} |
|
|
if (m->cpus[cpunr]->cd.mips.nullify_next) { |
|
|
printf("NOTE: Clearing the nullify-ne" |
|
|
"xt flag! (It was set before.)\n"); |
|
|
m->cpus[cpunr]->cd.mips.nullify_next = 0; |
|
|
} |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->pc; |
|
|
*match_register = 1; |
|
|
} else if (strcasecmp(name, "hi") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.mips.hi = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.hi; |
|
|
*match_register = 1; |
|
|
} else if (strcasecmp(name, "lo") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.mips.lo = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.lo; |
|
|
*match_register = 1; |
|
|
} else if (name[0] == 'r' && isdigit((int)name[1])) { |
|
|
int nr = atoi(name + 1); |
|
|
if (nr >= 0 && nr < N_MIPS_GPRS) { |
|
|
if (writeflag) { |
|
|
if (nr != 0) |
|
|
m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep; |
|
|
else |
|
|
printf("WARNING: Attempt to modify r0.\n"); |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; |
|
|
*match_register = 1; |
|
|
} |
|
|
} else { |
|
|
/* Check for a symbolic name such as "t6" or "at": */ |
|
|
int nr; |
|
|
for (nr=0; nr<N_MIPS_GPRS; nr++) |
|
|
if (strcmp(name, regnames[nr]) == 0) { |
|
|
if (writeflag) { |
|
|
if (nr != 0) |
|
|
m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep; |
|
|
else |
|
|
printf("WARNING: Attempt to modify r0.\n"); |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; |
|
|
*match_register = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
if (!(*match_register)) { |
|
|
/* Check for a symbolic coproc0 name: */ |
|
|
int nr; |
|
|
for (nr=0; nr<32; nr++) |
|
|
if (strcmp(name, cop0_names[nr]) == 0) { |
|
|
if (writeflag) { |
|
|
coproc_register_write(m->cpus[cpunr], |
|
|
m->cpus[cpunr]->cd.mips.coproc[0], nr, |
|
|
valuep, 1, 0); |
|
|
} else { |
|
|
/* TODO: Use coproc_register_read instead? */ |
|
|
*valuep = m->cpus[cpunr]->cd.mips.coproc[0]->reg[nr]; |
|
|
} |
|
|
*match_register = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
/* TODO: Coprocessor 1,2,3 registers. */ |
|
|
|
|
|
/* Only return lowest 32 bits when doing 32-bit emulation: */ |
|
|
if (!writeflag && m->cpus[cpunr]->is_32bit) |
|
|
*valuep = (uint32_t) (*valuep); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* cpu_flags(): |
|
|
* |
|
|
* Returns a pointer to a string containing "(d)" "(j)" "(dj)" or "", |
|
|
* depending on the cpu's current delay_slot and last_was_jumptoself |
|
|
* flags. |
|
|
*/ |
|
|
static const char *cpu_flags(struct cpu *cpu) |
|
|
{ |
|
|
if (cpu->delay_slot) { |
|
|
if (cpu->cd.mips.last_was_jumptoself) |
|
|
return " (dj)"; |
|
|
else |
|
|
return " (d)"; |
|
|
} else { |
|
|
if (cpu->cd.mips.last_was_jumptoself) |
|
|
return " (j)"; |
|
|
else |
|
|
return ""; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
687 |
* mips_cpu_disassemble_instr(): |
* mips_cpu_disassemble_instr(): |
688 |
* |
* |
689 |
* Convert an instruction word into human readable format, for instruction |
* Convert an instruction word into human readable format, for instruction |
700 |
int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, |
int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, |
701 |
int running, uint64_t dumpaddr) |
int running, uint64_t dumpaddr) |
702 |
{ |
{ |
703 |
int hi6, special6, regimm5; |
int hi6, special6, regimm5, sub; |
704 |
int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; |
int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; |
705 |
uint64_t addr, offset; |
uint64_t addr, offset; |
706 |
uint32_t instrword; |
uint32_t instrword; |
742 |
debug(": %02x%02x%02x%02x", |
debug(": %02x%02x%02x%02x", |
743 |
instr[3], instr[2], instr[1], instr[0]); |
instr[3], instr[2], instr[1], instr[0]); |
744 |
|
|
745 |
if (running) |
if (running && cpu->delay_slot) |
746 |
debug("%s", cpu_flags(cpu)); |
debug(" (d)"); |
747 |
|
|
748 |
debug("\t"); |
debug("\t"); |
749 |
|
|
751 |
* Decode the instruction: |
* Decode the instruction: |
752 |
*/ |
*/ |
753 |
|
|
|
if (cpu->cd.mips.nullify_next && running) { |
|
|
debug("(nullified)"); |
|
|
goto disasm_ret; |
|
|
} |
|
|
|
|
754 |
hi6 = (instr[3] >> 2) & 0x3f; |
hi6 = (instr[3] >> 2) & 0x3f; |
755 |
|
|
756 |
switch (hi6) { |
switch (hi6) { |
766 |
case SPECIAL_DSLL32: |
case SPECIAL_DSLL32: |
767 |
case SPECIAL_DSRL32: |
case SPECIAL_DSRL32: |
768 |
case SPECIAL_DSRA32: |
case SPECIAL_DSRA32: |
769 |
|
sub = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
770 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
771 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
772 |
sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
780 |
debug("ehb"); |
debug("ehb"); |
781 |
else |
else |
782 |
debug("nop (weird, sa=%i)", sa); |
debug("nop (weird, sa=%i)", sa); |
783 |
goto disasm_ret; |
break; |
784 |
} else |
} |
785 |
|
|
786 |
|
switch (sub) { |
787 |
|
case 0x00: |
788 |
debug("%s\t%s,", |
debug("%s\t%s,", |
789 |
special_names[special6], |
special_names[special6], |
790 |
regname(cpu->machine, rd)); |
regname(cpu->machine, rd)); |
791 |
debug("%s,%i", regname(cpu->machine, rt), sa); |
debug("%s,%i", regname(cpu->machine, rt), sa); |
792 |
|
break; |
793 |
|
case 0x01: |
794 |
|
debug("%s\t%s,", |
795 |
|
special_rot_names[special6], |
796 |
|
regname(cpu->machine, rd)); |
797 |
|
debug("%s,%i", regname(cpu->machine, rt), sa); |
798 |
|
break; |
799 |
|
default:debug("UNIMPLEMENTED special, sub=0x%02x\n", |
800 |
|
sub); |
801 |
|
} |
802 |
break; |
break; |
803 |
case SPECIAL_DSRLV: |
case SPECIAL_DSRLV: |
804 |
case SPECIAL_DSRAV: |
case SPECIAL_DSRAV: |
809 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
810 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
811 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
812 |
debug("%s\t%s", |
sub = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
813 |
special_names[special6], regname(cpu->machine, rd)); |
|
814 |
debug(",%s", regname(cpu->machine, rt)); |
switch (sub) { |
815 |
debug(",%s", regname(cpu->machine, rs)); |
case 0x00: |
816 |
|
debug("%s\t%s", special_names[special6], |
817 |
|
regname(cpu->machine, rd)); |
818 |
|
debug(",%s", regname(cpu->machine, rt)); |
819 |
|
debug(",%s", regname(cpu->machine, rs)); |
820 |
|
break; |
821 |
|
case 0x01: |
822 |
|
debug("%s\t%s", special_rot_names[special6], |
823 |
|
regname(cpu->machine, rd)); |
824 |
|
debug(",%s", regname(cpu->machine, rt)); |
825 |
|
debug(",%s", regname(cpu->machine, rs)); |
826 |
|
break; |
827 |
|
default:debug("UNIMPLEMENTED special, sub=0x%02x\n", |
828 |
|
sub); |
829 |
|
} |
830 |
break; |
break; |
831 |
case SPECIAL_JR: |
case SPECIAL_JR: |
832 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
833 |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
834 |
cpu->cd.mips.gpr[rs], &offset); |
cpu->cd.mips.gpr[rs], &offset); |
835 |
debug("jr\t%s", regname(cpu->machine, rs)); |
/* .hb = hazard barrier hint on MIPS32/64 rev 2 */ |
836 |
|
debug("jr%s\t%s", |
837 |
|
(instr[1] & 0x04) ? ".hb" : "", |
838 |
|
regname(cpu->machine, rs)); |
839 |
if (running && symbol != NULL) |
if (running && symbol != NULL) |
840 |
debug("\t<%s>", symbol); |
debug("\t<%s>", symbol); |
841 |
break; |
break; |
844 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
845 |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
846 |
cpu->cd.mips.gpr[rs], &offset); |
cpu->cd.mips.gpr[rs], &offset); |
847 |
debug("jalr\t%s", regname(cpu->machine, rd)); |
/* .hb = hazard barrier hint on MIPS32/64 rev 2 */ |
848 |
|
debug("jalr%s\t%s", |
849 |
|
(instr[1] & 0x04) ? ".hb" : "", |
850 |
|
regname(cpu->machine, rd)); |
851 |
debug(",%s", regname(cpu->machine, rs)); |
debug(",%s", regname(cpu->machine, rs)); |
852 |
if (running && symbol != NULL) |
if (running && symbol != NULL) |
853 |
debug("\t<%s>", symbol); |
debug("\t<%s>", symbol); |
1084 |
} |
} |
1085 |
if (hi6 == HI6_SQ_SPECIAL3 && |
if (hi6 == HI6_SQ_SPECIAL3 && |
1086 |
cpu->cd.mips.cpu_type.rev != MIPS_R5900) { |
cpu->cd.mips.cpu_type.rev != MIPS_R5900) { |
1087 |
|
int msbd, lsb, sub10; |
1088 |
special6 = instr[0] & 0x3f; |
special6 = instr[0] & 0x3f; |
|
debug("%s", special3_names[special6]); |
|
1089 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
1090 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
1091 |
rd = (instr[1] >> 3) & 31; |
rd = msbd = (instr[1] >> 3) & 31; |
1092 |
|
lsb = ((instr[1] & 7) << 2) | (instr[0] >> 6); |
1093 |
|
sub10 = (rs << 5) | lsb; |
1094 |
|
|
1095 |
switch (special6) { |
switch (special6) { |
1096 |
|
|
1097 |
|
case SPECIAL3_EXT: |
1098 |
|
case SPECIAL3_DEXT: |
1099 |
|
case SPECIAL3_DEXTM: |
1100 |
|
case SPECIAL3_DEXTU: |
1101 |
|
debug("%s", special3_names[special6]); |
1102 |
|
if (special6 == SPECIAL3_DEXTM) |
1103 |
|
msbd += 32; |
1104 |
|
if (special6 == SPECIAL3_DEXTU) |
1105 |
|
lsb += 32; |
1106 |
|
debug("\t%s", regname(cpu->machine, rt)); |
1107 |
|
debug(",%s", regname(cpu->machine, rs)); |
1108 |
|
debug(",%i,%i", lsb, msbd + 1); |
1109 |
|
break; |
1110 |
|
|
1111 |
|
case SPECIAL3_INS: |
1112 |
|
case SPECIAL3_DINS: |
1113 |
|
case SPECIAL3_DINSM: |
1114 |
|
case SPECIAL3_DINSU: |
1115 |
|
debug("%s", special3_names[special6]); |
1116 |
|
if (special6 == SPECIAL3_DINSM) |
1117 |
|
msbd += 32; |
1118 |
|
if (special6 == SPECIAL3_DINSU) { |
1119 |
|
lsb += 32; |
1120 |
|
msbd += 32; |
1121 |
|
} |
1122 |
|
msbd -= lsb; |
1123 |
|
debug("\t%s", regname(cpu->machine, rt)); |
1124 |
|
debug(",%s", regname(cpu->machine, rs)); |
1125 |
|
debug(",%i,%i", lsb, msbd + 1); |
1126 |
|
break; |
1127 |
|
|
1128 |
|
case SPECIAL3_BSHFL: |
1129 |
|
switch (sub10) { |
1130 |
|
case BSHFL_WSBH: |
1131 |
|
case BSHFL_SEB: |
1132 |
|
case BSHFL_SEH: |
1133 |
|
switch (sub10) { |
1134 |
|
case BSHFL_WSBH: debug("wsbh"); break; |
1135 |
|
case BSHFL_SEB: debug("seb"); break; |
1136 |
|
case BSHFL_SEH: debug("seh"); break; |
1137 |
|
} |
1138 |
|
debug("\t%s", regname(cpu->machine,rd)); |
1139 |
|
debug(",%s", regname(cpu->machine,rt)); |
1140 |
|
break; |
1141 |
|
default:debug("%s", special3_names[special6]); |
1142 |
|
debug("\t(UNIMPLEMENTED)"); |
1143 |
|
} |
1144 |
|
break; |
1145 |
|
|
1146 |
|
case SPECIAL3_DBSHFL: |
1147 |
|
switch (sub10) { |
1148 |
|
case BSHFL_DSBH: |
1149 |
|
case BSHFL_DSHD: |
1150 |
|
switch (sub10) { |
1151 |
|
case BSHFL_DSBH: debug("dsbh"); break; |
1152 |
|
case BSHFL_DSHD: debug("dshd"); break; |
1153 |
|
} |
1154 |
|
debug("\t%s", regname(cpu->machine,rd)); |
1155 |
|
debug(",%s", regname(cpu->machine,rt)); |
1156 |
|
break; |
1157 |
|
default:debug("%s", special3_names[special6]); |
1158 |
|
debug("\t(UNIMPLEMENTED)"); |
1159 |
|
} |
1160 |
|
break; |
1161 |
|
|
1162 |
case SPECIAL3_RDHWR: |
case SPECIAL3_RDHWR: |
1163 |
|
debug("%s", special3_names[special6]); |
1164 |
debug("\t%s", regname(cpu->machine, rt)); |
debug("\t%s", regname(cpu->machine, rt)); |
1165 |
debug(",hwr%i", rd); |
debug(",hwr%i", rd); |
1166 |
break; |
break; |
1167 |
|
|
1168 |
default: |
default:debug("%s", special3_names[special6]); |
1169 |
debug("\t(UNIMPLEMENTED)"); |
debug("\t(UNIMPLEMENTED)"); |
1170 |
} |
} |
1171 |
break; |
break; |
1450 |
|
|
1451 |
case HI6_REGIMM: |
case HI6_REGIMM: |
1452 |
regimm5 = instr[2] & 0x1f; |
regimm5 = instr[2] & 0x1f; |
1453 |
|
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
1454 |
|
imm = (instr[1] << 8) + instr[0]; |
1455 |
|
if (imm >= 32768) |
1456 |
|
imm -= 65536; |
1457 |
|
|
1458 |
switch (regimm5) { |
switch (regimm5) { |
1459 |
|
|
1460 |
case REGIMM_BLTZ: |
case REGIMM_BLTZ: |
1461 |
case REGIMM_BGEZ: |
case REGIMM_BGEZ: |
1462 |
case REGIMM_BLTZL: |
case REGIMM_BLTZL: |
1465 |
case REGIMM_BLTZALL: |
case REGIMM_BLTZALL: |
1466 |
case REGIMM_BGEZAL: |
case REGIMM_BGEZAL: |
1467 |
case REGIMM_BGEZALL: |
case REGIMM_BGEZALL: |
|
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
|
|
imm = (instr[1] << 8) + instr[0]; |
|
|
if (imm >= 32768) |
|
|
imm -= 65536; |
|
|
|
|
1468 |
debug("%s\t%s,", regimm_names[regimm5], |
debug("%s\t%s,", regimm_names[regimm5], |
1469 |
regname(cpu->machine, rs)); |
regname(cpu->machine, rs)); |
1470 |
|
|
1475 |
else |
else |
1476 |
debug("0x%016"PRIx64, (uint64_t) addr); |
debug("0x%016"PRIx64, (uint64_t) addr); |
1477 |
break; |
break; |
1478 |
|
|
1479 |
|
case REGIMM_SYNCI: |
1480 |
|
debug("%s\t%i(%s)", regimm_names[regimm5], |
1481 |
|
imm, regname(cpu->machine, rs)); |
1482 |
|
break; |
1483 |
|
|
1484 |
default: |
default: |
1485 |
debug("unimplemented regimm5 = 0x%02x", regimm5); |
debug("unimplemented regimm5 = 0x%02x", regimm5); |
1486 |
} |
} |
2053 |
/* debug("[ warning: cpu%i exception while EXL is set," |
/* debug("[ warning: cpu%i exception while EXL is set," |
2054 |
" not setting EPC ]\n", cpu->cpu_id); */ |
" not setting EPC ]\n", cpu->cpu_id); */ |
2055 |
} else { |
} else { |
2056 |
if (cpu->delay_slot || cpu->cd.mips.nullify_next) { |
if (cpu->delay_slot) { |
2057 |
reg[COP0_EPC] = cpu->pc - 4; |
reg[COP0_EPC] = cpu->pc - 4; |
2058 |
reg[COP0_CAUSE] |= CAUSE_BD; |
reg[COP0_CAUSE] |= CAUSE_BD; |
|
|
|
|
/* TODO: Should the BD flag actually be set |
|
|
on nullified slots? */ |
|
2059 |
} else { |
} else { |
2060 |
reg[COP0_EPC] = cpu->pc; |
reg[COP0_EPC] = cpu->pc; |
2061 |
reg[COP0_CAUSE] &= ~CAUSE_BD; |
reg[COP0_CAUSE] &= ~CAUSE_BD; |
2067 |
else |
else |
2068 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
2069 |
|
|
|
cpu->cd.mips.nullify_next = 0; |
|
|
|
|
2070 |
/* TODO: This is true for MIPS64, but how about others? */ |
/* TODO: This is true for MIPS64, but how about others? */ |
2071 |
if (reg[COP0_STATUS] & STATUS_BEV) |
if (reg[COP0_STATUS] & STATUS_BEV) |
2072 |
base = 0xffffffffbfc00200ULL; |
base = 0xffffffffbfc00200ULL; |