diff --git a/Source/Core/DSPCore/Src/DSPAccelerator.cpp b/Source/Core/DSPCore/Src/DSPAccelerator.cpp index 946426161f..11ef81974a 100644 --- a/Source/Core/DSPCore/Src/DSPAccelerator.cpp +++ b/Source/Core/DSPCore/Src/DSPAccelerator.cpp @@ -150,9 +150,14 @@ u16 dsp_read_accelerator() } // TODO: Take GAIN into account, whatever it is. - // It looks like its always 0x800 for PCM8/PCM16 and 0x0 for adpcm + // adpcm = 0, pcm8 = 0x100, pcm16 = 0x800 + // games using pcm8 : Phoenix Wright Ace Attorney (Wiiware) if (g_dsp.ifx_regs[DSP_GAIN] > 0) { + // this was trial&error -> it fixes "Super Monkey Ball - Step & Roll" + // sth it wrong with exceptions here... + //DSPCore_SetException(EXP_3); + //NOTICE_LOG(DSPLLE,"format: 0x%04x - val: 0x%04x - gain: 0x%04x", g_dsp.ifx_regs[DSP_FORMAT], val, g_dsp.ifx_regs[DSP_GAIN]); } diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h index b38aa7b7e6..8a585d6c07 100644 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ b/Source/Core/DSPCore/Src/DSPCore.h @@ -157,7 +157,7 @@ #define SR_OVER_S32 0x0010 // set when there there was mod/tst/cmp on accu and result is over s32 #define SR_TOP2BITS 0x0020 // if the upper (ac?.m/ax?.h) 2 bits are equal #define SR_LOGIC_ZERO 0x0040 -#define SR_OVERFLOW_SPECIAL 0x0080 // set at the same time as 0x2 (under same conditions) - but not cleared the same +#define SR_OVERFLOW_STICKY 0x0080 // set at the same time as 0x2 (under same conditions) - but not cleared the same #define SR_100 0x0100 // unknown #define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. #define SR_400 0x0400 // unknown diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp index b5b2366196..f71f870452 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp @@ -40,7 +40,7 @@ void Update_SR_Register64(s64 _Value, bool carry, bool overflow) if (overflow) { g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_SPECIAL; + g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; } // 0x04 @@ -83,7 +83,7 @@ void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) if (overflow) { g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_SPECIAL; + g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; } // 0x04 diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp index c62388537c..332f5c20d0 100644 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp +++ b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp @@ -74,9 +74,9 @@ void nr(const UDSPInstruction& opc) { writeToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg])); } -// MV $axD, $acS.l +// MV $axD.D, $acS.S // xxxx xxxx 0001 ddss -// Move value of $acS.l to the $axD.l. +// Move value of $acS.S to the $axD.D. void mv(const UDSPInstruction& opc) { u8 sreg = (opc.hex & 0x3) + DSP_REG_ACL0; @@ -90,10 +90,10 @@ void mv(const UDSPInstruction& opc) writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r[sreg]); } -// S @$D, $acD.l +// S @$arD, $acS.S // xxxx xxxx 001s s0dd -// Store value of $(acS.l) in the memory pointed by register $D. -// Post increment register $D. +// Store value of $acS.S in the memory pointed by register $arD. +// Post increment register $arD. void s(const UDSPInstruction& opc) { u8 dreg = opc.hex & 0x3; @@ -103,24 +103,23 @@ void s(const UDSPInstruction& opc) writeToBackLog(0, dreg, dsp_increment_addr_reg(dreg)); } -// SN @$D, $acD.l +// SN @$arD, $acS.S // xxxx xxxx 001s s1dd -// Store value of register $acS in the memory pointed by register $D. -// Add indexing register $ixD to register $D. +// Store value of register $acS.S in the memory pointed by register $arD. +// Add indexing register $ixD to register $arD. void sn(const UDSPInstruction& opc) { u8 dreg = opc.hex & 0x3; u8 sreg = ((opc.hex >> 3) & 0x3) + DSP_REG_ACL0; dsp_dmem_write(g_dsp.r[dreg], g_dsp.r[sreg]); - writeToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg])); } -// L axD.l, @$S +// L $axD.D, @$arS // xxxx xxxx 01dd d0ss -// Load $axD with value from memory pointed by register $S. -// Post increment register $S. +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Post increment register $arS. void l(const UDSPInstruction& opc) { u8 sreg = opc.hex & 0x3; @@ -141,10 +140,10 @@ void l(const UDSPInstruction& opc) } } -// LN axD.l, @$S +// LN $axD.D, @$arS // xxxx xxxx 01dd d0ss -// Load $axD with value from memory pointed by register $S. -// Add indexing register register $ixS to register $S. +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Add indexing register register $ixS to register $arS. void ln(const UDSPInstruction& opc) { u8 sreg = opc.hex & 0x3; @@ -165,161 +164,159 @@ void ln(const UDSPInstruction& opc) } } -// LS $axD.l, $acS.m +// LS $axD.D, $acS.m // xxxx xxxx 10dd 000s -// Load register $axD.l with value from memory pointed by register +// Load register $axD.D with value from memory pointed by register // $ar0. Store value from register $acS.m to memory location pointed by // register $ar3. Increment both $ar0 and $ar3. void ls(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; - u8 sreg = DSP_REG_AR3; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r[sreg], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR3], g_dsp.r[sreg]); writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR0])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } -// LSN $acD.l, $acS.m +// LSN $axD.D, $acS.m // xxxx xxxx 10dd 010s -// Load register $acD.l with value from memory pointed by register +// Load register $axD.D with value from memory pointed by register // $ar0. Store value from register $acS.m to memory location pointed by // register $ar3. Add corresponding indexing register $ix0 to addressing // register $ar0 and increment $ar3. void lsn(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; - u8 sreg = DSP_REG_AR3; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r[sreg], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR3], g_dsp.r[sreg]); writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR0])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r[DSP_REG_IX0])); } -// LSM $acD.l, $acS.m +// LSM $axD.D, $acS.m // xxxx xxxx 10dd 100s -// Load register $acD.l with value from memory pointed by register +// Load register $axD.D with value from memory pointed by register // $ar0. Store value from register $acS.m to memory location pointed by // register $ar3. Add corresponding indexing register $ix3 to addressing // register $ar3 and increment $ar0. void lsm(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; - u8 sreg = DSP_REG_AR3; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r[sreg], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR3], g_dsp.r[sreg]); writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR0])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r[DSP_REG_IX0 + DSP_REG_AR3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } -// LSMN $acD.l, $acS.m +// LSMN $axD.D, $acS.m // xxxx xxxx 10dd 110s -// Load register $acD.l with value from memory pointed by register +// Load register $axD.D with value from memory pointed by register // $ar0. Store value from register $acS.m to memory location pointed by // register $ar3. Add corresponding indexing register $ix0 to addressing // register $ar0 and add corresponding indexing register $ix3 to addressing // register $ar3. void lsnm(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; - u8 sreg = DSP_REG_AR3; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r[sreg], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR3], g_dsp.r[sreg]); writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR0])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r[DSP_REG_IX0 + DSP_REG_AR3])); writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r[DSP_REG_IX0])); } -// SL $acS.m, $acD.l +// SL $acS.m, $axD.D // xxxx xxxx 10dd 001s // Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $acD.l with value from memory pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register // $ar3. Increment both $ar0 and $ar3. void sl(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - const u8 sreg = DSP_REG_AR3; - dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[sreg]); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[sreg])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } -// SLN $acS.m, $acD.l +// SLN $acS.m, $axD.D // xxxx xxxx 10dd 011s // Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $acD.l with value from memory pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register // $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 // and increment $ar3. void sln(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - const u8 sreg = DSP_REG_AR3; - dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[sreg]); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[sreg])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r[DSP_REG_IX0])); } -// SLM $acS.m, $acD.l +// SLM $acS.m, $axD.D // xxxx xxxx 10dd 101s // Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $acD.l with value from memory pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register // $ar3. Add corresponding indexing register $ix3 to addressing register $ar3 // and increment $ar0. void slm(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - const u8 sreg = DSP_REG_AR3; - dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[sreg]); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[sreg])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r[DSP_REG_IX0 + DSP_REG_AR3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } -// SLMN $acS.m, $acD.l +// SLMN $acS.m, $axD.D // xxxx xxxx 10dd 111s // Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $acD.l with value from memory pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register // $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 // and add corresponding indexing register $ix3 to addressing register $ar3. void slnm(const UDSPInstruction& opc) { - u8 areg = (opc.hex & 0x1) + DSP_REG_ACM0; + u8 sreg = (opc.hex & 0x1) + DSP_REG_ACM0; u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; - const u8 sreg = DSP_REG_AR3; - dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[areg]); + dsp_dmem_write(g_dsp.r[DSP_REG_AR0], g_dsp.r[sreg]); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[sreg])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r[DSP_REG_IX0 + DSP_REG_AR3])); writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r[DSP_REG_IX0])); } -// Not in duddie's doc -// LD $ax0.d $ax1.r @$arS +// LD $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 00ss +// example for "nx'ld $AX0.L, $AX1.L, @$AR3" +// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L. +// Increments AR0 and AR3. +// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are not doing that!) +// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. +// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not implemented yet) +// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not implemented yet) void ld(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 5) & 0x1; @@ -349,8 +346,7 @@ void ld(const UDSPInstruction& opc) writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } -// Not in duddie's doc -// LDN $ax0.d $ax1.r @$arS +// LDN $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 01ss void ldn(const UDSPInstruction& opc) { @@ -381,9 +377,7 @@ void ldn(const UDSPInstruction& opc) writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } - -// Not in duddie's doc -// LDM $ax0.d $ax1.r @$arS +// LDM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 10ss void ldm(const UDSPInstruction& opc) { @@ -415,8 +409,7 @@ void ldm(const UDSPInstruction& opc) dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r[DSP_REG_IX0 + DSP_REG_AR3])); } -// Not in duddie's doc -// LDNM $ax0.d $ax1.r @$arS +// LDNM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 11ss void ldnm(const UDSPInstruction& opc) { @@ -491,7 +484,7 @@ void zeroWriteBackLog() } //needed for 0x3... (at least)..., + clrl -//ex. corner case -> 0x4060: main opcode modifies .m, and extended .l -> .l shoudnt be zeroed because of .m write... +//ex. corner case -> 0x3060: main opcode modifies .m, and extended .l -> .l shoudnt be zeroed because of .m write... void zeroWriteBackLogPreserveAcc(u8 acc) { for (int i = 0; writeBackLogIdx[i] != -1; i++) { diff --git a/Source/Core/DSPCore/Src/DSPIntUtil.h b/Source/Core/DSPCore/Src/DSPIntUtil.h index 53d01fc769..4b9a8eaf2e 100644 --- a/Source/Core/DSPCore/Src/DSPIntUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntUtil.h @@ -218,11 +218,9 @@ inline s64 dsp_get_long_prod() return val; } -inline s64 dsp_get_long_prod_prodl_zero() +inline s64 dsp_get_long_prod_round_prodl() { - s64 tempprod = dsp_get_long_prod(); - tempprod = (tempprod & ~0xffff)+(((tempprod & 0xffff) >= 0x8000) ? 0x10000 : 0); - return tempprod; + return (dsp_get_long_prod() + 0x8000) & ~0xffff; } // For accurate emulation, this is wrong - but the real prod registers behave diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h index 5c91205553..ac99394b35 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.h +++ b/Source/Core/DSPCore/Src/DSPInterpreter.h @@ -163,9 +163,7 @@ void ori(const UDSPInstruction& opc); void srbith(const UDSPInstruction& opc); void mulaxh(const UDSPInstruction& opc); void tstprod(const UDSPInstruction& opc); - -//mia -void a100(const UDSPInstruction& opc); +void abs(const UDSPInstruction& opc); } // namespace diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 6c126bc123..f611158e4a 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -238,9 +238,9 @@ const DSPOPCTemplate opcodes[] = {"MULAC", 0x9400, 0xf600, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, - //a-b (!figure out 0xa100/0xa900!) + //a-b {"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true}, - {"a100", 0xa100, 0xf700, DSPInterpreter::a100, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true}, //Definitely not TSTAXL, it affects one of the accumulators + {"ABS", 0xa100, 0xf700, DSPInterpreter::abs, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true}, {"MULXMVZ", 0xa200, 0xe600, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, {"MULXAC", 0xa400, 0xe600, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, {"MULXMV", 0xa600, 0xe600, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, @@ -248,7 +248,7 @@ const DSPOPCTemplate opcodes[] = //c-d {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true}, - {"CMPAR" , 0xc100, 0xe700, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true}, //MIA in duddie dox + {"CMPAR" , 0xc100, 0xe700, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true}, {"MULCMVZ", 0xc200, 0xe600, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, {"MULCAC", 0xc400, 0xe600, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, {"MULCMV", 0xc600, 0xe600, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true}, diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 7c24dea14e..9bdaa4cefb 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -48,10 +48,9 @@ void clrl(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_acc(reg); - acc = (acc & ~0xffff) + (((acc & 0xffff) >= 0x8000) ? 0x10000 : 0); + s64 acc = (dsp_get_long_acc(reg) + 0x8000) & ~0xffff; - zeroWriteBackLogPreserveAcc(reg); + zeroWriteBackLog(); dsp_set_long_acc(reg, acc); Update_SR_Register64(acc); @@ -98,7 +97,7 @@ void andf(const UDSPInstruction& opc) // 1011 r001 xxxx xxxx // Test accumulator %acR. // -// flags out: xx xx00 +// flags out: --xx xx00 void tst(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 11) & 0x1; @@ -135,8 +134,7 @@ void cmp(const UDSPInstruction& opc) s64 acc1 = dsp_get_long_acc(1); s64 res = dsp_convert_long_acc(acc0 - acc1); - //Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> problems in ikaruga/nsmb -> 0xa100 ?? - Update_SR_Register64(res, false, isOverflow(acc0, -acc1, res)); + Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 zeroWriteBackLog(); } @@ -441,7 +439,7 @@ void add(const UDSPInstruction& opc) // 0100 111d xxxx xxxx // Adds product register to accumulator register. // -// flags out: x-xx xxxx - CF?? +// flags out: x-xx xxxx void addp(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; @@ -564,7 +562,7 @@ void inc(const UDSPInstruction& opc) // 0101 0ssd xxxx xxxx // Subtracts register $axS.L from accumulator $acD.M register. // -// flags out: xx xx00 +// flags out: x-xx xxxx void subr(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; @@ -702,6 +700,25 @@ void neg(const UDSPInstruction& opc) Update_SR_Register64(dsp_get_long_acc(dreg)); } +// ABS $acD +// 1010 d001 xxxx xxxx +// absolute value of $acD +// +// flags out: --xx xx00 +void abs(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + + if (acc < 0) + acc = 0 - acc; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} //---- // MOVR $acD, $axS.R @@ -1092,21 +1109,6 @@ void asrnr(const UDSPInstruction& opc) Update_SR_Register64(dsp_get_long_acc(dreg)); } -//---- - -// A100 $acD -// 1010 d001 xxxx xxxx -// -// MIA!! - needed for AX/AXWII -// -void a100(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 11) & 0x1; - //it changes target ACC sometimes! - - zeroWriteBackLog(); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} } // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp index 4c1d4e7c1b..d801dd6fc6 100644 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -27,7 +27,7 @@ namespace DSPInterpreter { -// Only MULX family instructions have unsigned support. +// Only MULX family instructions have unsigned/mixed support. inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) { s64 prod; @@ -37,7 +37,7 @@ inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) else if ((sign == 2) && (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)) //mixed prod = (u64)a * (s64)(s16)b; else - prod = (s64)(s16)a * (s64)(s16)b; + prod = (s64)(s16)a * (s64)(s16)b; //signed // Conditionally multiply by 2. if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) @@ -64,6 +64,40 @@ s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0) return prod; } +s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2) +{ + s64 result; + + if ((axh0==0) && (axh1==0)) // axl.0 * axl.1 + { + result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used + } + else if ((axh0==0) && (axh1==1)) // axl.0 * axh.1 + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + result = dsp_multiply(val1, val2, 2); + else if ((val1 >= 0x8000) && (val2 < 0x8000)) + result = dsp_multiply(val1, val2, 1); + else + result = dsp_multiply(val1, val2, 0); + } + else if ((axh0==1) && (axh1==0)) // axh.0 * axl.1 + { + if ((val2 >= 0x8000) && (val1 >= 0x8000)) + result = dsp_multiply(val2, val1, 2); + else if ((val2 >= 0x8000) && (val1 < 0x8000)) + result = dsp_multiply(val2, val1, 1); + else + result = dsp_multiply(val2, val1, 0); + } + else // axh.0 * axh.1 + { + result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + } + + return result; +} + //---- // CLRP @@ -74,11 +108,14 @@ void clrp(const UDSPInstruction& opc) // Magic numbers taken from duddie's doc // These are probably a bad idea to put here. zeroWriteBackLog(); +/* g_dsp.r[DSP_REG_PRODL] = 0x0000; g_dsp.r[DSP_REG_PRODM] = 0xfff0; g_dsp.r[DSP_REG_PRODH] = 0x00ff; g_dsp.r[DSP_REG_PRODM2] = 0x0010; +*/ // 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 + dsp_set_long_prod(0); // if we are doing it wrong then let's be consistent } // TSTPROD @@ -140,7 +177,7 @@ void movpz(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x01; - s64 acc = dsp_get_long_prod_prodl_zero(); + s64 acc = dsp_get_long_prod_round_prodl(); zeroWriteBackLog(); @@ -159,7 +196,7 @@ void addpaxz(const UDSPInstruction& opc) u8 dreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 9) & 0x1; - s64 prod = dsp_get_long_prod_prodl_zero(); + s64 prod = dsp_get_long_prod_round_prodl(); s64 ax = dsp_get_long_acx(sreg); s64 res = prod + (ax & ~0xffff); @@ -264,7 +301,7 @@ void mulmvz(const UDSPInstruction& opc) u8 rreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 11) & 0x1; - s64 acc = dsp_get_long_prod_prodl_zero(); + s64 acc = dsp_get_long_prod_round_prodl(); u16 axl = dsp_get_ax_l(sreg); u16 axh = dsp_get_ax_h(sreg); s64 prod = dsp_multiply(axl, axh); @@ -289,39 +326,7 @@ void mulx(const UDSPInstruction& opc) u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod; - - if (!treg && !sreg) - { - prod = dsp_multiply(val1, val2, 1); - } - else if (treg && !sreg) - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 2); - else if ((val1 >= 0x8000) && (val2 < 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else - prod = dsp_multiply(val1, val2, 0); - } - else if (!treg && sreg) - { - if ((val2 >= 0x8000) && (val1 >= 0x8000)) - prod = dsp_multiply(val2, val1, 2); - else if ((val2 >= 0x8000) && (val1 < 0x8000)) - prod = dsp_multiply(val2, val1, 1); - else - prod = dsp_multiply(val2, val1, 0); - } - else - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else if ((val1 >= 0x8000) || (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 0); - else - prod = dsp_multiply(val1, val2, 1); - } + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); zeroWriteBackLog(); @@ -344,39 +349,7 @@ void mulxac(const UDSPInstruction& opc) s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod; - - if (!treg && !sreg) - { - prod = dsp_multiply(val1, val2, 1); - } - else if (treg && !sreg) - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 2); - else if ((val1 >= 0x8000) && (val2 < 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else - prod = dsp_multiply(val1, val2, 0); - } - else if (!treg && sreg) - { - if ((val2 >= 0x8000) && (val1 >= 0x8000)) - prod = dsp_multiply(val2, val1, 2); - else if ((val2 >= 0x8000) && (val1 < 0x8000)) - prod = dsp_multiply(val2, val1, 1); - else - prod = dsp_multiply(val2, val1, 0); - } - else - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else if ((val1 >= 0x8000) || (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 0); - else - prod = dsp_multiply(val1, val2, 1); - } + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); zeroWriteBackLog(); @@ -401,39 +374,7 @@ void mulxmv(const UDSPInstruction& opc) s64 acc = dsp_get_long_prod(); u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod; - - if (!treg && !sreg) - { - prod = dsp_multiply(val1, val2, 1); - } - else if (treg && !sreg) - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 2); - else if ((val1 >= 0x8000) && (val2 < 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else - prod = dsp_multiply(val1, val2, 0); - } - else if (!treg && sreg) - { - if ((val2 >= 0x8000) && (val1 >= 0x8000)) - prod = dsp_multiply(val2, val1, 2); - else if ((val2 >= 0x8000) && (val1 < 0x8000)) - prod = dsp_multiply(val2, val1, 1); - else - prod = dsp_multiply(val2, val1, 0); - } - else - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else if ((val1 >= 0x8000) || (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 0); - else - prod = dsp_multiply(val1, val2, 1); - } + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); zeroWriteBackLog(); @@ -456,42 +397,10 @@ void mulxmvz(const UDSPInstruction& opc) u8 treg = (opc.hex >> 11) & 0x1; u8 sreg = (opc.hex >> 12) & 0x1; - s64 acc = dsp_get_long_prod_prodl_zero(); + s64 acc = dsp_get_long_prod_round_prodl(); u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod; - - if (!treg && !sreg) - { - prod = dsp_multiply(val1, val2, 1); - } - else if (treg && !sreg) - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 2); - else if ((val1 >= 0x8000) && (val2 < 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else - prod = dsp_multiply(val1, val2, 0); - } - else if (!treg && sreg) - { - if ((val2 >= 0x8000) && (val1 >= 0x8000)) - prod = dsp_multiply(val2, val1, 2); - else if ((val2 >= 0x8000) && (val1 < 0x8000)) - prod = dsp_multiply(val2, val1, 1); - else - prod = dsp_multiply(val2, val1, 0); - } - else - { - if ((val1 >= 0x8000) && (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 1); - else if ((val1 >= 0x8000) || (val2 >= 0x8000)) - prod = dsp_multiply(val1, val2, 0); - else - prod = dsp_multiply(val1, val2, 1); - } + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); zeroWriteBackLog(); @@ -586,7 +495,7 @@ void mulcmvz(const UDSPInstruction& opc) u8 treg = (opc.hex >> 11) & 0x1; u8 sreg = (opc.hex >> 12) & 0x1; - s64 acc = dsp_get_long_prod_prodl_zero(); + s64 acc = dsp_get_long_prod_round_prodl(); u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply(accm, axh);