Files
oot-vc/src/virtual_console/cpu.c
T
KrimtonZ e70fe00a28 wip
2021-05-11 11:33:56 -05:00

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")