mirror of
https://github.com/libretro/beetle-psx-libretro.git
synced 2024-11-27 02:40:31 +00:00
564 lines
21 KiB
C
564 lines
21 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "pgxp_debug.h"
|
|
#include "pgxp_cpu.h"
|
|
#include "pgxp_gte.h"
|
|
#include "pgxp_mem.h"
|
|
#include "pgxp_value.h"
|
|
|
|
unsigned int pgxp_debug = 0;
|
|
|
|
// Instruction register decoding
|
|
#define op(_instr) (_instr >> 26) // The op part of the instruction register
|
|
#define func(_instr) ((_instr) & 0x3F) // The funct part of the instruction register
|
|
#define sa(_instr) ((_instr >> 6) & 0x1F) // The sa part of the instruction register
|
|
#define rd(_instr) ((_instr >> 11) & 0x1F) // The rd part of the instruction register
|
|
#define rt(_instr) ((_instr >> 16) & 0x1F) // The rt part of the instruction register
|
|
#define rs(_instr) ((_instr >> 21) & 0x1F) // The rs part of the instruction register
|
|
#define imm(_instr) (_instr & 0xFFFF) // The immediate part of the instruction register
|
|
|
|
// Operand ID flags
|
|
typedef enum
|
|
{
|
|
fOp_CPU_Hi = 1 << 0,
|
|
fOp_CPU_Lo = 1 << 1,
|
|
fOp_CPU_Rd = 1 << 2,
|
|
fOp_CPU_Rs = 1 << 3,
|
|
fOp_CPU_Rt = 1 << 4,
|
|
|
|
fOp_GTE_Dd = 1 << 5,
|
|
fOp_GTE_Dt = 1 << 6,
|
|
fOp_GTE_Cd = 1 << 7,
|
|
fOp_GTE_Ct = 1 << 8,
|
|
|
|
fOp_CP0_Dd = 1 << 9,
|
|
fOp_CP0_Cd = 1 << 10,
|
|
|
|
fOp_Ad = 1 << 11,
|
|
fOp_Sa = 1 << 12,
|
|
fOp_Im = 1 << 13
|
|
} PGXP_CPU_OperandIDs;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int eOp;
|
|
unsigned short OutputFlags;
|
|
unsigned short InputFlags;
|
|
unsigned char numRegisters;
|
|
unsigned char numArgs;
|
|
const char* szOpString;
|
|
const char* szOpName;
|
|
void(*funcPtr)();
|
|
} PGXP_CPU_OpData;
|
|
|
|
void PGXP_CPU_EMPTY() {}
|
|
void PGXP_CPU_NULL() { int* pi = NULL; *pi = 5; }
|
|
void PGXP_CPU_ERROR() { int* pi = NULL; *pi = 5; }
|
|
|
|
#define PGXP_Data_ERROR { DBG_E_ERROR, 0, 0, 0, 0, "", "ERROR", (void(*)())PGXP_CPU_ERROR }
|
|
#define PGXP_Data_NULL { DBG_E_NULL, 0, 0, 0, 0, "", "NULL", (void(*)())PGXP_CPU_NULL }
|
|
#define PGXP_Data_SPECIAL { DBG_E_SPECIAL, 0, 0, 0, 0, "", "SPECIAL", (void(*)())PGXP_CPU_EMPTY }
|
|
#define PGXP_Data_COP0 { DBG_E_COP0, 0, 0, 0, 0, "", "COP0", (void(*)())PGXP_CPU_EMPTY }
|
|
#define PGXP_Data_COP2 { DBG_E_COP2, 0, 0, 0, 0, "", "COP2", (void(*)())PGXP_CPU_EMPTY }
|
|
#define PGXP_Data_HLE { DBG_E_HLE, 0, 0, 0, 0, "", "HLE", (void(*)())PGXP_CPU_EMPTY }
|
|
|
|
// Arithmetic with immediate value
|
|
#define PGXP_Data_ADDI { DBG_E_ADDI, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "+", "ADDI", (void(*)())PGXP_CPU_ADDI }
|
|
#define PGXP_Data_ADDIU { DBG_E_ADDIU, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "+", "ADDIU", (void(*)())PGXP_CPU_ADDIU }
|
|
#define PGXP_Data_ANDI { DBG_E_ANDI, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "&", "ANDI", (void(*)())PGXP_CPU_ANDI }
|
|
#define PGXP_Data_ORI { DBG_E_ORI, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "|", "ORI", (void(*)())PGXP_CPU_ORI }
|
|
#define PGXP_Data_XORI { DBG_E_XORI, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "^", "XORI", (void(*)())PGXP_CPU_XORI }
|
|
#define PGXP_Data_SLTI { DBG_E_SLTI, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "<", "SLTI", (void(*)())PGXP_CPU_SLTI }
|
|
#define PGXP_Data_SLTIU { DBG_E_SLTIU, fOp_CPU_Rt, fOp_CPU_Rs | fOp_Im, 2, 2, "<", "SLTIU", (void(*)())PGXP_CPU_SLTIU }
|
|
// Load Upper
|
|
#define PGXP_Data_LUI { DBG_E_LUI, fOp_CPU_Rt, fOp_Im, 1, 1, "<<", "LUI", (void(*)())PGXP_CPU_LUI }
|
|
|
|
// Load/Store
|
|
#define PGXP_Data_LWL { DBG_E_LWL, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LWL", (void(*)())PGXP_CPU_LWL } // 32-bit Loads
|
|
#define PGXP_Data_LW { DBG_E_LW, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LW", (void(*)())PGXP_CPU_LW }
|
|
#define PGXP_Data_LWR { DBG_E_LWR, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LWR", (void(*)())PGXP_CPU_LWR }
|
|
#define PGXP_Data_LH { DBG_E_LH, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LH", (void(*)())PGXP_CPU_LH } // 16-bit Loads
|
|
#define PGXP_Data_LHU { DBG_E_LHU, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LHU", (void(*)())PGXP_CPU_LHU }
|
|
#define PGXP_Data_LB { DBG_E_LB, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LB", (void(*)())PGXP_CPU_LB } // 8-bit Loads
|
|
#define PGXP_Data_LBU { DBG_E_LBU, fOp_CPU_Rt, fOp_Ad, 1, 2, "", "LBU", (void(*)())PGXP_CPU_LBU }
|
|
#define PGXP_Data_SWL { DBG_E_SWL, fOp_Ad, fOp_CPU_Rt, 1, 2, "", "SWL", (void(*)())PGXP_CPU_SWL } // 32-bit Store
|
|
#define PGXP_Data_SW { DBG_E_SW, fOp_Ad, fOp_CPU_Rt, 1, 2, "", "SW", (void(*)())PGXP_CPU_SW }
|
|
#define PGXP_Data_SWR { DBG_E_SWR, fOp_Ad, fOp_CPU_Rt, 1, 2, "", "SWR", (void(*)())PGXP_CPU_SWR }
|
|
#define PGXP_Data_SH { DBG_E_SH, fOp_Ad, fOp_CPU_Rt, 1, 2, "", "SH", (void(*)())PGXP_CPU_SH } // 16-bit Store
|
|
#define PGXP_Data_SB { DBG_E_SB, fOp_Ad, fOp_CPU_Rt, 1, 2, "", "SB", (void(*)())PGXP_CPU_SB } // 8-bit Store
|
|
|
|
// Load/Store GTE
|
|
#define PGXP_Data_LWC2 { DBG_E_LWC2, fOp_GTE_Dt, fOp_Ad, 1, 2, "", "LWC2", (void(*)())PGXP_GTE_LWC2 } // 32-bit Loads
|
|
#define PGXP_Data_SWC2 { DBG_E_SWC2, fOp_Ad, fOp_GTE_Dt, 1, 2, "", "SWC2", (void(*)())PGXP_GTE_SWC2 } // 32-bit Store
|
|
|
|
static PGXP_CPU_OpData PGXP_BSC_LUT[64] = {
|
|
PGXP_Data_SPECIAL, PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_ADDI , PGXP_Data_ADDIU , PGXP_Data_SLTI, PGXP_Data_SLTIU, PGXP_Data_ANDI, PGXP_Data_ORI , PGXP_Data_XORI, PGXP_Data_LUI ,
|
|
PGXP_Data_COP0 , PGXP_Data_NULL , PGXP_Data_COP2, PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_LB , PGXP_Data_LH , PGXP_Data_LWL , PGXP_Data_LW , PGXP_Data_LBU , PGXP_Data_LHU , PGXP_Data_LWR , PGXP_Data_NULL,
|
|
PGXP_Data_SB , PGXP_Data_SH , PGXP_Data_SWL , PGXP_Data_SW , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_SWR , PGXP_Data_NULL,
|
|
PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_LWC2, PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_SWC2, PGXP_Data_HLE , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL
|
|
};
|
|
|
|
// Register Arithmetic
|
|
#define PGXP_Data_ADD { DBG_E_ADD, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "+", "ADD", (void(*)())PGXP_CPU_ADD }
|
|
#define PGXP_Data_ADDU { DBG_E_ADDU, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "+", "ADDU", (void(*)())PGXP_CPU_ADDU }
|
|
#define PGXP_Data_SUB { DBG_E_SUB, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "-", "SUB", (void(*)())PGXP_CPU_SUB }
|
|
#define PGXP_Data_SUBU { DBG_E_SUBU, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "-", "SUBU", (void(*)())PGXP_CPU_SUBU }
|
|
#define PGXP_Data_AND { DBG_E_AND, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "&", "AND", (void(*)())PGXP_CPU_AND }
|
|
#define PGXP_Data_OR { DBG_E_OR, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "|", "OR", (void(*)())PGXP_CPU_OR }
|
|
#define PGXP_Data_XOR { DBG_E_XOR, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "^", "XOR", (void(*)())PGXP_CPU_XOR }
|
|
#define PGXP_Data_NOR { DBG_E_NOR, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "^", "NOR", (void(*)())PGXP_CPU_NOR }
|
|
#define PGXP_Data_SLT { DBG_E_SLT, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "<", "SLT", (void(*)())PGXP_CPU_SLT }
|
|
#define PGXP_Data_SLTU { DBG_E_SLTU, fOp_CPU_Rd, fOp_CPU_Rs | fOp_CPU_Rt, 3, 3, "<", "SLTU", (void(*)())PGXP_CPU_SLTU }
|
|
|
|
// Register mult/div
|
|
#define PGXP_Data_MULT { DBG_E_MULT, fOp_CPU_Hi | fOp_CPU_Lo, fOp_CPU_Rs | fOp_CPU_Rt, 4, 4, "*", "MULT", (void(*)())PGXP_CPU_MULT }
|
|
#define PGXP_Data_MULTU { DBG_E_MULTU, fOp_CPU_Hi | fOp_CPU_Lo, fOp_CPU_Rs | fOp_CPU_Rt, 4, 4, "*", "MULTU", (void(*)())PGXP_CPU_MULTU }
|
|
#define PGXP_Data_DIV { DBG_E_DIV, fOp_CPU_Hi | fOp_CPU_Lo, fOp_CPU_Rs | fOp_CPU_Rt, 4, 4, "/", "DIV", (void(*)())PGXP_CPU_DIV }
|
|
#define PGXP_Data_DIVU { DBG_E_DIVU, fOp_CPU_Hi | fOp_CPU_Lo, fOp_CPU_Rs | fOp_CPU_Rt, 4, 4, "/", "DIVU", (void(*)())PGXP_CPU_DIVU }
|
|
|
|
// Shift operations (sa)
|
|
#define PGXP_Data_SLL { DBG_E_SLL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, "<<", "SLL", (void(*)())PGXP_CPU_SLL }
|
|
#define PGXP_Data_SRL { DBG_E_SRL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, ">>", "SRL", (void(*)())PGXP_CPU_SRL }
|
|
#define PGXP_Data_SRA { DBG_E_SRA, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, ">>", "SRA", (void(*)())PGXP_CPU_SRA }
|
|
|
|
// Shift operations variable
|
|
#define PGXP_Data_SLLV { DBG_E_SLLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, "<<", "SLLV", (void(*)())PGXP_CPU_SLLV }
|
|
#define PGXP_Data_SRLV { DBG_E_SRLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, ">>", "SRLV", (void(*)())PGXP_CPU_SRLV }
|
|
#define PGXP_Data_SRAV { DBG_E_SRAV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, ">>", "SRAV", (void(*)())PGXP_CPU_SRAV }
|
|
|
|
// Move registers
|
|
#define PGXP_Data_MFHI { DBG_E_MFHI, fOp_CPU_Rd, fOp_CPU_Hi, 2, 2, "<-", "MFHI", (void(*)())PGXP_CPU_MFHI }
|
|
#define PGXP_Data_MTHI { DBG_E_MTHI, fOp_CPU_Hi, fOp_CPU_Rd, 2, 2, "<-", "MTHI", (void(*)())PGXP_CPU_MTHI }
|
|
#define PGXP_Data_MFLO { DBG_E_MFLO, fOp_CPU_Rd, fOp_CPU_Lo, 2, 2, "<-", "MFLO", (void(*)())PGXP_CPU_MFLO }
|
|
#define PGXP_Data_MTLO { DBG_E_MTLO, fOp_CPU_Lo, fOp_CPU_Rd, 2, 2, "<-", "MFHI", (void(*)())PGXP_CPU_MTLO }
|
|
|
|
static PGXP_CPU_OpData PGXP_SPC_LUT[64] = {
|
|
PGXP_Data_SLL , PGXP_Data_NULL, PGXP_Data_SRL , PGXP_Data_SRA , PGXP_Data_SLLV , PGXP_Data_NULL , PGXP_Data_SRLV, PGXP_Data_SRAV,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_MFHI, PGXP_Data_MTHI, PGXP_Data_MFLO, PGXP_Data_MTLO, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_MULT, PGXP_Data_MULTU, PGXP_Data_DIV, PGXP_Data_DIVU, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_ADD , PGXP_Data_ADDU, PGXP_Data_SUB , PGXP_Data_SUBU, PGXP_Data_AND , PGXP_Data_OR , PGXP_Data_XOR , PGXP_Data_NOR ,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_SLT , PGXP_Data_SLTU, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL , PGXP_Data_NULL , PGXP_Data_NULL, PGXP_Data_NULL
|
|
};
|
|
|
|
// GTE transfer registers
|
|
#define PGXP_Data_MFC2 { DBG_E_MFC2, fOp_CPU_Rt, fOp_GTE_Dd, 2, 2, "<-", "MFC2", (void(*)())PGXP_GTE_MFC2 }
|
|
#define PGXP_Data_MTC2 { DBG_E_MTC2, fOp_GTE_Dd, fOp_CPU_Rt, 2, 2, "<-", "MTC2", (void(*)())PGXP_GTE_MTC2 }
|
|
#define PGXP_Data_CFC2 { DBG_E_CFC2, fOp_CPU_Rt, fOp_GTE_Cd, 2, 2, "<-", "CFC2", (void(*)())PGXP_GTE_CFC2 }
|
|
#define PGXP_Data_CTC2 { DBG_E_CTC2, fOp_GTE_Cd, fOp_CPU_Rt, 2, 2, "<-", "CTC2", (void(*)())PGXP_GTE_CTC2 }
|
|
|
|
static PGXP_CPU_OpData PGXP_CO2BSC_LUT[32] = {
|
|
PGXP_Data_MFC2, PGXP_Data_NULL, PGXP_Data_CFC2, PGXP_Data_NULL, PGXP_Data_MTC2, PGXP_Data_NULL, PGXP_Data_CTC2, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL
|
|
};
|
|
|
|
// CP0 transfer registers
|
|
#define PGXP_Data_MFC0 { DBG_E_MFC0, fOp_CPU_Rt, fOp_CP0_Dd, 2, 2, "<-", "MFC0", (void(*)())PGXP_CP0_MFC0 }
|
|
#define PGXP_Data_MTC0 { DBG_E_MTC0, fOp_CP0_Dd, fOp_CPU_Rt, 2, 2, "<-", "MTC0", (void(*)())PGXP_CP0_MTC0 }
|
|
#define PGXP_Data_CFC0 { DBG_E_CFC0, fOp_CPU_Rt, fOp_CP0_Cd, 2, 2, "<-", "CFC0", (void(*)())PGXP_CP0_CFC0 }
|
|
#define PGXP_Data_CTC0 { DBG_E_CTC0, fOp_CP0_Cd, fOp_CPU_Rt, 2, 2, "<-", "CTC0", (void(*)())PGXP_CP0_CTC0 }
|
|
#define PGXP_Data_RFE { DBG_E_RFE, 0, 0, 0, 0,"", "RFE", PGXP_CPU_EMPTY }
|
|
|
|
static PGXP_CPU_OpData PGXP_COP0_LUT[32] = {
|
|
PGXP_Data_MFC0, PGXP_Data_NULL, PGXP_Data_CFC0, PGXP_Data_NULL, PGXP_Data_MTC0, PGXP_Data_NULL, PGXP_Data_CTC0, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_RFE , PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL,
|
|
PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL, PGXP_Data_NULL
|
|
};
|
|
|
|
PGXP_CPU_OpData GetOpData(u32 instr)
|
|
{
|
|
PGXP_CPU_OpData pOpData = PGXP_Data_ERROR;
|
|
switch (op(instr))
|
|
{
|
|
case 0:
|
|
if (func(instr) < 64)
|
|
pOpData = PGXP_SPC_LUT[func(instr)];
|
|
break;
|
|
case 1:
|
|
//pOpData = PGXP_BCOND_LUT[rt(instr)];
|
|
break;
|
|
case 16:
|
|
if (rs(instr) < 32)
|
|
pOpData = PGXP_COP0_LUT[rs(instr)];
|
|
break;
|
|
case 18:
|
|
if ((func(instr) == 0) && (rs(instr) < 32))
|
|
pOpData = PGXP_CO2BSC_LUT[rs(instr)];
|
|
//else
|
|
// pOpData = PGXP_COP2_LUT[func(instr)];
|
|
break;
|
|
default:
|
|
if(op(instr) < 64)
|
|
pOpData = PGXP_BSC_LUT[op(instr)];
|
|
break;
|
|
}
|
|
|
|
return pOpData;
|
|
}
|
|
|
|
PGXP_value* GetReg(u32 instr, u32 flag, u32 psxValue)
|
|
{
|
|
// iCB Hack: reorder Rs and Rt for SLLV SRLV and SRAV
|
|
if ((op(instr) == 0) && (func(instr) > 3) && (func(instr) < 8))
|
|
flag = (flag == fOp_CPU_Rs) ? fOp_CPU_Rt : ((flag == fOp_CPU_Rt) ? fOp_CPU_Rs : flag);
|
|
// /iCB Hack
|
|
|
|
switch (flag)
|
|
{
|
|
case fOp_CPU_Hi:
|
|
return &CPU_Hi;
|
|
case fOp_CPU_Lo:
|
|
return &CPU_Lo;
|
|
case fOp_CPU_Rd:
|
|
return &CPU_reg[rd(instr)];
|
|
case fOp_CPU_Rs:
|
|
return &CPU_reg[rs(instr)];
|
|
case fOp_CPU_Rt:
|
|
return &CPU_reg[rt(instr)];
|
|
case fOp_GTE_Dd:
|
|
return >E_data_reg[rd(instr)];
|
|
case fOp_GTE_Dt:
|
|
return >E_data_reg[rt(instr)];
|
|
case fOp_GTE_Cd:
|
|
return >E_ctrl_reg[rd(instr)];
|
|
case fOp_GTE_Ct:
|
|
return >E_ctrl_reg[rt(instr)];
|
|
case fOp_CP0_Dd:
|
|
return &CP0_reg[rd(instr)];
|
|
case fOp_CP0_Cd:
|
|
return &CP0_reg[rd(instr)];
|
|
case fOp_Ad:
|
|
return GetPtr(psxValue);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void ForceValues(u32 instr, u32 flags, psx_value* psx_regs, u32 startIdx)
|
|
{
|
|
u32 opdIdx;
|
|
PGXP_value* pReg = NULL;
|
|
u32 regIdx = startIdx;
|
|
|
|
for (opdIdx = 0; opdIdx < 14; opdIdx++)
|
|
{
|
|
u32 flag = 1 << opdIdx;
|
|
|
|
// iCB: Skip Load operations as data at address is unknown
|
|
if ((flags & flag) && (flag != fOp_Ad))
|
|
{
|
|
pReg = GetReg(instr, flag, psx_regs[regIdx].d);
|
|
|
|
if (pReg)
|
|
{
|
|
SetValue(pReg, psx_regs[regIdx].d);
|
|
regIdx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestValues(u32 instr, u32 flags, psx_value* psx_regs, u32 *test_flags, u32 startIdx)
|
|
{
|
|
u32 opdIdx;
|
|
PGXP_value* pReg = NULL;
|
|
u32 regIdx = startIdx;
|
|
|
|
for (opdIdx = 0; opdIdx < 14; opdIdx++)
|
|
{
|
|
u32 flag = 1 << opdIdx;
|
|
|
|
// iCB: Skip Store operations as data at address is unknown
|
|
if ((flags & flag) && (flag != fOp_Ad))
|
|
{
|
|
pReg = GetReg(instr, flag, psx_regs[regIdx].d);
|
|
|
|
if (pReg)
|
|
{
|
|
test_flags[regIdx] = ValueToTolerance(pReg, psx_regs[regIdx].d, PGXP_DEBUG_TOLERANCE);
|
|
regIdx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintOperands(char* szBuffer, u32 instr, u32 flags, const char* szDelim, psx_value* psx_regs, u32 startIdx)
|
|
{
|
|
u32 opdIdx;
|
|
char szTempBuffer[256];
|
|
PGXP_value* pReg = NULL;
|
|
psx_value psx_reg;
|
|
u32 regIdx = startIdx;
|
|
char szOpdName[16];
|
|
const char* szPre = "";
|
|
|
|
memset(szTempBuffer, 0, sizeof(szTempBuffer));
|
|
for (opdIdx = 0; opdIdx < 14; opdIdx++)
|
|
{
|
|
u32 flag = 1 << opdIdx;
|
|
|
|
// iCB Hack: reorder Rs and Rt for SLLV SRLV and SRAV
|
|
if ((op(instr) == 0) && (func(instr) > 3) && (func(instr) < 8))
|
|
flag = (flag == fOp_CPU_Rs) ? fOp_CPU_Rt : ((flag == fOp_CPU_Rt) ? fOp_CPU_Rs : flag);
|
|
// /iCB Hack
|
|
|
|
if (flags & flag)
|
|
{
|
|
switch (flag)
|
|
{
|
|
case fOp_CPU_Hi:
|
|
pReg = &CPU_Hi;
|
|
sprintf(szOpdName, "Hi");
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CPU_Lo:
|
|
pReg = &CPU_Lo;
|
|
sprintf(szOpdName, "Lo");
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CPU_Rd:
|
|
pReg = &CPU_reg[rd(instr)];
|
|
sprintf(szOpdName, "Rd[%d]", rd(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CPU_Rs:
|
|
pReg = &CPU_reg[rs(instr)];
|
|
sprintf(szOpdName, "Rs[%d]", rs(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CPU_Rt:
|
|
pReg = &CPU_reg[rt(instr)];
|
|
sprintf(szOpdName, "Rt[%d]", rt(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_GTE_Dd:
|
|
pReg = >E_data_reg[rd(instr)];
|
|
sprintf(szOpdName, "GTE_Dd[%d]", rd(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_GTE_Dt:
|
|
pReg = >E_data_reg[rt(instr)];
|
|
sprintf(szOpdName, "GTE_Dt[%d]", rt(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_GTE_Cd:
|
|
pReg = >E_ctrl_reg[rd(instr)];
|
|
sprintf(szOpdName, "GTE_Cd[%d]", rd(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_GTE_Ct:
|
|
pReg = >E_ctrl_reg[rt(instr)];
|
|
sprintf(szOpdName, "GTE_Ct[%d]", rt(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CP0_Dd:
|
|
pReg = &CP0_reg[rd(instr)];
|
|
sprintf(szOpdName, "CP0_Dd[%d]", rd(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_CP0_Cd:
|
|
pReg = &CP0_reg[rd(instr)];
|
|
sprintf(szOpdName, "CP0_Cd[%d]", rd(instr));
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_Ad:
|
|
pReg = NULL;
|
|
sprintf(szOpdName, "Addr");
|
|
psx_reg = psx_regs[regIdx++];
|
|
break;
|
|
case fOp_Sa:
|
|
pReg = NULL;
|
|
sprintf(szOpdName, "Sa");
|
|
psx_reg.d = sa(instr);
|
|
break;
|
|
case fOp_Im:
|
|
pReg = NULL;
|
|
sprintf(szOpdName, "Imm");
|
|
psx_reg.d = imm(instr);
|
|
break;
|
|
}
|
|
|
|
if (pReg)
|
|
{
|
|
sprintf(szTempBuffer, "%s %s [%x(%d, %d) %x(%.2f, %.2f, %.2f)%x : %x:%x:%x:%x] ", szPre, szOpdName,
|
|
psx_reg.d, psx_reg.sw.l, psx_reg.sw.h,
|
|
pReg->value, pReg->x, pReg->y, pReg->z, pReg->count, pReg->compFlags[0], pReg->compFlags[1], pReg->compFlags[2], pReg->compFlags[3]);
|
|
strcat(szBuffer, szTempBuffer);
|
|
}
|
|
else if(flag == fOp_Ad)
|
|
{
|
|
pReg = GetPtr(psx_reg.d);
|
|
if(pReg)
|
|
sprintf(szTempBuffer, "%s %s [%x(%d, %d) (%x) %x(%.2f, %.2f, %.2f)%x : %x:%x:%x:%x] ", szPre, szOpdName,
|
|
psx_reg.d, psx_reg.sw.l, psx_reg.sw.h, PGXP_ConvertAddress(psx_reg.d),
|
|
pReg->value, pReg->x, pReg->y, pReg->z, pReg->count, pReg->compFlags[0], pReg->compFlags[1], pReg->compFlags[2], pReg->compFlags[3]);
|
|
else
|
|
sprintf(szTempBuffer, "%s %s [%x(%d, %d) (%x) INVALID_ADDRESS!] ", szPre, szOpdName,
|
|
psx_reg.d, psx_reg.sw.l, psx_reg.sw.h, PGXP_ConvertAddress(psx_reg.d));
|
|
strcat(szBuffer, szTempBuffer);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szTempBuffer, "%s %s [%x(%d, %d)] ", szPre, szOpdName,
|
|
psx_reg.d, psx_reg.sw.l, psx_reg.sw.h);
|
|
strcat(szBuffer, szTempBuffer);
|
|
}
|
|
|
|
szPre = szDelim;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PGXP_CPU_DebugOutput(u32 eOp, u32 instr, u32 numOps, u32 op1, u32 op2, u32 op3, u32 op4)
|
|
{
|
|
u32 opdIdx;
|
|
char szOutputBuffer[256];
|
|
char szInputBuffer[512];
|
|
PGXP_CPU_OpData opData = GetOpData(instr);
|
|
u32 test_flags[4] = { VALID_ALL, VALID_ALL, VALID_ALL, VALID_ALL };
|
|
u32 inIdx = 0;
|
|
psx_value psx_regs[4];
|
|
psx_regs[0].d = op1;
|
|
psx_regs[1].d = op2;
|
|
psx_regs[2].d = op3;
|
|
psx_regs[3].d = op4;
|
|
|
|
// iCB Hack: Switch operands around for store functions
|
|
if ((op(instr) >= 40)&& (op(instr) != 50))
|
|
{
|
|
psx_regs[0].d = op2;
|
|
psx_regs[1].d = op1;
|
|
}
|
|
|
|
// Hack: duplicate psx register data for GTE register movement funcs
|
|
//if ((op(instr) == 18) && (func(instr) == 0))
|
|
// psx_regs[1] = psx_regs[0];
|
|
|
|
(void)psx_regs;
|
|
|
|
// /iCB Hack
|
|
|
|
// skip output arguments to find first input
|
|
for (opdIdx = 0; opdIdx < 12; opdIdx++)
|
|
{
|
|
if (opData.OutputFlags & (1 << opdIdx))
|
|
inIdx++;
|
|
}
|
|
|
|
#ifdef PGXP_FORCE_INPUT_VALUES
|
|
ForceValues(instr, opData.InputFlags, psx_regs, inIdx);
|
|
#endif
|
|
|
|
|
|
#ifdef PGXP_OUTPUT_ALL
|
|
// reset buffers
|
|
if (pgxp_debug)
|
|
{
|
|
memset(szInputBuffer, 0, sizeof(szInputBuffer));
|
|
memset(szOutputBuffer, 0, sizeof(szOutputBuffer));
|
|
|
|
// Print inputs
|
|
PrintOperands(szInputBuffer, instr, opData.InputFlags, opData.szOpString, psx_regs, inIdx);
|
|
}
|
|
#endif
|
|
|
|
// Call function
|
|
if (numOps != opData.numArgs)
|
|
PGXP_CPU_ERROR();
|
|
|
|
if (eOp != opData.eOp)
|
|
PGXP_CPU_ERROR();
|
|
|
|
switch (numOps)
|
|
{
|
|
case 0:
|
|
((void(*)(u32))opData.funcPtr)(instr);
|
|
break;
|
|
case 1:
|
|
((void(*)(u32, u32))opData.funcPtr)(instr, op1);
|
|
break;
|
|
case 2:
|
|
((void(*)(u32, u32, u32))opData.funcPtr)(instr, op1, op2);
|
|
break;
|
|
case 3:
|
|
((void(*)(u32, u32, u32, u32))opData.funcPtr)(instr, op1, op2, op3);
|
|
break;
|
|
case 4:
|
|
((void(*)(u32, u32, u32, u32, u32))opData.funcPtr)(instr, op1, op2, op3, op4);
|
|
break;
|
|
}
|
|
|
|
#ifdef PGXP_TEST_OUTPUT_VALUES
|
|
TestValues(instr, opData.OutputFlags, psx_regs, test_flags, 0);
|
|
#endif//PGXP_TEST_OUTPUT_VALUES
|
|
|
|
#ifdef PGXP_OUTPUT_ALL
|
|
// Print operation details
|
|
if (pgxp_debug)
|
|
{
|
|
sprintf(szOutputBuffer, "%s %x %x: ", opData.szOpName, op(instr), func(instr));
|
|
// Print outputs
|
|
PrintOperands(szOutputBuffer, instr, opData.OutputFlags, "/", psx_regs, 0);
|
|
strcat(szOutputBuffer, "=");
|
|
|
|
#ifdef GTE_LOG
|
|
#ifdef PGXP_TEST_OUTPUT_VALUES
|
|
if((test_flags[0] & test_flags[1] & VALID_01) != VALID_01)
|
|
#endif//PGXP_TEST_OUTPUT_VALUES
|
|
GTE_LOG("PGXP_Trace: %s %s|", szOutputBuffer, szInputBuffer);
|
|
#endif//GTE_LOG
|
|
|
|
}
|
|
#endif//PGXP_OUTPUT_ALL
|
|
}
|
|
|
|
void PGXP_psxTraceOp(u32 eOp, u32 instr)
|
|
{
|
|
//PGXP_CPU_OpData opData = GetOpData(instr);
|
|
//if (opData.funcPtr && (opData.numArgs == 0))
|
|
// ((void(*)(u32))opData.funcPtr)(instr);
|
|
PGXP_CPU_DebugOutput(eOp, instr, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
void PGXP_psxTraceOp1(u32 eOp, u32 instr, u32 op1)
|
|
{
|
|
//PGXP_CPU_OpData opData = GetOpData(instr);
|
|
//if (opData.funcPtr && (opData.numArgs == 1))
|
|
// ((void(*)(u32, u32))opData.funcPtr)(instr, op1);
|
|
PGXP_CPU_DebugOutput(eOp, instr, 1, op1, 0, 0, 0);
|
|
}
|
|
|
|
void PGXP_psxTraceOp2(u32 eOp, u32 instr, u32 op1, u32 op2)
|
|
{
|
|
//PGXP_CPU_OpData opData = GetOpData(instr);
|
|
//if (opData.funcPtr && (opData.numArgs == 2))
|
|
// ((void(*)(u32, u32, u32))opData.funcPtr)(instr, op1, op2);
|
|
PGXP_CPU_DebugOutput(eOp, instr, 2, op1, op2, 0, 0);
|
|
}
|
|
|
|
void PGXP_psxTraceOp3(u32 eOp, u32 instr, u32 op1, u32 op2, u32 op3)
|
|
{
|
|
//PGXP_CPU_OpData opData = GetOpData(instr);
|
|
//if (opData.funcPtr && (opData.numArgs == 3))
|
|
// ((void(*)(u32, u32, u32, u32))opData.funcPtr)(instr, op1, op2, op3);
|
|
PGXP_CPU_DebugOutput(eOp, instr, 3, op1, op2, op3, 0);
|
|
}
|
|
|
|
void PGXP_psxTraceOp4(u32 eOp, u32 instr, u32 op1, u32 op2, u32 op3, u32 op4)
|
|
{
|
|
//PGXP_CPU_OpData opData = GetOpData(instr);
|
|
//if (opData.funcPtr && (opData.numArgs == 4))
|
|
// ((void(*)(u32, u32, u32, u32, u32))opData.funcPtr)(instr, op1, op2, op3, op4);
|
|
PGXP_CPU_DebugOutput(eOp, instr, 4, op1, op2, op3, op4);
|
|
}
|