DSP: Corrected CMPI implementation. (i think)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2888 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-04-05 21:04:46 +00:00
parent 1ad5c7c9aa
commit e3b1356f3d
3 changed files with 39 additions and 66 deletions

View File

@ -602,36 +602,16 @@ void andf(const UDSPInstruction& opc)
} }
} }
// FIXME inside
void cmpi(const UDSPInstruction& opc) void cmpi(const UDSPInstruction& opc)
{ {
if (opc.hex & 0xf)
{
// FIXME: Implement
ERROR_LOG(DSPHLE, "dsp subf opcode");
}
#if 1
// Old implementation
u8 reg = 0x1e + ((opc.hex >> 8) & 0x1);
s64 imm = (s16)dsp_fetch_code();
s64 val = (s16)g_dsp.r[reg];
s64 res = val - imm;
Update_SR_Register64(res);
#else
// Implementation according to docs
int reg = (opc.hex >> 8) & 0x1; int reg = (opc.hex >> 8) & 0x1;
// Immediate is considered to be at M level in the 40-bit accumulator. // Immediate is considered to be at M level in the 40-bit accumulator.
s64 imm = (s64)dsp_fetch_code() << 16; s64 imm = (s64)(s16)dsp_fetch_code() << 16;
s64 val = dsp_get_long_acc(reg); s64 val = dsp_get_long_acc(reg);
s64 res = val - imm; s64 res = val - imm;
Update_SR_Register64(res); Update_SR_Register64(res);
#endif
} }
// FIXME inside // FIXME inside
@ -1061,27 +1041,38 @@ void srbith(const UDSPInstruction& opc)
{ {
switch ((opc.hex >> 8) & 0xf) switch ((opc.hex >> 8) & 0xf)
{ {
// M0 seems to be the default. M2 is used in functions in Zelda
// and then reset with M0 at the end. Like the other bits here, it's
// done around loops with lots of multiplications.
case 0xa: // M2 case 0xa: // M2
ERROR_LOG(DSPHLE, "dsp_opc.hex_m2"); ERROR_LOG(DSPHLE, "M2");
break; break;
// FIXME: Both of these appear in the beginning of the Wind Waker // FIXME: Both of these appear in the beginning of the Wind Waker
case 0xb: // M0 case 0xb: // M0
ERROR_LOG(DSPHLE, "dsp_opc.hex_m0"); ERROR_LOG(DSPHLE, "M0");
break;
case 0xc: // CLR15
ERROR_LOG(DSPHLE, "dsp_opc.hex_clr15");
break;
case 0xd: // SET15
ERROR_LOG(DSPHLE, "dsp_opc.hex_set15");
break; break;
// 15-bit precision? clamping? no idea :(
// CLR15 seems to be the default.
case 0xc: // CLR15
ERROR_LOG(DSPHLE, "CLR15");
break;
case 0xd: // SET15
ERROR_LOG(DSPHLE, "SET15");
break;
// 40-bit precision? clamping? no idea :(
// 40 seems to be the default.
case 0xe: // SET40 (really, clear SR's 0x4000?) something about "set 40-bit operation"? case 0xe: // SET40 (really, clear SR's 0x4000?) something about "set 40-bit operation"?
g_dsp.r[R_SR] &= ~(1 << 14); g_dsp.r[R_SR] &= ~(1 << 14);
ERROR_LOG(DSPHLE, "SET40");
break; break;
case 0xf: // SET16 (really, set SR's 0x4000?) something about "set 16-bit operation"? case 0xf: // SET16 (really, set SR's 0x4000?) something about "set 16-bit operation"?
// that doesnt happen on a real console << what does this comment mean? // that doesnt happen on a real console << what does this comment mean?
g_dsp.r[R_SR] |= (1 << 14); g_dsp.r[R_SR] |= (1 << 14);
ERROR_LOG(DSPHLE, "SET16");
break; break;
default: default:

View File

@ -57,8 +57,9 @@ jnz, ifs, retlnz
void nop(const UDSPInstruction& opc) {/*DSPInterpreter::unknown(opc);*/} void nop(const UDSPInstruction& opc) {/*DSPInterpreter::unknown(opc);*/}
// Unknown Ops
// "Unrecognized opcode 0x01a2, pc 0x0165" seems wrong. // All AX games: a100
// Zelda Four Swords: 02ca
// TODO: Fill up the tables with the corresponding instructions // TODO: Fill up the tables with the corresponding instructions
@ -66,6 +67,7 @@ DSPOPCTemplate opcodes[] =
{ {
{"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL}, {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL},
{"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL}, {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL},
{"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
{"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
{"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
@ -205,10 +207,16 @@ DSPOPCTemplate opcodes[] =
{"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
// These guys probably change the precision or range of some operations.
// The question is which. 16-bit mode vs 40-bit mode sounds plausible for SET40/SET16.
// Maybe Set15 makes the dsp drop the top bit from all calculations or something? Or clamp?
// SET15/CLR15 is commonly used around MULXAC in Zeldas.
// SET16 is done around complicated loops with many madds etc.
{"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SET40", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"SET40", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SET16", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"SET16", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
@ -218,6 +226,9 @@ DSPOPCTemplate opcodes[] =
{"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
// ??? is seen in burnout2 : opcode 0xa100
// {"???", 0xa100, 0xf7ff, DSPInterpreter::unknown,nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"TST", 0xb100, 0xf7ff, DSPInterpreter::tsta, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"TST", 0xb100, 0xf7ff, DSPInterpreter::tsta, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},

View File

@ -120,7 +120,7 @@ inline s64 dsp_get_long_prod()
low_prod <<= 16; low_prod <<= 16;
low_prod |= g_dsp.r[0x14]; low_prod |= g_dsp.r[0x14];
val += low_prod; val += low_prod;
return(val); return val;
} }
@ -138,11 +138,8 @@ inline void dsp_set_long_prod(s64 val)
g_dsp.r[0x17] = 0; g_dsp.r[0x17] = 0;
} }
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
//
// --- acc // --- acc
//
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
inline s64 dsp_get_long_acc(int reg) inline s64 dsp_get_long_acc(int reg)
@ -152,37 +149,11 @@ inline s64 dsp_get_long_acc(int reg)
#endif #endif
_assert_(reg < 2); _assert_(reg < 2);
s64 val; s64 high = (s64)(s8)g_dsp.r[0x10 + reg] << 32;
s64 low_acc; u32 mid_low = ((u32)g_dsp.r[0x1e + reg] << 16) | g_dsp.r[0x1c + reg];
val = (s8)g_dsp.r[0x10 + reg]; return high | mid_low;
val <<= 32;
low_acc = g_dsp.r[0x1e + reg];
low_acc <<= 16;
low_acc |= g_dsp.r[0x1c + reg];
val |= low_acc;
return val;
} }
inline u64 dsp_get_ulong_acc(int reg)
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
_assert_(reg < 2);
u64 val;
u64 low_acc;
val = (u8)g_dsp.r[0x10 + reg];
val <<= 32;
low_acc = g_dsp.r[0x1e + reg];
low_acc <<= 16;
low_acc |= g_dsp.r[0x1c + reg];
val |= low_acc;
return val;
}
inline void dsp_set_long_acc(int _reg, s64 val) inline void dsp_set_long_acc(int _reg, s64 val)
{ {
#if PROFILE #if PROFILE