mirror of
https://github.com/zeldaret/oot-vc.git
synced 2026-10-02 23:55:14 -04:00
2921 lines
108 KiB
C
2921 lines
108 KiB
C
#include "cpu.h"
|
|
#include "mips.h"
|
|
#include "rom.h"
|
|
#include "xlHeap.h"
|
|
#include "system.h"
|
|
|
|
int cpuGetAddressBuffer(cpu_class_t *cpu, void **buffer, u32 addr);
|
|
int cpuFreeCachedAddress(cpu_class_t *cpu, s32, s32);
|
|
int func_8003E604(cpu_class_t *cpu, s32, s32);
|
|
int rspGetBuffer(void *, void **, u32, void *);
|
|
int func_8000E054(cpu_class_t *cpu, u32, u32, u32, u32);
|
|
int func_8000CB1C(cpu_class_t *cpu);
|
|
int cpuMakeDevice(cpu_class_t *cpu, u32*, void *, s32, s32, u32, u32);
|
|
void DCStoreRange(void *, size_t);
|
|
void ICInvalidateRange(void *, size_t);
|
|
double sqrt(double in);
|
|
double ceil(double in);
|
|
double floor(double in);
|
|
|
|
extern class_t lbl_80171F38;
|
|
extern u32 lbl_80170B68[32];
|
|
extern void (*lbl_8025CFE8)();
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuTestInterrupt.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuException.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuMakeDevice.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000D580.s")
|
|
|
|
s32 func_8000D6EC(cpu_class_t *cpu, s32 arg1);
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000D6EC.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000DEBC.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000DF58.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E054.s")
|
|
|
|
s32 func_8000E0E8(cpu_class_t *cpu, s32 reg, u32 hi, u32 lo);
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E0E8.s")
|
|
|
|
s32 func_8000E2B0(cpu_class_t *cpu, s32, u32*);
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E2B0.s")
|
|
|
|
int func_8000E43C(cpu_class_t *cpu) {
|
|
if(cpu->cp0[0xC].d & 4) {
|
|
cpu->pc = cpu->cp0[0x1E].d;
|
|
cpu->cp0[0xC].d &= ~4;
|
|
} else {
|
|
cpu->pc = cpu->cp0[0xE].d;
|
|
cpu->cp0[0xC].d &= ~2;
|
|
}
|
|
|
|
cpu->unk_0x00 |= 0x24;
|
|
return 1;
|
|
}
|
|
|
|
int __cpuBreak(cpu_class_t *cpu) {
|
|
cpu->unk_0x00 |= 2;
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E4B8.s")
|
|
|
|
#ifdef NON_MATCHING
|
|
// matches, but jump table
|
|
int cpuCheckDelaySlot(u32 inst) {
|
|
s32 t;
|
|
int ret = 0;
|
|
if(inst == 0) {
|
|
return 0;
|
|
}
|
|
|
|
switch(inst >> 0x1A) {
|
|
case 0:
|
|
switch(inst & 0x3F) {
|
|
case 8:
|
|
ret = 0xD05;
|
|
break;
|
|
case 9:
|
|
ret = 0x8AE;
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
switch((inst >> 0x10) & 0x1F) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
ret = 0x457;
|
|
break;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
switch(inst & 0x3F) {
|
|
default:
|
|
switch((inst >> 0x15) & 0x1F) {
|
|
default:
|
|
break;
|
|
case 8:
|
|
switch((inst >> 0x10) & 0x1F) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
ret = 0x457;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 5:
|
|
case 8:
|
|
case 0x18:
|
|
break;
|
|
}
|
|
break;
|
|
case 0x11:
|
|
if(((inst >> 0x15) & 0x1F) == 8) {
|
|
switch((inst >> 0x10) & 0x1F) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
ret = 0x457;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
ret = 0xD05;
|
|
break;
|
|
case 3:
|
|
ret = 0x8AE;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
ret = 0x457;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCheckDelaySlot.s")
|
|
#endif
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E654.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E734.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8000E81C.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuGetPPC.s")
|
|
|
|
int func_80031D4C() {
|
|
return 0;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuMakeFunction.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_80032248.s")
|
|
|
|
inline s32 find_in_node_unk_0xC(recomp_node_t *node, s32 pc) {
|
|
int i;
|
|
|
|
for(i = 0; i < node->unk_0x08; i++) {
|
|
if(pc == node->unk_0x0C[i].unk_0x04) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int func_800326D0(cpu_class_t *cpu, s32 pc, s32 r5) {
|
|
if(!cpu->unk_0x12270) {
|
|
return 0;
|
|
}
|
|
|
|
if(cpu->unk_0x12274 == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if(r5 != cpu->unk_0x12278) {
|
|
return 0;
|
|
}
|
|
|
|
if(!find_in_node_unk_0xC(cpu->running_node, pc)) {
|
|
cpu->unk_0x12274 = 0;
|
|
return 0;
|
|
}
|
|
|
|
cpu->unk_0x12274 = 0;
|
|
return 1;
|
|
}
|
|
|
|
int func_80032780(cpu_class_t *cpu, s32 pc, s32 r5) {
|
|
if(!cpu->unk_0x12270) {
|
|
return 0;
|
|
}
|
|
|
|
if(cpu->unk_0x12280 == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if(r5 != cpu->unk_0x12284) {
|
|
return 0;
|
|
}
|
|
|
|
if(!find_in_node_unk_0xC(cpu->running_node, pc)) {
|
|
cpu->unk_0x12280 = 0;
|
|
return 0;
|
|
}
|
|
|
|
cpu->unk_0x12280 =0;
|
|
return 1;
|
|
}
|
|
|
|
int func_80032830(cpu_class_t *cpu, s32 pc, u32 *code, s32 base, s32 rt) {
|
|
s32 i;
|
|
|
|
if(code == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if(!cpu->unk_0x12270) {
|
|
return 0;
|
|
}
|
|
|
|
if(!find_in_node_unk_0xC(cpu->running_node, pc)) {
|
|
return 0;
|
|
}
|
|
|
|
cpu->unk_0x12288 = 1;
|
|
|
|
if(base == rt) {
|
|
cpu->unk_0x1228C = -1;
|
|
return 0;
|
|
}
|
|
|
|
if(cpu->unk_0x1228C != base) {
|
|
cpu->unk_0x1228C = base;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void func_8007FCD0();
|
|
|
|
#ifdef NON_MATCHING
|
|
int func_800328EC(cpu_class_t *cpu, u32 addr, s32 inst, u32 *code, u32 *pos) {
|
|
if(code == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if(cpu->unk_0x12270 == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if(cpu->unk_0x12294 != addr - 4) {
|
|
cpu->unk_0x12294 = 0;
|
|
return 0;
|
|
}
|
|
|
|
cpu->unk_0x12294 = 0;
|
|
|
|
if(!find_in_node_unk_0xC(cpu->running_node, addr)) {
|
|
return 0;
|
|
}
|
|
|
|
switch(inst >> 0x1A) {
|
|
case 0xD:
|
|
if(cpu->unk_0x12278 == ((inst >> 0x15) & 0x1F) && ((inst >> 0x15) & 0x1F) == ((inst >> 0x10) & 0x1F)) {
|
|
if(cpu->unk_0x12290 != 1000) {
|
|
return 0;
|
|
}
|
|
code[*pos - 1] = 0x60000000;
|
|
code[(*pos)++] = (inst & 0xFFFF) | (cpu->unk_0x1227C << 0x10) | (cpu->unk_0x1227C << 0x15) | 0x60000000;
|
|
code[(*pos)++] = 0x60000000;
|
|
code[(*pos)++] = (((inst >> 0x10) & 0x1F) * 8) + ((cpu->unk_0x1227C << 0x15) | 0x90030000) + ((u32)&cpu->gpr[0] - (u32)cpu);
|
|
cpu->unk_0x12274 = 2;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
case 9:
|
|
if(cpu->unk_0x12278 == ((inst >> 0x15) & 0x1F) && ((inst >> 0x15) & 0x1F) == ((inst >> 0x10) & 0x1F)) {
|
|
if(cpu->unk_0x12290 != 1000) {
|
|
return 0;
|
|
}
|
|
|
|
code[*pos - 1] = 0x60000000;
|
|
code[(*pos)++] = (inst & 0xFFFF) | (cpu->unk_0x1227C << 0x10) | (cpu->unk_0x1227C << 0x15) | 0x38000000;
|
|
code[(*pos)++] = 0x60000000;
|
|
code[(*pos)++] = (((inst >> 0x10) & 0x1F) * 8) + ((cpu->unk_0x1227C << 0x15) | 0x90030000) + ((u32)&cpu->gpr[0] - (u32)cpu);
|
|
cpu->unk_0x12274 = 2;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
default:
|
|
func_8007FCD0();
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_800328EC.s")
|
|
#endif
|
|
|
|
void func_80032B74(u32 arg0) {
|
|
gSystem->cpu->unk_0x3C = arg0;
|
|
if(lbl_8025CFE8 != NULL) {
|
|
lbl_8025CFE8();
|
|
}
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteUpdate.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DSLLV.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DSRLV.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DSRAV.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DMULT.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DMULTU.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DDIV.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_DDIVU.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_S_SQRT.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_D_SQRT.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_W_CVT_SD.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_L_CVT_SD.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_CEIL_W.s")
|
|
|
|
#ifdef NON_MATCHING
|
|
|
|
inline u32 PPC_STWU(u32 rS, u32 rA, s16 offset) {
|
|
return (0x25 << 0x1A) | ((rS & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | (offset & 0xFFFF);
|
|
}
|
|
|
|
inline u32 PPC_LFD(u32 rD, u32 rA, s16 offset) {
|
|
return (0x32 << 0x1A) | ((rD & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | (offset & 0xFFFF);
|
|
}
|
|
|
|
inline u32 PPC_FCMPO(u32 crfD, u32 frA, u32 frB) {
|
|
return (0x3F << 0x1A) | ((crfD & 7) << 0x15) | ((frA & 0x1F) << 0x10) | ((frB & 0x1F) << 0x10) | (0x20 << 1);
|
|
}
|
|
|
|
inline u32 PPC_BC(u32 BO, u32 BI, s32 target) {
|
|
return (0x10 << 0x1A) | ((BO & 0x1F) << 0x15) | ((BI & 0x1F) << 0x10) | (target & 0x3FFC);
|
|
}
|
|
|
|
inline u32 PPC_BLT(s32 target) {
|
|
return PPC_BC(12, 0, target);
|
|
}
|
|
|
|
inline u32 PPC_ADDI(u32 rD, u32 rA, s16 imm) {
|
|
return (0xE << 0x1A) | ((rD & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | (imm & 0xFFFF);
|
|
}
|
|
|
|
inline u32 PPC_FCTIWZ(u32 frD, u32 frB, u32 rC) {
|
|
return (0x3F << 0x1A) | ((frD & 0x1F) << 0x15) | ((frB & 0x1F) << 0xB) | (0xF << 1) | ((rC & 1) << 0);
|
|
}
|
|
|
|
inline u32 PPC_STFD(u32 frS, u32 rA, s16 offset) {
|
|
return (0x36 << 0x1A) | ((frS & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | (offset & 0xFFFF);
|
|
}
|
|
|
|
inline u32 PPC_LWZ(u32 rD, u32 rA, s16 offset) {
|
|
return (0x20 << 0x1A) | ((rD & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | (offset & 0xFFFF);
|
|
}
|
|
|
|
inline u32 PPC_SUBF(u32 rD, u32 rA, u32 rB) {
|
|
return (0x1F << 0x1A) | ((rD & 0x1F) << 0x15) | ((rA & 0x1F) << 0x10) | ((rB & 0x1F) << 0xB) | (0x28 << 1);
|
|
}
|
|
|
|
inline u32 PPC_BLR() {
|
|
return (0x13 << 0x1A) | (0x14 << 0x15) | (0x10 << 1);
|
|
}
|
|
|
|
|
|
int cpuCompile_FLOOR_W(cpu_class_t *cpu, u32 **code) {
|
|
u32 *buf;
|
|
|
|
if(!xlHeapTake((void**)&buf, 0x30000034)) {
|
|
return 0;
|
|
}
|
|
|
|
*code = buf;
|
|
buf[0] = PPC_STWU(1, 1, -32);
|
|
buf[1] = PPC_LFD(0, 3, ((s32)&cpu->fpr[0] - (s32)cpu));
|
|
//buf[1] = 0xc8030000 | ((u32)&cpu->fpr[0] - (u32)cpu);
|
|
//buf[2] = 0xfc010040;
|
|
buf[2] = PPC_FCMPO(0, 1, 0);
|
|
//buf[3] = 0x4180000c;
|
|
buf[3] = PPC_BLT(12);
|
|
//buf[4] = 0x38c00000;
|
|
buf[4] = PPC_ADDI(6, 0, 0);
|
|
//buf[5] = 0x42800008;
|
|
buf[5] = PPC_BC(20, 0, 8);
|
|
//buf[6] = 0x38c00001;
|
|
buf[6] = PPC_ADDI(6, 0, 1);
|
|
buf[7] = PPC_FCTIWZ(1, 1, 0);
|
|
//buf[7] = 0xfc20081e;
|
|
//buf[8] = 0xd8210010;
|
|
buf[8] = PPC_STFD(1, 1, 16);
|
|
//buf[9] = 0x80a10014;
|
|
buf[9] = PPC_LWZ(5, 1, 20);
|
|
//buf[10] = 0x7ca62850;
|
|
buf[10] = PPC_SUBF(5, 6, 5);
|
|
buf[11] = PPC_ADDI(1, 1, 32);
|
|
//buf[11] = 0x38210020;
|
|
//buf[12] = 0x4E800020;
|
|
buf[12] = PPC_BLR();
|
|
DCStoreRange(buf, 0x34);
|
|
ICInvalidateRange(buf, 0x34);
|
|
return 1;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_FLOOR_W.s")
|
|
#endif
|
|
|
|
#ifdef NON_MATCHING
|
|
int cpuCompile_LB(cpu_class_t *cpu, void **code) {
|
|
u32 *buf;
|
|
|
|
if(!xlHeapTake((void**)&buf, 0x3000002C)) {
|
|
return 0;
|
|
}
|
|
|
|
*code = buf;
|
|
buf[0] = 0x54c6103a;
|
|
buf[1] = 0x38e30000 | ((u32)&cpu->devices - (u32)cpu);
|
|
buf[2] = 0x7cc6382e;
|
|
buf[3] = 0x80e60008;
|
|
buf[4] = 0x7ca53a14;
|
|
buf[5] = 0x80e60004;
|
|
buf[6] = 0x80e70004;
|
|
buf[7] = 0x7ca538ae;
|
|
buf[8] = 0x7ca50774;
|
|
buf[9] = 0x4e800020;
|
|
|
|
DCStoreRange(buf, 0x28);
|
|
ICInvalidateRange(buf, 0x28);
|
|
|
|
return 1;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LB.s")
|
|
#endif
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LH.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LW.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LBU.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LHU.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_SB.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_SH.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_SW.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LDC.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_SDC.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LWL.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuCompile_LWR.s")
|
|
|
|
u32 OSGetTick(void);
|
|
s32 systemCheckInterrupts(system_class_t *sys);
|
|
inline s32 checkRetrace() {
|
|
if(gSystem->unk_0x00 != 0) {
|
|
if(!systemCheckInterrupts(gSystem)) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
videoForceRetrace(gSystem->video);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
inline unkFrameSet(u32 rom_id, u32 *frame, u32 addr) {
|
|
if(rom_id == 'NKTJ') {
|
|
if(addr == 0x802A4118) {
|
|
frame[0x11] = 0;
|
|
}
|
|
if(addr == 0x80072D94) {
|
|
frame[0x11] = 1;
|
|
}
|
|
} else if(rom_id == 'NKTP') {
|
|
if(addr == 0x802A4160) {
|
|
frame[0x11] = 0;
|
|
}
|
|
if(addr == 0x80072E34) {
|
|
frame[0x11] = 1;
|
|
}
|
|
} else if(rom_id == 'NKTE') {
|
|
if(addr == 0x802A4160) {
|
|
frame[0x11] = 0;
|
|
}
|
|
if(addr == 0x80072E54) {
|
|
frame[0x11] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
inline cpu_dev_t *get_dev(cpu_dev_t **devs, u8 *idxs, u32 addr) {
|
|
return devs[idxs[(addr >> 0x10)]];
|
|
}
|
|
|
|
inline s32 calc_ea(cpu_class_t *cpu, s32 reg, s32 imm) {
|
|
return cpu->gpr[reg].w[1] + (u32)imm;
|
|
}
|
|
|
|
void *cpuExecuteOpcode(cpu_class_t *cpu, s32 arg1, u32 addr, u32 *ret) {
|
|
s32 save_ra = 0;
|
|
u32 tick = OSGetTick();
|
|
u32 *code_buf;
|
|
u32 inst;
|
|
u64 prev_ra;
|
|
u8 *dev_idx;
|
|
cpu_dev_t *dev;
|
|
cpu_dev_t **devs;
|
|
reg64_t tmp;
|
|
s32 i;
|
|
s32 val;
|
|
u32 ea;
|
|
|
|
if(cpu->unk_0x24 != 0) {
|
|
cpu->unk_0x00 |= 8;
|
|
} else {
|
|
cpu->unk_0x00 &= ~8;
|
|
}
|
|
|
|
unkFrameSet(gSystem->rom_id, gSystem->frame, addr);
|
|
|
|
dev_idx = cpu->mem_hi_map;
|
|
devs = cpu->devices;
|
|
|
|
if(!cpuGetAddressBuffer(cpu, (void**)&code_buf, addr)) {
|
|
return NULL;
|
|
}
|
|
|
|
inst = *code_buf;
|
|
cpu->pc = addr + 4;
|
|
if(inst == 0xACBF011C) {
|
|
prev_ra = cpu->gpr[0x1F].d;
|
|
cpu->gpr[0x1F].w[1] = cpu->unk_0x30;
|
|
save_ra = 1;
|
|
}
|
|
|
|
switch(MIPS_OP(inst)) {
|
|
case OPC_SPECIAL:
|
|
switch(SPEC_FUNCT(inst)) {
|
|
case SPEC_SLL: // SLL
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RT(inst)].w[1] << MIPS_SA(inst);
|
|
break;
|
|
case SPEC_SRL: // SRL
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RT(inst)].w[1] >> MIPS_SA(inst);
|
|
break;
|
|
case SPEC_SRA: // SRA
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] = cpu->gpr[MIPS_RT(inst)].sw[1] >> MIPS_SA(inst);
|
|
break;
|
|
case SPEC_SLLV: // SLLV
|
|
cpu->gpr[MIPS_RD(inst)].w[1] =
|
|
cpu->gpr[MIPS_RT(inst)].w[1] << (cpu->gpr[MIPS_RS(inst)].w[1] & 0x1F);
|
|
break;
|
|
case SPEC_SRLV: // SRLV
|
|
cpu->gpr[MIPS_RD(inst)].w[1] =
|
|
cpu->gpr[MIPS_RT(inst)].w[1] >> (cpu->gpr[MIPS_RS(inst)].w[1] & 0x1F);
|
|
break;
|
|
case SPEC_SRAV: // SRAV
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] =
|
|
cpu->gpr[MIPS_RT(inst)].sw[1] >> (cpu->gpr[MIPS_RS(inst)].sw[1] & 0x1F);
|
|
break;
|
|
case SPEC_JR: // JR
|
|
cpu->unk_0x24 = cpu->gpr[MIPS_RS(inst)].w[1];
|
|
break;
|
|
case SPEC_JALR: // JALR
|
|
cpu->unk_0x24 = cpu->gpr[MIPS_RS(inst)].w[1];
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->pc + 4;
|
|
break;
|
|
case SPEC_SYSCALL: // SYSCALL
|
|
cpuException(cpu, 8, 0);
|
|
break;
|
|
case SPEC_BREAK: // BREAk
|
|
cpuException(cpu, 9, 0);
|
|
break;
|
|
case SPEC_MFHI: // MFHI
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->hi.d;
|
|
break;
|
|
case SPEC_MTHI: // MTHI
|
|
cpu->hi.d = cpu->gpr[MIPS_RS(inst)].d;
|
|
break;
|
|
case SPEC_MFLO: // MFLO
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->lo.d;
|
|
break;
|
|
case SPEC_MTLO: // MTLO
|
|
cpu->lo.d = cpu->gpr[MIPS_RD(inst)].d;
|
|
break;
|
|
case SPEC_DSLLV: // DSLLV
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d << (cpu->gpr[MIPS_RS(inst)].d & 0x1F);
|
|
break;
|
|
case SPEC_DSRLV: // DSRLV
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d >> (cpu->gpr[MIPS_RS(inst)].d & 0x1F);
|
|
break;
|
|
case SPEC_DSRAV: // DRAV
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RT(inst)].sd >> (cpu->gpr[MIPS_RS(inst)].sd & 0x1F);
|
|
break;
|
|
case SPEC_MULT: // MULT
|
|
{
|
|
s64 rs = cpu->gpr[MIPS_RS(inst)].sw[1];
|
|
s64 rt = cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
tmp.sd = (s64)(rs * rt);
|
|
cpu->lo.sd = (s32)(tmp.sd & 0xFFFFFFFF);
|
|
cpu->hi.sd = (s32)(tmp.sd >> 32);
|
|
}
|
|
break;
|
|
case SPEC_MULTU: // MULTU
|
|
{
|
|
u64 rs = cpu->gpr[MIPS_RS(inst)].w[1];
|
|
u64 rt = cpu->gpr[MIPS_RT(inst)].w[1];
|
|
tmp.d = (s64)(rs * rt);
|
|
cpu->lo.sd = (s32)(tmp.sd & 0xFFFFFFFF);
|
|
cpu->hi.sd = (s32)(tmp.sd >> 32);
|
|
}
|
|
break;
|
|
case SPEC_DIV: // DIV
|
|
{
|
|
if(cpu->gpr[MIPS_RT(inst)].w[1] == 0) {
|
|
break;
|
|
}
|
|
|
|
cpu->lo.sd = cpu->gpr[MIPS_RS(inst)].sw[1] / cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
|
|
cpu->hi.sd = cpu->gpr[MIPS_RS(inst)].sw[1] % cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
}
|
|
break;
|
|
case SPEC_DIVU: // DIVU
|
|
{
|
|
if(cpu->gpr[MIPS_RT(inst)].w[1] == 0) {
|
|
break;
|
|
}
|
|
|
|
cpu->lo.sd = (s32)(cpu->gpr[MIPS_RS(inst)].w[1] / cpu->gpr[MIPS_RT(inst)].w[1]);
|
|
cpu->hi.sd = (s32)(cpu->gpr[MIPS_RS(inst)].w[1] % cpu->gpr[MIPS_RT(inst)].w[1]);
|
|
}
|
|
break;
|
|
|
|
case SPEC_DMULT: // DMULT
|
|
{
|
|
|
|
reg64_t *rs = &cpu->gpr[MIPS_RS(inst)];
|
|
reg64_t *rt = &cpu->gpr[MIPS_RT(inst)];
|
|
|
|
cpu->lo.w[1] = rs->w[1] * rt->w[1];
|
|
cpu->lo.w[0] = (u32)(((u64)rs->w[1] * (u64)rt->w[1]) >> 32) + (rs->w[0] * rt->w[1]);
|
|
cpu->hi.sd = -((cpu->lo.w[0] ^ 0x80000000) < 0x80000000);
|
|
}
|
|
break;
|
|
case SPEC_DMULTU: // DMULTU
|
|
{
|
|
tmp.d = cpu->gpr[MIPS_RS(inst)].d * cpu->gpr[MIPS_RT(inst)].d;
|
|
cpu->lo.d = tmp.d;
|
|
cpu->hi.d = tmp.d >> 32;
|
|
}
|
|
break;
|
|
case SPEC_DDIV: // DDIV
|
|
if(cpu->gpr[MIPS_RT(inst)].d == 0) {
|
|
break;
|
|
}
|
|
|
|
cpu->lo.sd = cpu->gpr[MIPS_RS(inst)].sd / cpu->gpr[MIPS_RT(inst)].sd;
|
|
cpu->hi.sd = cpu->gpr[MIPS_RS(inst)].sd % cpu->gpr[MIPS_RT(inst)].sd;
|
|
break;
|
|
|
|
case SPEC_DDIVU: // DDIVU
|
|
if(cpu->gpr[MIPS_RT(inst)].d == 0) {
|
|
break;
|
|
}
|
|
|
|
cpu->lo.d = cpu->gpr[MIPS_RS(inst)].d / cpu->gpr[MIPS_RT(inst)].d;
|
|
cpu->hi.d = cpu->gpr[MIPS_RS(inst)].d % cpu->gpr[MIPS_RT(inst)].d;
|
|
break;
|
|
case SPEC_ADD: // ADD
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] = cpu->gpr[MIPS_RS(inst)].sw[1] + cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
break;
|
|
case SPEC_ADDU: // ADDU
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RS(inst)].w[1] + cpu->gpr[MIPS_RT(inst)].w[1];
|
|
break;
|
|
case SPEC_SUB: // SUB
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] = cpu->gpr[MIPS_RS(inst)].sw[1] - cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
break;
|
|
case SPEC_SUBU: // SUBU
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] = cpu->gpr[MIPS_RS(inst)].sw[1] - cpu->gpr[MIPS_RT(inst)].sw[1];
|
|
break;
|
|
case SPEC_AND: // AND
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RS(inst)].w[1] & cpu->gpr[MIPS_RT(inst)].w[1];
|
|
break;
|
|
case SPEC_OR: // OR
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RS(inst)].w[1] | cpu->gpr[MIPS_RT(inst)].w[1];
|
|
break;
|
|
case SPEC_XOR: // XOR
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = cpu->gpr[MIPS_RS(inst)].w[1] ^ cpu->gpr[MIPS_RT(inst)].w[1];
|
|
break;
|
|
case SPEC_NOR: // NOR
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = ~(cpu->gpr[MIPS_RS(inst)].w[1] | cpu->gpr[MIPS_RT(inst)].w[1]);
|
|
break;
|
|
case SPEC_SLT: // SLT
|
|
cpu->gpr[MIPS_RD(inst)].sw[1] = !!(cpu->gpr[MIPS_RS(inst)].sw[1] < cpu->gpr[MIPS_RT(inst)].sw[1]);
|
|
break;
|
|
case SPEC_SLTU: // SLTU
|
|
cpu->gpr[MIPS_RD(inst)].w[1] = !!(cpu->gpr[MIPS_RS(inst)].w[1] < cpu->gpr[MIPS_RT(inst)].w[1]);
|
|
break;
|
|
case SPEC_DADD: // DADD
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RS(inst)].sd + cpu->gpr[MIPS_RT(inst)].sd;
|
|
break;
|
|
case SPEC_DADDU: // DADDU
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RS(inst)].d + cpu->gpr[MIPS_RT(inst)].d;
|
|
break;
|
|
case SPEC_DSUB: // DSUB
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RS(inst)].sd - cpu->gpr[MIPS_RT(inst)].sd;
|
|
break;
|
|
case SPEC_DSUBU: // DSUBU
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RS(inst)].sd - cpu->gpr[MIPS_RT(inst)].sd;
|
|
break;
|
|
case SPEC_TGE: // TGE
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= cpu->gpr[MIPS_RT(inst)].sw[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_TGEU: // TGEU
|
|
if(cpu->gpr[MIPS_RS(inst)].w[1] >= cpu->gpr[MIPS_RT(inst)].w[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_TLT: // TGE
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < cpu->gpr[MIPS_RT(inst)].sw[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_TLTU: // TGEU
|
|
if(cpu->gpr[MIPS_RS(inst)].w[1] < cpu->gpr[MIPS_RT(inst)].w[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_TEQ: // TEQ
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] == cpu->gpr[MIPS_RT(inst)].sw[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_TNE: // TNE
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] != cpu->gpr[MIPS_RT(inst)].sw[1]) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case SPEC_DSLL: // DSLL
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d << MIPS_SA(inst);
|
|
break;
|
|
case SPEC_DSRL: // DSRL
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d >> MIPS_SA(inst);
|
|
break;
|
|
case SPEC_DSRA: // DSRA
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RT(inst)].sd >> MIPS_SA(inst);
|
|
break;
|
|
case SPEC_DSLL32: // DSLL32
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d << (MIPS_SA(inst) + 32);
|
|
break;
|
|
case SPEC_DSRL32: // DSRL32
|
|
cpu->gpr[MIPS_RD(inst)].d = cpu->gpr[MIPS_RT(inst)].d >> (MIPS_SA(inst) + 32);
|
|
break;
|
|
case SPEC_DSRA32: // DSRA32
|
|
cpu->gpr[MIPS_RD(inst)].sd = cpu->gpr[MIPS_RT(inst)].sd >> (MIPS_SA(inst) + 32);
|
|
break;
|
|
|
|
}
|
|
break;
|
|
case OPC_REGIMM:
|
|
switch(REGIMM_SUB(inst)) {
|
|
case REGIMM_BLTZ: // BLTZ
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < 0) {
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
}
|
|
break;
|
|
case REGIMM_BGEZ: // BGEZ
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= 0) {
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
}
|
|
break;
|
|
case REGIMM_BLTZL: // BLTZL
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < 0) {
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case REGIMM_BGEZL: // BGEZL
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= 0) {
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case REGIMM_TGEI: // TGEI
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_TGEIU: // TGEIU
|
|
if(cpu->gpr[MIPS_RS(inst)].w[1] >= MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_TLTI: // TLTI
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_TLTIU: // TLTIU
|
|
if(cpu->gpr[MIPS_RS(inst)].w[1] < MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_TEQI: // TEQI
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] == MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_TNEI: // TNEI
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] != MIPS_IMM(inst) ) {
|
|
cpuException(cpu, 0xD, 0);
|
|
}
|
|
break;
|
|
case REGIMM_BLTZAL: // BLTZAL
|
|
cpu->gpr[0x1F].w[1] = cpu->pc + 4;
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < 0) {
|
|
cpu->unk_0x24 = cpu->unk_0x28 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
}
|
|
break;
|
|
case REGIMM_BGEZAL: // BGEZAL
|
|
cpu->gpr[0x1F].w[1] = cpu->pc + 4;
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= 0) {
|
|
cpu->unk_0x24 = cpu->unk_0x28 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
}
|
|
break;
|
|
case REGIMM_BLTZALL: // BLTZALL
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] < 0) {
|
|
cpu->gpr[0x1F].sw[1] = cpu->pc + 4;
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case REGIMM_BGEZALL: // BGEZALL
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] >= 0) {
|
|
cpu->gpr[0x1F].sw[1] = cpu->pc + 4;
|
|
cpu->unk_0x24 = cpu->pc + (MIPS_IMM(inst) * 4);
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case OPC_J: // J
|
|
{
|
|
cpu->unk_0x24 = (cpu->pc & 0xF0000000) | ((inst & 0x3FFFFFF) << 2);
|
|
if(cpu->unk_0x24 != cpu->pc - 4) {
|
|
break;
|
|
}
|
|
|
|
if(!checkRetrace()) {
|
|
return NULL;
|
|
}
|
|
}
|
|
break;
|
|
case OPC_JAL: //JAL
|
|
{
|
|
recomp_node_t *node;
|
|
|
|
cpu->gpr[0x1F].w[1] = cpu->pc + 4;
|
|
cpu->unk_0x24 = cpu->unk_0x28 = (cpu->pc & 0xF0000000) | ((inst & 0x3FFFFFF) << 2);
|
|
cpuFindFunction(cpu, cpu->unk_0x24, &node);
|
|
}
|
|
break;
|
|
case OPC_BEQ: // BEQ
|
|
if(cpu->gpr[MIPS_RS(inst)].sw[1] == cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
|
|
if(cpu->unk_0x24 != cpu->pc - 4) {
|
|
break;
|
|
}
|
|
|
|
if(!checkRetrace()) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
case OPC_BNE: // BNE
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] != cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
break;
|
|
case OPC_BLEZ: // BLEZ
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] <= 0) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
break;
|
|
case OPC_BGTZ: // BGTZ
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] > 0) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
break;
|
|
case OPC_ADDI: // ADDI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst) ;
|
|
break;
|
|
case OPC_ADDIU: // ADDIU
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst) ;
|
|
break;
|
|
case OPC_SLTI: // SLTI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = !!(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] < MIPS_IMM(inst) );
|
|
break;
|
|
case OPC_SLTIU: // SLTIU
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = !!(cpu->gpr[(inst >> 0x15) & 0x1F].w[1] < MIPS_IMM(inst) );
|
|
break;
|
|
case OPC_ANDI: // ANDI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] & (inst & 0xFFFF);
|
|
break;
|
|
case OPC_ORI: // ORI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] | (inst & 0xFFFF);
|
|
break;
|
|
case OPC_XORI: // XORI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] ^ (inst & 0xFFFF);
|
|
break;
|
|
case OPC_LUI: // LUI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = (inst & 0xFFFF) << 0x10;
|
|
|
|
break;
|
|
case OPC_CP0: // CP0
|
|
switch(inst & 0x3F) {
|
|
case 1: // TLBR
|
|
cpu->cp0[2].d = cpu->unk_0x248[cpu->cp0[0].w[1] & 0x3F].unk_0x00.d;
|
|
cpu->cp0[3].d = cpu->unk_0x248[cpu->cp0[0].w[1] & 0x3F].unk_0x08.d;
|
|
cpu->cp0[0xA].d = cpu->unk_0x248[cpu->cp0[0].w[1] & 0x3F].unk_0x10.d;
|
|
cpu->cp0[5].d = cpu->unk_0x248[cpu->cp0[0].w[1] & 0x3F].unk_0x18.d;
|
|
break;
|
|
case 2: // TLBWI
|
|
func_8000D6EC(cpu, cpu->cp0[0].w[1] & 0x3F);
|
|
break;
|
|
case 5: // TLBWR
|
|
{
|
|
for(i = 0; i < 0x30; i++) {
|
|
if(!(cpu->unk_0x248[i].unk_0x10.w[1] & 2)) {
|
|
val++;
|
|
}
|
|
}
|
|
|
|
cpu->cp0[1].sd = val;
|
|
func_8000D6EC(cpu, val);
|
|
}
|
|
break;
|
|
case 8: // TLBP
|
|
{
|
|
cpu->cp0[0].d |= 0x80000000;
|
|
|
|
for(i = 0; i < 0x30; i++) {
|
|
if(cpu->unk_0x248[i].unk_0x00.w[1] & 2) {
|
|
if(!(cpu->cp0[10].d ^ cpu->unk_0x248[i].unk_0x10.d)) {
|
|
cpu->cp0[0].d = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 24: // ERET
|
|
if(cpu->cp0[12].d & 4) {
|
|
cpu->pc = cpu->cp0[30].w[1];
|
|
cpu->cp0[12].d &= ~4;
|
|
} else {
|
|
cpu->pc = cpu->cp0[14].w[1];
|
|
cpu->cp0[12].d &= ~2;
|
|
}
|
|
cpu->unk_0x00 |= 0x24;
|
|
break;
|
|
case 0:
|
|
default:
|
|
switch((inst >> 0x15) & 0x1F) {
|
|
case 0: // MFC0
|
|
{
|
|
if(!func_8000E2B0(cpu, (inst >> 0xB) & 0x1F, &tmp.w[1])) {
|
|
break;
|
|
}
|
|
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = tmp.d & 0xFFFFFFFFUL;
|
|
}
|
|
break;
|
|
case 1: // DMFC0
|
|
{
|
|
if(!func_8000E2B0(cpu, (inst >> 0xB) & 0x1F, &tmp.w[0])) {
|
|
break;
|
|
}
|
|
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = tmp.d;
|
|
}
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 4: // MTC0
|
|
func_8000E0E8(cpu, (inst >> 0xB) & 0x1F, 0, cpu->gpr[(inst >> 0x10) & 0x1F].w[1]);
|
|
break;
|
|
case 5: // DMTC0
|
|
func_8000E0E8(cpu, (inst >> 0xB) & 0x1F, cpu->gpr[(inst >> 0x10) & 0x1F].w[0], cpu->gpr[(inst >> 0x10) & 0x1F].w[1]);
|
|
break;
|
|
case 6:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case OPC_CP1:
|
|
if(MIPS_FDT(inst) == 0) {
|
|
if(MIPS_FSUB(inst) >= 0x10) {
|
|
break;
|
|
}
|
|
|
|
switch(MIPS_FSUB(inst)) {
|
|
case MIPS_FSUB_MFC:
|
|
if(MIPS_FS(inst) & 1) {
|
|
cpu->gpr[MIPS_RT(inst)].w[1] = cpu->fpr[MIPS_FS(inst) - 1].w[0];
|
|
} else {
|
|
cpu->gpr[MIPS_RT(inst)].w[1] = cpu->fpr[MIPS_FS(inst)].w[1];
|
|
}
|
|
break;
|
|
case MIPS_FSUB_DMFC:
|
|
cpu->gpr[MIPS_RT(inst)].d = cpu->fpr[MIPS_FS(inst)].d;
|
|
break;
|
|
case MIPS_FSUB_CFC:
|
|
cpu->gpr[MIPS_RT(inst)].w[1] = cpu->fscr[MIPS_FS(inst)];
|
|
break;
|
|
case MIPS_FSUB_MTC:
|
|
if(MIPS_FS(inst) & 1) {
|
|
cpu->fpr[MIPS_FS(inst) - 1].d = cpu->fpr[MIPS_FS(inst) - 1].d & 0xFFFFFFFFUL;
|
|
cpu->fpr[MIPS_FS(inst) - 1].d |= ((u64)cpu->gpr[MIPS_RT(inst)].w[1] << 32);
|
|
|
|
} else {
|
|
cpu->fpr[MIPS_FS(inst)].w[1] = cpu->gpr[MIPS_RT(inst)].w[1];
|
|
}
|
|
break;
|
|
case MIPS_FSUB_DMTC:
|
|
cpu->fpr[MIPS_FS(inst)].d = cpu->gpr[MIPS_RT(inst)].d;
|
|
break;
|
|
case MIPS_FSUB_CTC:
|
|
cpu->fscr[MIPS_FS(inst)] = cpu->gpr[MIPS_RT(inst)].w[1];
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Condition Code
|
|
if(MIPS_FFMT(inst) == 8) {
|
|
switch((inst >> 0x10) & 0x1F) {
|
|
case 0: // BC1F
|
|
if(!(cpu->fscr[0x1F] & 0x800000)) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
break;
|
|
case 1: // BC1T
|
|
if(cpu->fscr[0x1F] & 0x800000) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
}
|
|
break;
|
|
case 2: // BC1FL
|
|
if(!(cpu->fscr[0x1F] & 0x800000)) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case 3: // BC1TL
|
|
if(cpu->fscr[0x1F] & 0x800000) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch(MIPS_FFMT(inst)) {
|
|
case MIPS_FMT_SINGLE:
|
|
switch(MIPS_FFUNC(inst)) {
|
|
case 0: // ADD.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1] + cpu->fpr[(inst >> 0x10) & 0x1F].f[1];
|
|
break;
|
|
case 1: // SUB.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1] - cpu->fpr[(inst >> 0x10) & 0x1F].f[1];
|
|
break;
|
|
case 2: // MUL.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1] * cpu->fpr[(inst >> 0x10) & 0x1F].f[1];
|
|
break;
|
|
case 3: // DIV.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1] / cpu->fpr[(inst >> 0x10) & 0x1F].f[1];
|
|
break;
|
|
case 4: // SQRT.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = sqrt(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 5: // ABS.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = __fabs(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 6: // MOV.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 7: // NEG.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = -cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 8: // ROUND.L.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = 0.5f + cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 9: // TRUNC.L.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 10: // CEIL.L.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 11: // FLOOR.L.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = floor(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 12: // ROUND.W.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = 0.5f + cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 13: // TRUNC.W.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 14: // CEIL.W.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 15: // FLOOR.W.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = floor(cpu->fpr[(inst >> 0xB) & 0x1F].f[1]);
|
|
break;
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 31:
|
|
break;
|
|
case 32: // CVT.S.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 33: // CVT.D.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 34:
|
|
case 35:
|
|
break;
|
|
case 37: // CVT.W.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 38: // CVT.L.S
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].f[1];
|
|
break;
|
|
case 39:
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
case 48:
|
|
break;
|
|
case 49: // C.F.S
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 50: // C.UN.S
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 51: // C.EQ.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] == cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 52: // C.UEQ.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] == cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 53: // C.OLT.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] < cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 54: // C.ULT.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] < cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 55: // C.OLE.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 56: // C.ULE.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 57: // C.SF.S
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 58: // C.NGLE.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 59: // C.SEQ.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] == cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 60: // C.NGL.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] == cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 61: // C.LT.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] < cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 62: // C.NGE.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] < cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 63: // C.LE.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 64: // C.NGT.S
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].f[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].f[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MIPS_FMT_DOUBLE:
|
|
switch(MIPS_FFUNC(inst)) {
|
|
case 0: // ADD.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd + cpu->fpr[(inst >> 0x10) & 0x1F].fd;
|
|
break;
|
|
case 1: // SUB.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd - cpu->fpr[(inst >> 0x10) & 0x1F].fd;
|
|
break;
|
|
case 3: // MUL.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd * cpu->fpr[(inst >> 0x10) & 0x1F].fd;
|
|
break;
|
|
case 4: // DIV.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd / cpu->fpr[(inst >> 0x10) & 0x1F].fd;
|
|
break;
|
|
case 5: // SQRT.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = sqrt(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 6: // ABS.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = __fabs(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 7: // MOV.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 8: // NEG.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = -cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 9: // ROUND.L.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = 0.5 + cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 10: // TRUNC.L.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 11: // CEIL.L.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 12: // FLOOR.L.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = floor(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 13: // ROUND.W.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = 0.5 + cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 14: // TRUNC.W.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 15: // CEIL.W.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 16: // FLOOR.W.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = floor(cpu->fpr[(inst >> 0xB) & 0x1F].fd);
|
|
break;
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
break;
|
|
case 33: // CVT.S.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 34: // CVT.D.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 35:
|
|
case 36:
|
|
break;
|
|
case 37: // CVT.W.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 38: // CVT.L.D
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].fd;
|
|
break;
|
|
case 39:
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
case 48:
|
|
break;
|
|
case 49: // C.F.D
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 50: // C.UN.D
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 51: // C.EQ.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd == cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 52: // C.UEQ.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd == cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 53: // C.OLT.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd < cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 54: // C.ULT.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd < cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 55: // C.OLE.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd <= cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 56: // C.ULE.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd <= cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 57: // C.SF.D
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 58: // C.NGLE.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd <= cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 59: // C.SEQ.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd == cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 60: // C.NGL.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd == cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 61: // C.LT.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd < cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 62: // C.NGE.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd < cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 63: // C.LE.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd <= cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 64: // C.NGT.D
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].fd <= cpu->fpr[(inst >> 0x10) & 0x1F].fd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MIPS_FMT_WORD:
|
|
switch(MIPS_FFUNC(inst)) {
|
|
case 0: // ADD.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] + cpu->fpr[(inst >> 0x10) & 0x1F].sw[1];
|
|
break;
|
|
case 1: // SUB.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] - cpu->fpr[(inst >> 0x10) & 0x1F].sw[1];
|
|
break;
|
|
case 2: // MUL.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] * cpu->fpr[(inst >> 0x10) & 0x1F].sw[1];
|
|
break;
|
|
case 3: // DIV.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] / cpu->fpr[(inst >> 0x10) & 0x1F].sw[1];
|
|
break;
|
|
case 4: // SQRT.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = sqrt(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 5: // ABS.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = __fabs(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 6: // MOV.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 7: // NEG.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = -cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 8: // ROUND.L.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 9: // TRUNC.L.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 10: // CEIL.L.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 11: // FLOOR.L.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = floor(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 12: // ROUND.W.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 13: // TRUNC.W.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 14: // CEIL.W.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 15: // FLOOR.W.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = floor(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1]);
|
|
break;
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 31:
|
|
break;
|
|
case 32: // CVT.S.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 33: // CVT.D.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 34:
|
|
case 35:
|
|
break;
|
|
case 37: // CVT.W.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 38: // CVT.L.W
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sw[1];
|
|
break;
|
|
case 39:
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
case 48:
|
|
break;
|
|
case 49: // C.F.W
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 50: // C.UN.W
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 51: // C.EQ.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] == cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 52: // C.UEQ.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] == cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 53: // C.OLT.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] < cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 54: // C.ULT.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] < cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 55: // C.OLE.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 56: // C.ULE.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 57: // C.SF.W
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 58: // C.NGLE.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 59: // C.SEQ.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] == cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 60: // C.NGL.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] == cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 61: // C.LT.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] < cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 62: // C.NGE.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] < cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 63: // C.LE.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 64: // C.NGT.W
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sw[1] <= cpu->fpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MIPS_FMT_DBLWORD:
|
|
switch(MIPS_FFUNC(inst)) {
|
|
case 0: // ADD.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd + cpu->fpr[(inst >> 0x10) & 0x1F].sd;
|
|
break;
|
|
case 1: // SUB.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd - cpu->fpr[(inst >> 0x10) & 0x1F].sd;
|
|
break;
|
|
case 2: // MUL.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd * cpu->fpr[(inst >> 0x10) & 0x1F].sd;
|
|
break;
|
|
case 3: // DIV.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd / cpu->fpr[(inst >> 0x10) & 0x1F].sd;
|
|
break;
|
|
case 4: // SQRT.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = sqrt(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 5: // ABS.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = __fabs(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 6: // MOV.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 7: // NEG.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = -cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 8: // ROUND.L.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 9: // TRUNC.L.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 10: // CEIL.L.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 11: // FLOOR.L.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = floor(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 12: // ROUND.W.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 13: // TRUNC.W.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 14: // CEIL.W.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = ceil(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 15: // FLOOR.W.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = floor(cpu->fpr[(inst >> 0xB) & 0x1F].sd);
|
|
break;
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 31:
|
|
break;
|
|
case 32: // CVT.S.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].f[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 33: // CVT.D.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].fd = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 34:
|
|
case 35:
|
|
break;
|
|
case 37: // CVT.W.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sw[1] = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 38: // CVT.L.L
|
|
cpu->fpr[(inst >> 6) & 0x1F].sd = cpu->fpr[(inst >> 0xB) & 0x1F].sd;
|
|
break;
|
|
case 39:
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
case 48:
|
|
break;
|
|
case 49: // C.F.L
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 50: // C.UN.L
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 51: // C.EQ.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd == cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 52: // C.UEQ.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd == cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 53: // C.OLT.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd < cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 54: // C.ULT.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd < cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 55: // C.OLE.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd <= cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 56: // C.ULE.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd <= cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 57: // C.SF.L
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
break;
|
|
case 58: // C.NGLE.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd <= cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 59: // C.SEQ.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd == cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 60: // C.NGL.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd == cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 61: // C.LT.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd < cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 62: // C.NGE.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd < cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 63: // C.LE.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd <= cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
case 64: // C.NGT.L
|
|
if(cpu->fpr[(inst >> 0xB) & 0x1F].sd <= cpu->fpr[(inst >> 0x10) & 0x1F].sd) {
|
|
cpu->fscr[0x1F] |= 0x00800000;
|
|
} else {
|
|
cpu->fscr[0x1F] &= ~0x00800000;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 20: // BEQL
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] == cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case 21: // BNEL
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] != cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case 22: // BLEZL
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] <= 0) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case 23: // BGTZL
|
|
if(cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] > 0) {
|
|
cpu->unk_0x24 = cpu->pc + MIPS_IMM(inst) * 4;
|
|
} else {
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc += 4;
|
|
}
|
|
break;
|
|
case 24: // DADDI
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sd = cpu->gpr[(inst >> 0x15) & 0x1F].sd + MIPS_IMM(inst) ;
|
|
break;
|
|
case 25: // DADDIU
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = cpu->gpr[(inst >> 0x15) & 0x1F].sd + MIPS_IMM(inst) ;
|
|
break;
|
|
case 31: // precompiled function.
|
|
if(!func_8005D614(gSystem->unk_0x0058, cpu, MIPS_IMM(inst) )) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
case 26: // LDL
|
|
{
|
|
s32 sh = 0x38;
|
|
u8 buf;
|
|
ea = MIPS_IMM(inst) + cpu->gpr[MIPS_RS(inst)].sw[1];
|
|
|
|
do {
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lb(dev->unk_4, ea + dev->unk_8, (s8*)&buf)) {
|
|
tmp.d = (u64)buf << sh;
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = tmp.d | (cpu->gpr[(inst >> 0x10) & 0x1F].d & ~((u64)0xFF << sh));
|
|
}
|
|
|
|
ea++;
|
|
sh -= 8;
|
|
|
|
} while((ea - 1) & 7);
|
|
}
|
|
break;
|
|
case 27: // LDR
|
|
{
|
|
s32 sh = 0;
|
|
u8 buf;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst) ;
|
|
|
|
do {
|
|
if(devs[dev_idx[ea >> 0x10]]->lb(devs[dev_idx[ea >> 0x10]]->unk_4, ea + devs[dev_idx[ea >> 0x10]]->unk_8, (s8*)&buf)) {
|
|
tmp.d = (u64)buf << sh;
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = tmp.d | (cpu->gpr[(inst >> 0x10) & 0x1F].d & ~((u64)0xFF << sh));
|
|
}
|
|
ea--;
|
|
sh += 8;
|
|
} while((ea + 1) & 7);
|
|
}
|
|
break;
|
|
case 39: // LWU
|
|
{
|
|
u32 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lw(dev->unk_4, ea + dev->unk_8, (s32*)&dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 32: // LB
|
|
{
|
|
s8 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lb(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 33: // LH
|
|
{
|
|
s16 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lh(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 34: // LWL
|
|
{
|
|
u8 buf;
|
|
s32 sh = 0x18;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
if(dev->lb(dev->unk_4, ea + dev->unk_8, (s8*)&buf)) {
|
|
tmp.w[1] = (u32)buf << sh;
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = tmp.w[1] | (cpu->gpr[(inst >> 0x10) & 0x1F].w[1] & ~((u32)0xFF << sh));
|
|
}
|
|
ea++;
|
|
sh -= 8;
|
|
} while((ea - 1) & 3);
|
|
}
|
|
break;
|
|
case 35: // LW
|
|
{
|
|
s32 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lw(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 36: // LBU
|
|
{
|
|
u8 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lb(dev->unk_4, ea + dev->unk_8, (s8*)&dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 37: // LHU
|
|
{
|
|
u16 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
|
|
if(func_80052D68(gSystem->frame, &dst, ea)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = dst;
|
|
break;
|
|
}
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lh(dev->unk_4, ea + dev->unk_8, (s16*)&dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 38: // LWR
|
|
{
|
|
u8 buf;
|
|
s32 sh = 0;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
if(dev->lb(dev->unk_4, ea + dev->unk_8, (s8*)&buf)) {
|
|
tmp.w[1] = (u32)buf << sh;
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].w[1] = tmp.w[1] | (cpu->gpr[(inst >> 0x10) & 0x1F].w[1] & ~((u32)0xFF << sh));
|
|
}
|
|
ea--;
|
|
sh += 8;
|
|
} while((ea + 1) & 3);
|
|
}
|
|
break;
|
|
case 40: // SB
|
|
{
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
dev->sb(dev->unk_4, ea + dev->unk_8, (s8*)&cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]);
|
|
}
|
|
break;
|
|
case 41: // SH
|
|
{
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
dev->sh(dev->unk_4, ea + dev->unk_8, (s16*)&cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]);
|
|
}
|
|
break;
|
|
case 42: // SWL
|
|
{
|
|
s8 buf;
|
|
s32 sh = 0x18;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
buf = cpu->gpr[(inst >> 0x10) & 0x1F].w[1] >> sh;
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
dev->sb(dev->unk_4, ea + dev->unk_8, &buf);
|
|
ea++;
|
|
sh -= 8;
|
|
} while((ea - 1) & 3);
|
|
}
|
|
break;
|
|
case 43: // SW
|
|
{
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
dev->sw(dev->unk_4, ea + dev->unk_8, &cpu->gpr[(inst >> 0x10) & 0x1F].sw[1]);
|
|
}
|
|
break;
|
|
case 44: // SDL
|
|
{
|
|
s8 buf;
|
|
s32 sh = 0x38;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
buf = cpu->gpr[(inst >> 0x10) & 0x1F].d >> sh;
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
dev->sb(dev->unk_4, ea + dev->unk_8, &buf);
|
|
ea++;
|
|
sh -= 8;
|
|
} while((ea - 1) & 7);
|
|
}
|
|
break;
|
|
case 45: // SDR
|
|
{
|
|
s8 buf;
|
|
s32 sh = 0;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
buf = cpu->gpr[(inst >> 0x10) & 0x1F].d >> sh;
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
dev->sb(dev->unk_4, ea + dev->unk_8, &buf);
|
|
ea--;
|
|
sh += 8;
|
|
} while((ea + 1) & 7);
|
|
}
|
|
break;
|
|
break;
|
|
case 46: // SWR
|
|
{
|
|
s8 buf;
|
|
s32 sh = 0;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].sw[1] + MIPS_IMM(inst);
|
|
|
|
do {
|
|
buf = cpu->gpr[(inst >> 0x10) & 0x1F].w[1] >> sh;
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
dev->sb(dev->unk_4, ea + dev->unk_8, &buf);
|
|
ea--;
|
|
sh += 8;
|
|
} while((ea + 1) & 3);
|
|
}
|
|
break;
|
|
case 48: // LL
|
|
{
|
|
s32 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lw(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 49: // LWC1
|
|
{
|
|
s32 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->lw(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
if((inst >> 0x10) & 1) {
|
|
cpu->fpr[MIPS_FS(inst) - 1].d = cpu->fpr[MIPS_FS(inst) - 1].d & 0xFFFFFFFFUL;
|
|
cpu->fpr[MIPS_FS(inst) - 1].d |= ((u64)cpu->gpr[MIPS_RT(inst)].w[1] << 32);
|
|
} else {
|
|
cpu->fpr[(inst >> 0x10) & 0x1F].sw[1] = dst;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 52: // LLD
|
|
{
|
|
s64 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->ld(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 53: // LDC1
|
|
{
|
|
s64 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->ld(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->fpr[(inst >> 0x10) & 0x1F].d = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 55: // LD
|
|
{
|
|
s64 dst;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if(dev->ld(dev->unk_4, ea + dev->unk_8, &dst)) {
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].d = dst;
|
|
}
|
|
}
|
|
break;
|
|
case 56: // SC
|
|
{
|
|
ea = cpu->gpr[(inst >> 0x10) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = !!dev->sw(dev->unk_4, ea + dev->unk_8, &cpu->gpr[(inst >> 0x15) & 0x1F].sw[1]);
|
|
}
|
|
break;
|
|
case 57: // SWC1
|
|
{
|
|
u32 buf;
|
|
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
if((inst >> 0x10) & 1) {
|
|
buf = cpu->fpr[(inst >> 0x10) & 0x1F].w[0];
|
|
} else {
|
|
buf = cpu->fpr[(inst >> 0x10) & 0x1F].w[1];
|
|
}
|
|
|
|
dev->sw(dev->unk_4, ea + dev->unk_8, (s32*)&buf);
|
|
}
|
|
break;
|
|
case 60: // SCD
|
|
{
|
|
ea = cpu->gpr[(inst >> 0x10) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
cpu->gpr[(inst >> 0x10) & 0x1F].sw[1] = !!dev->sd(dev->unk_4, ea + dev->unk_8, &cpu->gpr[(inst >> 0x15) & 0x1F].sd);
|
|
}
|
|
break;
|
|
case 61: // SDC1
|
|
{
|
|
u64 buf = cpu->fpr[(inst >> 0x10) & 0x1F].d;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
dev->sd(dev->unk_4, ea + dev->unk_8, (s64*)&buf);
|
|
}
|
|
break;
|
|
case 63:
|
|
{
|
|
u64 buf = cpu->gpr[(inst >> 0x10) & 0x1F].d;
|
|
ea = cpu->gpr[(inst >> 0x15) & 0x1F].w[1] + MIPS_IMM(inst);
|
|
dev = devs[dev_idx[ea >> 0x10]];
|
|
|
|
dev->sd(dev->unk_4, ea + dev->unk_8, (s64*)&buf);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if(!cpuExecuteUpdate(cpu, &ret, tick + 1)) {
|
|
return NULL;
|
|
}
|
|
|
|
if(save_ra) {
|
|
cpu->gpr[0x1F].d = prev_ra;
|
|
}
|
|
|
|
cpu->unk_0x24 = -1;
|
|
cpu->unk_0x38 = OSGetTick();
|
|
|
|
return ret;
|
|
}
|
|
|
|
//#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteOpcode.s")
|
|
|
|
s32 videoForceRetrace(void *);
|
|
s32 cpuExecuteUpdate(cpu_class_t *cpu, u32 **, u32);
|
|
|
|
#ifdef NON_MATCHING
|
|
void *cpuExecuteIdle(cpu_class_t *cpu, u32 r4, u32 addr, u32 *ret) {
|
|
rom_class_t *rom;
|
|
u32 tick;
|
|
|
|
rom = gSystem->rom;
|
|
tick = OSGetTick();
|
|
|
|
if(cpu->unk_0x24 != 0) {
|
|
cpu->unk_0x00 |= 8;
|
|
} else {
|
|
cpu->unk_0x00 &= ~8;
|
|
}
|
|
|
|
cpu->pc = addr;
|
|
cpu->unk_0x00 |= 0x80;
|
|
|
|
if(!(cpu->unk_0x00 & 0x40) && !rom->unk_19A34) {
|
|
videoForceRetrace(gSystem->video);
|
|
}
|
|
|
|
if(!cpuExecuteUpdate(cpu, &ret, tick)) {
|
|
return NULL;
|
|
}
|
|
|
|
cpu->unk_0x38 = OSGetTick();
|
|
|
|
return ret;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteIdle.s")
|
|
#endif
|
|
|
|
void *cpuExecuteJump(cpu_class_t *cpu, u32 r4, u32 addr, u32 *ret) {
|
|
u32 tick = OSGetTick();
|
|
|
|
if(cpu->unk_0x24 != 0) {
|
|
cpu->unk_0x00 |= 8;
|
|
} else {
|
|
cpu->unk_0x00 &= ~8;
|
|
}
|
|
|
|
cpu->pc = addr;
|
|
cpu->unk_0x00 |= 4;
|
|
if(!cpuExecuteUpdate(cpu, &ret, tick)) {
|
|
return NULL;
|
|
}
|
|
|
|
cpu->unk_0x38 = OSGetTick();
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef NON_MATCHING
|
|
inline void tf(cpu_class_t *cpu, s32 addr, u32 *ret) {
|
|
s32 i;
|
|
recomp_node_t *node;
|
|
unk_node_0x18 *unk_0x18;
|
|
u32 *ret_p = ret - 1;
|
|
|
|
cpuFindFunction(cpu, cpu->unk_0x30 - 8, &node);
|
|
|
|
unk_0x18 = node->unk_0x18;
|
|
for(i = 0; i < node->unk_0x1C; unk_0x18++, i++) {
|
|
if(addr == unk_0x18->unk_0x00) {
|
|
if(unk_0x18->unk_0x04 == NULL) {
|
|
node->unk_0x18[i].unk_0x04 = ret_p;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void *cpuExecuteCall(cpu_class_t *cpu, u32 arg1, u32 addr, u32 *ret) {
|
|
u32 tick = OSGetTick();
|
|
recomp_node_t *node;
|
|
s32 i;
|
|
s32 flg;
|
|
u32 *ret_p;
|
|
u32 *ret_p2;
|
|
|
|
if(cpu->unk_0x24 != 0) {
|
|
cpu->unk_0x00 |= 8;
|
|
} else {
|
|
cpu->unk_0x00 &= ~8;
|
|
}
|
|
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->pc = addr;
|
|
cpu->gpr[0x1F].w[1] = (u32)ret;
|
|
cpu->unk_0x34++;
|
|
|
|
tf(cpu, addr, ret);
|
|
|
|
flg = ((lbl_80170B68[31] >> 8) & 1) != 0;
|
|
ret_p = ret - (!!flg + 3);
|
|
if(flg) {
|
|
ret_p[0] = ((u32)ret >> 0x10) | 0x3CA00000;
|
|
ret_p[1] = ((u32)ret & 0xFFFF) | 0x60A50000;
|
|
DCStoreRange(ret_p, 8);
|
|
ICInvalidateRange(ret_p, 8);
|
|
} else {
|
|
u32 rs = lbl_80170B68[31] << 0x15;
|
|
u32 ra = lbl_80170B68[31] << 0x10;
|
|
ret_p[0] = 0x3C000000 | rs | ((u32)ret >> 0x10);
|
|
ret_p[1] = 0x60000000 | rs | ra | ((u32)ret & 0xFFFF);
|
|
DCStoreRange(ret_p, 8);
|
|
ICInvalidateRange(ret_p, 8);
|
|
}
|
|
|
|
if(!cpuExecuteUpdate(cpu, &ret, tick)) {
|
|
return NULL;
|
|
}
|
|
|
|
if(flg) {
|
|
ret_p[3] = 0x48000000 | (((u32)ret - (u32)&ret_p[3]) & 0x3FFFFFC);
|
|
DCStoreRange(ret_p, 16);
|
|
ICInvalidateRange(ret_p, 16);
|
|
} else {
|
|
ret_p[2] = 0x48000000 | (((u32)ret - (u32)&ret_p[3]) & 0x3FFFFFC);
|
|
DCStoreRange(ret_p, 12);
|
|
ICInvalidateRange(ret_p, 12);
|
|
}
|
|
|
|
cpu->unk_0x38 = OSGetTick();
|
|
|
|
return ret;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteCall.s")
|
|
#endif
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteLoadStore.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecuteLoadStoreF.s")
|
|
|
|
int cpuMakeLink(cpu_class_t *cpu, u32 **link_code, void *handler) {
|
|
u32 *code;
|
|
s32 i;
|
|
u32 paddr;
|
|
s32 cnt = sizeof(lbl_80170B68) / sizeof(*lbl_80170B68);
|
|
|
|
if(!xlHeapTake((void**)&code, 0x30000200)) {
|
|
return 0;
|
|
}
|
|
|
|
*link_code = code;
|
|
*code++ = 0x7CC802A6; // mflr r6
|
|
|
|
for(i = 1; i < 32; i++) {
|
|
if(!(lbl_80170B68[i] & 0x100)) {
|
|
*code++ = (((u32)&cpu->gpr[i] - (u32)cpu) + 4) |
|
|
(lbl_80170B68[i] << 0x15) |
|
|
0x90030000; // stw rx, off(r3)
|
|
}
|
|
}
|
|
|
|
*code++ = (((u32)handler - (u32)code) & 0x3FFFFFC) |
|
|
0x48000001; // bl handler
|
|
*code++ = 0x7C6803A6; // mtlr r3
|
|
*code++ = ((u32)cpu >> 0x10) |
|
|
0x3C600000; // lis r3, cpu@h
|
|
*code++ = ((u32)cpu & 0xFFFF) |
|
|
0x60630000; // ori r3, r3, cpu@l
|
|
*code++ = (((s32)&cpu->unk_0x34 - (s32)cpu)) +
|
|
0x80830000; // lwz r4, 0x34(r3)
|
|
|
|
paddr = (u32)gSystem->ram->dram - 0x80000000;
|
|
*code++ = (paddr >> 0x10) |
|
|
0x3D000000; // lui r8, dram@h
|
|
if(cpu->unk_0x12224 & 0x100) {
|
|
*code++ = 0x3D20DFFF; // lis r9, 0xDFFF
|
|
*code++ = (paddr & 0xFFFF) |
|
|
0x61080000; // ori r8, r8, dram@l
|
|
*code++ = 0x6129FFFF; // ori r9, r9, 0xFFFF
|
|
} else if(cpu->unk_0x12224 & 1) {
|
|
*code++ = (((u32)cpu->mem_hi_map - (u32)cpu)) +
|
|
0x39230000; // addi r9, r3, 0xF60
|
|
*code++ = (paddr & 0xFFFF) |
|
|
0x61080000; // ori r8, r8, dram@l
|
|
}
|
|
|
|
*code++ = (lbl_80170B68[0] << 0x15) |
|
|
0x38000000; // li r10, 0
|
|
|
|
for(i = 1; i < 32; i++) {
|
|
if(!(lbl_80170B68[i] & 0x100)) {
|
|
*code++ = (((u32)&cpu->gpr[i] - (u32)cpu) + 4) |
|
|
(lbl_80170B68[i] << 0x15) |
|
|
0x80030000; // lwz rx, off(r3)
|
|
}
|
|
}
|
|
|
|
*code++ = 0x4E800020; // blr
|
|
|
|
DCStoreRange(*link_code, 0x200);
|
|
ICInvalidateRange(*link_code, 0x200);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuExecute.s")
|
|
|
|
int cpuMapObject(cpu_class_t *cpu, void *dev, u32 address_start, u32 address_end, u32 param_5){
|
|
u32 size = address_end - address_start + 1;
|
|
u32 dev_idx;
|
|
|
|
if(address_start == 0 && address_end == 0xFFFFFFFF) {
|
|
if(!cpuMakeDevice(cpu, &dev_idx, dev, 0, 0, size, param_5)) {
|
|
return 0;
|
|
}
|
|
|
|
cpu->unk_0x1C = dev_idx;
|
|
} else {
|
|
if(!cpuMakeDevice(cpu, &dev_idx, dev, address_start | 0x80000000, address_start, size, param_5)) {
|
|
return 0;
|
|
}
|
|
|
|
if(!cpuMakeDevice(cpu, &dev_idx, dev, address_start | 0xA0000000, address_start, size, param_5)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8003C708.s")
|
|
|
|
s32 cpuSetGetBlock(cpu_class_t* cpu, cpu_dev_t* dev, void* arg2) {
|
|
dev->unk_0x2C = arg2;
|
|
|
|
return 1;
|
|
}
|
|
|
|
s32 cpuSetDeviceGet(cpu_class_t* cpu, cpu_dev_t* dev, lb_func_t lb, lh_func_t lh, lw_func_t lw, ld_func_t ld) {
|
|
dev->lb = lb;
|
|
dev->lh = lh;
|
|
dev->lw = lw;
|
|
dev->ld = ld;
|
|
|
|
return 1;
|
|
}
|
|
|
|
s32 cpuSetDevicePut(cpu_class_t* cpu, cpu_dev_t* dev, sb_func_t sb, sh_func_t sh, sw_func_t sw, sd_func_t sd) {
|
|
dev->sb = sb;
|
|
dev->sh = sh;
|
|
dev->sw = sw;
|
|
dev->sd = sd;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int func_8003C7E0(cpu_class_t *cpu, u32 addr, u32 repl, s32 end) {
|
|
int i;
|
|
|
|
for(i = 0; i < cpu->hack_cnt; i++) {
|
|
if(addr == cpu->hacks[i].addr) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
cpu->hacks[i].addr = addr;
|
|
cpu->hacks[i].expected = repl;
|
|
cpu->hacks[i].replacement = end;
|
|
cpu->hack_cnt++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#ifdef NON_MATCHING
|
|
// Matches except first loop is unrolled twice, and double constant.
|
|
inline s32 clearblk(u32 *blk, s32 cnt) {
|
|
s32 i;
|
|
for(i = 0; i < cnt; i++) {
|
|
blk[i] = 0;
|
|
}
|
|
}
|
|
|
|
int cpuReset(cpu_class_t *cpu) {
|
|
int i;
|
|
cpu->unk_0x04 = 0;
|
|
cpu->hack_cnt = 0;
|
|
cpu->unk_0x00 = 0x40;
|
|
cpu->execute_opcode = NULL;
|
|
|
|
for(i = 0; i < 0x30; i++) {
|
|
cpu->unk_0x248[i].unk_0x00.d = 0;
|
|
cpu->unk_0x248[i].unk_0x08.d = 0;
|
|
cpu->unk_0x248[i].unk_0x10.d = 0;
|
|
cpu->unk_0x248[i].unk_0x18.d = 0;
|
|
cpu->unk_0x248[i].unk_0x20.d = -1;
|
|
}
|
|
|
|
cpu->lo.d = 0;
|
|
cpu->hi.d = 0;
|
|
cpu->pc = 0x80000400;
|
|
cpu->unk_0x24 = -1;
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
cpu->gpr[i].d = 0;
|
|
}
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
cpu->fpr[i].fd = 0.0;
|
|
}
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
cpu->fscr[i] = 0;
|
|
}
|
|
|
|
cpu->gpr[0x14].d = 1;
|
|
cpu->gpr[0x16].d = 0x3F;
|
|
cpu->gpr[0x1D].d = 0xA4001FF0;
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
cpu->cp0[i].d = 0;
|
|
}
|
|
|
|
cpu->cp0[0xF].d = 0xB00;
|
|
cpu->cp0[0x9].d = 0x10000000;
|
|
|
|
func_8000E054(cpu, 0x20010000, 0, 0x2000FF01, 1);
|
|
|
|
cpu->cp0[0x10].d = 0x6E463;
|
|
cpu->unk_0x18 = 0;
|
|
|
|
if(func_8000CB1C(cpu)) {
|
|
cpu->unk_0x00 |= 0x10;
|
|
}
|
|
|
|
|
|
clearblk(cpu->sm_blk_status, SM_BLK_CNT);
|
|
|
|
if(cpu->sm_blk_code == NULL && !xlHeapTake(&cpu->sm_blk_code, 0x30300000)) {
|
|
return 0;
|
|
}
|
|
|
|
clearblk(cpu->lg_blk_status, LG_BLK_CNT);
|
|
|
|
if(cpu->lg_blk_code == NULL && !xlHeapTake(&cpu->lg_blk_code, 0x30104000)) {
|
|
return 0;
|
|
}
|
|
|
|
clearblk(cpu->tree_blk_status, TREE_BLK_CNT);
|
|
|
|
if(cpu->recomp_tree != NULL) {
|
|
treeKill(cpu);
|
|
}
|
|
|
|
cpu->unk_0x12224 = 1;
|
|
cpu->unk_0x12228 = 0;
|
|
cpu->unk_0x1222C = 0;
|
|
cpu->unk_0x12230 = 0;
|
|
cpu->unk_0x12234 = 0;
|
|
cpu->unk_0x12238 = 0;
|
|
cpu->unk_0x1223C = 0;
|
|
cpu->unk_0x12240 = 0;
|
|
cpu->unk_0x12244 = 0;
|
|
cpu->unk_0x12248 = 0;
|
|
cpu->unk_0x1224C = 0;
|
|
cpu->unk_0x12250 = 0;
|
|
cpu->unk_0x12254 = 0;
|
|
cpu->unk_0x12258 = 0;
|
|
cpu->unk_0x1225C = 0;
|
|
cpu->unk_0x12260 = 0;
|
|
cpu->unk_0x12264 = 0;
|
|
cpu->unk_0x12268 = 0;
|
|
cpu->unk_0x1226C = 0;
|
|
|
|
return 1;
|
|
}
|
|
#else
|
|
int cpuReset(cpu_class_t *cpu);
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuReset.s")
|
|
#endif
|
|
|
|
int cpuGetXPC(cpu_class_t *cpu, u64 *param_2, u64 *param_3, u64 *param_4) {
|
|
if(!xlObjectTest(cpu, &lbl_80171F38)) {
|
|
return 0;
|
|
}
|
|
|
|
if(param_2 != NULL) {
|
|
*param_2 = cpu->pc;
|
|
}
|
|
|
|
if(param_3 != NULL) {
|
|
*param_3 = cpu->lo.d;
|
|
}
|
|
|
|
if(param_4 != NULL) {
|
|
*param_4 = cpu->hi.d;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int cpuSetXPC(cpu_class_t *cpu, u32 r4, u64 pc, u64 lo, u64 hi) {
|
|
if(!xlObjectTest(cpu, &lbl_80171F38)) {
|
|
return 0;
|
|
}
|
|
|
|
cpu->pc = pc;
|
|
cpu->unk_0x00 |= 4;
|
|
cpu->lo.d = lo;
|
|
cpu->hi.d = hi;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuEvent.s")
|
|
|
|
int func_8003D344(cpu_class_t *cpu, u32 *buffer, u32 addr) {
|
|
if(addr >= 0x80000000 && addr < 0xC0000000) {
|
|
*buffer = addr & 0x7FFFFF;
|
|
} else {
|
|
if(cpu->devices[cpu->mem_hi_map[addr >> 0x10]]->unk_0 & 0x100) {
|
|
*buffer = addr + cpu->devices[cpu->mem_hi_map[addr >> 0x10]]->unk_8 & 0x7FFFFF;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int cpuGetAddressBuffer(cpu_class_t *cpu, void **buffer, u32 addr) {
|
|
cpu_dev_t *dev = cpu->devices[cpu->mem_hi_map[addr >> 0x10]];
|
|
|
|
if(dev->unk_4 == gSystem->ram) {
|
|
if(!ramGetBuffer((ram_class_t*)dev->unk_4, buffer, addr + dev->unk_8, NULL)) {
|
|
return 0;
|
|
}
|
|
} else if(dev->unk_4 == gSystem->rom) {
|
|
if(!romGetBuffer(dev->unk_4, buffer, addr + dev->unk_8, NULL)) {
|
|
return 0;
|
|
}
|
|
} else if(dev->unk_4 == gSystem->rsp) {
|
|
if(!rspGetBuffer(dev->unk_4, buffer, addr + dev->unk_8, NULL)) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8003D47C.s")
|
|
|
|
int cpuInvalidateCache(cpu_class_t *cpu, u32 param_2, s32 param_3) {
|
|
if((param_2 & 0xF0000000) == 0xA0000000) {
|
|
return 1;
|
|
}
|
|
|
|
if(!cpuFreeCachedAddress(cpu, param_2, param_3)) {
|
|
return 0;
|
|
}
|
|
|
|
func_8003E604(cpu, param_2, param_3);
|
|
return 1;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuGetFunctionChecksum.s")
|
|
|
|
#ifdef NON_MATCHING
|
|
int cpuHeapTake(char **code, cpu_class_t *cpu, recomp_node_t *func, int size) {
|
|
s32 smblk_needed = (size + (0x200 - 1)) / 0x200;
|
|
s32 lgblk_needed = (size + (0xA00 - 1)) / 0xA00;
|
|
int type_swapped = 0;
|
|
int chunk_found = 0;
|
|
int blk_cnt;
|
|
u32 *blks;
|
|
s32 blks_needed;
|
|
int i;
|
|
int j;
|
|
|
|
while(!type_swapped) {
|
|
if(func->alloc_type == -1) {
|
|
if(size > 0x3200) {
|
|
func->alloc_type = 2;
|
|
} else {
|
|
func->alloc_type = 1;
|
|
}
|
|
} else if(func->alloc_type == 1) {
|
|
func->alloc_type = 2;
|
|
type_swapped = 1;
|
|
} else if(func->alloc_type == 2) {
|
|
func->alloc_type = 1;
|
|
type_swapped = 1;
|
|
}
|
|
|
|
if(func->alloc_type == 1) {
|
|
func->alloc_type = 1;
|
|
blk_cnt = sizeof(cpu->sm_blk_status) / sizeof(*cpu->sm_blk_status);
|
|
blks = cpu->sm_blk_status;
|
|
blks_needed = smblk_needed;
|
|
if(type_swapped && smblk_needed >= 32) {
|
|
func->alloc_type = 3;
|
|
func->unk_0x34 = 0xFFFFFFFF;
|
|
return !!xlHeapTake((void**)code, size);
|
|
}
|
|
} else if(func->alloc_type == 2) {
|
|
func->alloc_type = 2;
|
|
blk_cnt = sizeof(cpu->lg_blk_status) / sizeof(*cpu->lg_blk_status);
|
|
blks = cpu->lg_blk_status;
|
|
blks_needed = lgblk_needed;
|
|
}
|
|
|
|
if(blks_needed >= 32) {
|
|
func->alloc_type = 3;
|
|
func->unk_0x34 = 0xFFFFFFFF;
|
|
return !!xlHeapTake((void**)code, size);
|
|
}
|
|
|
|
for(i = 0; i != blk_cnt; i++) {
|
|
u32 mask = (1 << blks_needed) - 1;
|
|
|
|
if(blks[i] != 0xFFFFFFFF) {
|
|
for(j = 0; j < 33 - blks_needed; j++) {
|
|
if((blks[i] & mask) == 0) {
|
|
chunk_found = 1;
|
|
blks[i] |= mask;
|
|
func->unk_0x34 = (blks_needed << 0x10) | ((i * 32) + j);
|
|
break;
|
|
}
|
|
|
|
mask <<= 1;
|
|
}
|
|
|
|
if(chunk_found) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(chunk_found) {
|
|
if(func->alloc_type == 1) {
|
|
*code = (char*)cpu->sm_blk_code + ((func->unk_0x34 & 0xFFFF) * 0x200);
|
|
} else {
|
|
*code = (char*)cpu->lg_blk_code + ((func->unk_0x34 & 0xFFFF) * 0xA00);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
|
|
if(type_swapped) {
|
|
func->alloc_type = -1;
|
|
func->unk_0x34 = 0xFFFFFFFF;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuHeapTake.s")
|
|
#endif
|
|
|
|
int cpuHeapFree(cpu_class_t *cpu, recomp_node_t *func) {
|
|
u32 mask;
|
|
u32 blk_idx;
|
|
u32 *blk;
|
|
|
|
if(func->alloc_type == 1) {
|
|
blk = cpu->sm_blk_status;
|
|
} else if(func->alloc_type == 2) {
|
|
blk = cpu->lg_blk_status;
|
|
} else {
|
|
if(func->unk_0x00 != 0) {
|
|
if(!xlHeapFree((void**)&func->unk_0x00)) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
if(!xlHeapFree((void**)&func->recompiled_func)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if(func->unk_0x34 == -1) {
|
|
return 0;
|
|
}
|
|
|
|
mask = ((1 << (func->unk_0x34 >> 0x10)) - 1) << (func->unk_0x34 & 0x1F);
|
|
blk_idx = (func->unk_0x34 >> 5) & 0x7FF;
|
|
|
|
if((blk[blk_idx] & mask) == mask) {
|
|
blk[blk_idx] &= ~mask;
|
|
func->alloc_type = -1;
|
|
func->unk_0x34 = -1;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuTreeTake.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/cpuFindFunction.s")
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/virtual_console/cpu/func_8003E604.s") |